
2009/9/28 Ben Franksen
To expose an impure function (!) in an API, I don't know... I mean, couldn't one just wrap the value like this
data Attributed a -- opaque
(&=) :: a -> Attrib -> Attributed a
mode :: Data a => Attributed a -> Mode a
and thus retain a purely functional interface?
Hi Ben, I don't think this would work because you need to be able to put the Attributed things in the fields of your command options data type. If they are wrapped in an "Attributed" then this may not be possible. In particular the sample won't compile in your proposal: data Sample = Sample {hello :: String} deriving (Show, Data, Typeable) sample = mode $ Sample{hello = def &= text "World argument" & empty "world"} Because the &= would return an Attributed String whereas you are actually after a String. Essential the problem is that attributes are attached to *fields*, but mode consumes a *record*. The best way to do this typefully is to paramaterise the options data type with a functor: data Sample f = Sample {hello :: f String} deriving (Show, Data, Typeable) Now you can do what you want, where mode :: Data a => a Attribute -> Mode (a Id). In fact, you could even do away with Data and substitute some sort of Foldable/Traversable as long as you were happy with the library not being able to fill in a default argument name from the record field name. The current interface is the best tradeoff given what Neil is trying to do IMHO - though the side effects make me shudder too! Cheers, Max