Home > Blockchain >  Force keyword arguments in Haskell record init
Force keyword arguments in Haskell record init

Time:09-07

Can I force the use of keywords only when initializing a record in Haskell?

data Person
   = Person
   {
       name :: String,
       idnum :: String
   }
   deriving( Show )


main = putStrLn $ show $ Person "oren" "9200"

-- I want to only allow such initializations:
-- main = putStrLn $ show $ Person { name = "moish", idnum = "7400" }

(This is especially useful when two fields have the same type)

CodePudding user response:

As far as I know, no.

Consider maybe the following solution?

newtype Name = Name String
newtype Idnum = Idnum String

data Person = Person { name :: Name, idnum :: Idnum }

Another possibility, worse in my opinion, is this:

module A (Person, name, idnum) where

data Person = Person
  { _name :: String
  , _idnum :: String
  }

name :: String -> (Person -> Person)
name n p = p { _name = n }

idnum :: String -> (Person -> Person)
idnum n p = p { _idnum = n }

emptyPerson :: Person
emptyPerson = Person "" ""

# in another module

module B

import A (Person, name, idnum)

myPerson = name "myname" . idnum "myidnum" $ emptyPerson

In this case there's no guarantee that both name and idnum get a value.


The fact that Person can always be used as a 'plain function' may turn out to be very useful. If you have, for instance, getName :: IO String and getIdnum :: IO String, then combining these to form a getPerson :: IO Person is concise: getPerson = Person <$> getName <*> getIdnum. This is only possible because we don't use record syntax here!

  • Related