Struct Embedding in Haskell

In Haskell, we can achieve a similar structure using algebraic data types and type classes. Here’s how we can translate the concept of struct embedding:

{-# LANGUAGE RecordWildCards #-}

import Text.Printf (printf)

data Base = Base
    { num :: Int
    }

class Describer a where
    describe :: a -> String

instance Describer Base where
    describe Base{..} = printf "base with num=%d" num

-- A Container type that includes a Base
data Container = Container
    { base :: Base
    , str :: String
    }

-- Make Container an instance of Describer
instance Describer Container where
    describe Container{..} = describe base

main :: IO ()
main = do
    -- Create a Container with an embedded Base
    let co = Container
            { base = Base { num = 1 }
            , str = "some name"
            }

    -- Access fields directly
    printf "co={num: %d, str: %s}\n" (num $ base co) (str co)

    -- Access using the full path
    putStrLn $ "also num: " ++ show (num $ base co)

    -- Call the describe method on Container
    putStrLn $ "describe: " ++ describe co

    -- Demonstrate that Container implements Describer
    let d :: Describer a => a
        d = co
    putStrLn $ "describer: " ++ describe d

In this Haskell version:

  1. We define a Base data type with a num field, similar to the Go struct.

  2. We create a Describer type class, which is analogous to the Go interface.

  3. We make Base an instance of Describer, implementing the describe method.

  4. We define a Container data type that includes a Base and an additional str field. This is similar to embedding in Go.

  5. We make Container an instance of Describer by delegating to the Base implementation.

  6. In the main function, we create a Container, access its fields, and demonstrate that it implements the Describer interface.

While Haskell doesn’t have struct embedding in the same way as Go, we can achieve similar functionality through composition and type classes. The RecordWildCards language extension is used to make field access more convenient.

To run this program, save it as struct_embedding.hs and use:

$ ghc struct_embedding.hs
$ ./struct_embedding
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

This example demonstrates how Haskell can model similar concepts to Go’s struct embedding using its own idioms and features.