Skip to content
Brian Marick edited this page Aug 17, 2017 · 5 revisions

Full source

Problem 1

The trick is to define an extensible type:

takerVariant : { whole | id : Int } -> Int
takerVariant record =
  record.id

makerVariant is impossible. It creates a record with a name field, but taker requires that its parameter have exactly and only an Int id. (I suppose makerVariant could throw away its argument and just produce {id = 3}, but that seems excessively pointless for a function that takes a name as an argument.)

Problem 2

Without a type annotation, Elm calculates this type for setName:

      <function> : a -> { c | name : b } -> { c | name : a }

I'd forgotten that the { record | ... } notation can change not only a field's value but also its type. That is, it is allowed to take a record with a name of type b and produce a record whose name type is now a. Weird.

The following type annotation rules out that behavior by reusing the name field's type:

setName : part -> { whole | name : part } -> { whole | name : part }
setName newValue record =
  { record | name = newValue } 

Problem 3

type alias Lens whole part =
  { get : { whole | name : part } -> part
  , set : part -> { whole | name : part } -> { whole | name : part }
  }

Problem 4

type alias Lens whole part =
  { get : whole -> part
  , set : part -> whole -> whole
  }

lens : (whole -> part) -> (part -> whole -> whole) -> Lens whole part
lens getter setter =
  { get = getter, set = setter }

Problem 5

type alias Lens whole part =
  { get : whole -> part
  , set : part -> whole -> whole
  , update : (part -> part) -> whole -> whole
  }

  
lens : (whole -> part) -> (part -> whole -> whole) -> Lens whole part
lens getter setter =
  let
    updater f whole =
      setter (f (getter whole)) whole
  in
    { get = getter, set = setter, update = updater }

Clone this wiki locally