Proper way to treat global flags in Haskell

后端 未结 4 842
天涯浪人
天涯浪人 2021-02-07 12:19

I often need to make a core function that\'s used in many places somehow configurable - i.e., it may use either algorithm A or algorithm B depending on a command-line switch; o

4条回答
  •  刺人心
    刺人心 (楼主)
    2021-02-07 12:46

    Another option is GHC implicit parameters. These give a less painful version of your option (2): intermediate type signatures get infected, but you don't have to change any intermediate code.

    Here's an example:

    {-# LANGUAGE ImplicitParams #-}
    import System.Environment (getArgs)    
    
    -- Put the flags in a record so you can add new flags later
    -- without affecting existing type signatures.
    data Flags = Flags { flag :: Bool }
    
    -- Leaf functions that read the flags need the implicit argument
    -- constraint '(?flags::Flags)'.  This is reasonable.
    leafFunction :: (?flags::Flags) => String
    leafFunction = if flag ?flags then "do_stuff_A" else "do_stuff_B"
    
    -- Implicit argument constraints are propagated to callers, so
    -- intermediate functions also need the implicit argument
    -- constraint.  This is annoying.
    intermediateFunction :: (?flags::Flags) => String
    intermediateFunction = "We are going to " ++ leafFunction
    
    -- Implicit arguments can be bound at the top level, say after
    -- parsing command line arguments or a configuration file.
    main :: IO ()
    main = do
      -- Read the flag value from the command line.
      commandLineFlag <- (read . head) `fmap` getArgs
      -- Bind the implicit argument.
      let ?flags = Flags { flag = commandLineFlag }
      -- Subsequent code has access to the bound implicit.
      print intermediateFunction
    

    If you run this program with argument True it prints We are going to do_stuff_A; with argument False it prints We are going to do_stuff_B.

    I think this approach is similar to the reflection package mentioned in another answer, and I think the HFlags mentioned in the accepted answer is probably a better choice, but I'm adding this answer for completeness.

提交回复
热议问题