[Haskell-cafe] APIs

robert dockins robdockins at fastmail.fm
Tue May 24 14:31:29 EDT 2005


>> > One of the best bad example is the use of boolean as arguments.
>>
>> Oh, yes.  That's a pet peeve of mine.  About 99% of boolean arguments
>> should be meaningful two-valued enumerated types.  It's literally a
>> one-liner to create such an enumerated type, so there's no excuse.
> 
> 
> The documentation effect and type safety provided by two-valued 
> enumerated types is indeed much greater. But one needs a conversion from 
> Bool to the enumeration if one wants to pass the result of a logic 
> operation to the function. What about records with named fields, 
> especially if more options are needed?
> 
> data CreateDirectoryOptions = Cons {createParents :: Bool}
> 
> createDirectory (Cons {createParents = True}) "dir"

Hummmm.... I think I like this.  Something like the following allows a 
simple way to make the call site concise and provide defaults at the 
same time.  Additional plus -- adding options requires no call-site code 
changes.


---------------------------------------

import Control.Monad

-- provide "opts" which should be a labeled record
-- of default options
class FunctionOptions a where opts :: a

-- alias for readability when you don't want to change
-- the default options
defaults = opts

-- create a datatype for each function which needs some flags
data CreateDirectoryOptions
    = CreateDirectoryOptions
     { createParents :: Bool
     , barFlag :: Bool
     , andNow :: Bool
     , aWholeBunch :: Bool
     , ofOther :: Bool
     , seldomEverUsed :: Bool
     , esotericOptions :: Bool
     }

-- set the flag defaults
instance FunctionOptions CreateDirectoryOptions
   where opts =
           CreateDirectoryOptions
           { createParents = False
           , barFlag = True
           , andNow = True
           , aWholeBunch = True
           , ofOther = False
           , seldomEverUsed = True
           , esotericOptions = False
           }

createDirectory :: CreateDirectoryOptions -> FilePath -> IO ()
createDirectory o path =
         do when (createParents o) (putStrLn "creating parents")
            when (barFlag o) (putStrLn "bar flag true")
            putStrLn ("creating "++path)
            return ()

-- readable AND typesafe :-)
main = do createDirectory opts{ createParents = True } "foo"
           createDirectory defaults "baz"



More information about the Haskell-Cafe mailing list