3 ms·
Yes! Syntactically Purescript essentially automatically gives you lightweight lenses for records. E.g. myValue { field0 { subField0 { subSubField0 = 5 }}} S
by dwohnitmok 7y ago
Yes! Syntactically Purescript essentially automatically gives you lightweight lenses for records. E.g.
myValue { field0 { subField0 { subSubField0 = 5 }}}
Semantically... oh boy, row types (i.e. extensible product types) and polymorphic variants (i.e. extensible sum types) are fantastic! I'd go so far as to say as long as you give me `newtype`, I would be in favor of row types and polymorphic variants completely replacing `data` declarations.
-- forall x here means that our record can have other fields
resetName :: forall x. { name :: String | x } -> { name :: String | x }
resetName itemWithName = itemWithName { name = "Default" }
-- Notice how Person is just a type synonym!
-- And there's no data constructor
-- { name :: String, id :: Int } is a type, not just a constructor
type Person = { name :: String, id :: Int }
type Pet = { name :: String, owner :: Person }
bob = { name : "Bob", id : 0 }
doggy = { name : "Doggy", owner : bob }
-- Look they both work!
bobReset = resetName bob
doggyReset = resetName doggy
-- And no clashes, because records are a first class type declaration
bob.name == "Bob"
doggyReset.name == "Default"
Purescript unfortunately doesn't have built-in polymorphic variants (you can derive them from row types with a bit of type-level hackery), so a bit of this is pseudo-Purescript (mainly the case declaration, functionally you can get the same thing, it just looks slightly different).
newtype TextTooShort = ...
newtype TextNotValidASCII = ...
findFirst5CharWord :: forall e. String -> Either (TextTooShort + e) String
asciiNumberRepresentation :: forall e. String -> Either (TextNotValidASCII + e) (Array Int)
processString :: forall e. String -> Either (TextTooShort + TextNotValidASCII + e) (Array Int)
-- No lifting or wrapping of intermediate errors required!
-- All the types still unify!
processString = findFirst5CharWord `andThen` asciiNumberRepresentation
-- But you still get exhaustivity checking!
displayString :: String -> String
displayString input = case (processString input) of
Left TextTooShort -> "You didn't give me enough text!"
Left TextNotValidAscii -> "Whoops no ASCII rep exists!"
Right arrayOfInts -> show arrayOfInts