1. 1

    I’m interested in Haskell but very new to the language. Could someone explain how the design presented in this post would be preferable over something like this?

    {-# LANGUAGE RecordWildCards #-}
    
    data Bicycle = Bicycle
        { cadence :: Int
        , speed   :: Int
        , gear    :: Int
    } deriving (Show)
    
    newAcmeBicycle :: Bicycle
    newAcmeBicycle = Bicycle 0 0 1
    
    newFooBicycle :: Bicycle
    newFooBicycle = Bicycle 0 0 4
    
    printStates :: Bicycle -> IO ()
    printStates Bicycle{..} = putStrLn $
        unlines ["cadence: " ++ show cadence,
                 "speed: " ++ show speed,
                 "gear: " ++ show gear]
    
    changeGear:: Bicycle -> Int -> Bicycle
    changeGear b g = b {gear = g}
    

    I’m guessing that it has something to do with record immutability but is it preferable to actually mutate the record fields rather than returning a new record with the new field values?

    1. 4

      (I’m the author of the post) You’re exactly right, what you’ve written is much better for most cases. I just wanted a more direct comparison; I think changing too many things in the Haskell translation would have obscured the focus of what I wanted to contrast.

      1. 1

        You’re right if you’re using records to store data - it’s usually better to create a fresh new copy with updated field values. However, if you’re doing object-oriented programming (and no language ought to prevent you from doing that if you so wish), you typically want the state and future behavior of objects to change in response to messages. For this reason, objects are modeled in Haskell as records of methods whose fields are (functions returning) IO actions.

        1. 1

          Thank you for the explanation. That’s very helpful for my understanding.

          Would implementing a message passing design have any benefits over just using records to store the data and functions that operate on those records? It seems like the design presented backs them into a corner where they lose ‘object’ polymorphism and instead need to implement a conversion function for each type of bike, like acmeToBicycle.

          Would this be considered the idiomatic way of addressing designing this system or am I reading a little too much into a design that was merely meant to show parallels between two seemingly unrelated concepts?