Warm tip: This article is reproduced from serverfault.com, please click

How to chain the use of maybe argument in haskell?

发布于 2014-05-23 21:34:18

I'm trying to build a string from optional arguments. For example to generate a greeting string from a title and a name This is trivial in a imperative language and would look like this

def greeting(title, name):
   s = "Hello"
   if a :
        s += "Mr"
   if b: 
        s += b

My first attempt in haskell is :

greeting :: Bool-> Maybe String -> String
greeting title name = foldl (++) "Hello" (catMaybes [title' title, name])
   where
   title' True = Just "Mr"
   title' False = Nothing

I'm sure there is a bette way to do it. First, I'm sure this foldl catMaybes combination exists somewhere but I couldn't find it. Second, folding works here because I'm using the same operation (and the same type). So what is there a better way to do it ? I was also thinking using a Writer but I'm not sure either how to do it.

Update

This is only an example (maybe bad or too simple). My question is more , how to generalize it to many arguments .

So the real problem is not just about concatening 2 strings but more how to generate letters from a template with optional sections and parameters, like you would do in Word with the mail merge tool.

You have on one a csv file with customer name, telephone number, how much is overdue etc. Some of the field could be optional. On the other side you have a template and the goal is to generate one letter per customer (row) according to the *template. The question is then how do you write this template in haskell (without the help of any templating library). In my first example the template will be "hello (Mr){name}" but in the real word the template could be in invoice, a statement letter or even a complete accounting report.

Questioner
mb14
Viewed
0
Nikita Volkov 2014-05-24 18:29:26

Haskell is so good at abstractions, it can easily replicate the imperative patterns. What you're doing in your example is called a "builder" pattern. Writer is a monad, which wraps a pattern of accumulation or "building" of any Monoid data, and String is a Monoid.

import Control.Monad.Writer hiding (forM_)
import Data.Foldable

greeting :: Bool -> Maybe String -> String -> String
greeting mr name surname = 
  execWriter $ do
    tell $ "Hello,"
    when mr $ tell $ " Mr."
    forM_ name $ \s -> tell $ " " ++ s
    tell $ " " ++ surname
    tell $ "!"

main = do
  putStrLn $ greeting False (Just "Ray") "Charles"
  putStrLn $ greeting True Nothing "Bean"

Outputs:

Hello, Ray Charles!
Hello, Mr. Bean!