Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Augmenting type aliases in elm or haskell

Tags:

haskell

elm

Say I have a type in elm (0.18) like this:

type alias CatSimple = 
  { color : String
  , age : Int 
  , name : String
  , breed : String
}

My project requires that I also have a type that has all the fields of the previous one, but with a few additional fields:

type alias CatComplex =
  { color : String
  , age : Int 
  , name : String
  , breed : String
  , feral : Bool
  , spayed : Bool
} 

Now let's say that I need to add another field to CatSimple. I would have to remember to add it to CatComplex as well.

I would like to be able to dynamically augment my types so that I can avoid having to update all of them, or having to resort to something like this:

type alias CatComplex =
  { simpleData: CatSimple
  , feral : Bool
  , spayed : Bool
} 

Is there any way to do that in Elm?

If not, does Haskell provide a way to do this?

like image 256
Mark Karavan Avatar asked Jan 21 '26 15:01

Mark Karavan


2 Answers

You can use extensible records in Elm to define a rudimentary sort of field composition:

type alias Cat c =
    { c
        | color : String
        , age : Int
        , name : String
        , breed : String
    }

type alias FeralCat =
    Cat
        { feral : Bool
        , spayed : Bool
        }

Here's an example of how it could be used:

feralCatSummary : FeralCat -> String
feralCatSummary { color, feral } =
    color ++ "; Feral? " ++ toString feral

main : Html msg
main =
    text <|
        feralCatSummary
            { color = "Blue"
            , age = 5
            , name = "Billy"
            , breed = "Bluecat"
            , feral = True
            , spayed = False
            }
like image 110
Chad Gilbert Avatar answered Jan 23 '26 08:01

Chad Gilbert


The short answer is no, but there are some things you can do that go in the direction you want:

Have a single type but make the extra info 'optional'

type alias Cat =
  { color : String
  , age : Int 
  , name : String
  , breed : String
  , feral : Maybe Bool
  , spayed : Maybe Bool
 } 

When you want to pass CatComplex to a function that only uses the Cat fields you could define a Type

 type alias CatGeneric a =       
    { a| 
          color : String
          , age : Int 
          , name : String
          , breed : String 
      }

then

fn : CatGeneric a -> Bool 
....

and this should type check if you pass either a Cat or a CatComplex

like image 34
Simon H Avatar answered Jan 23 '26 09:01

Simon H