如何使用Monad-List构建函数?

时间:2012-07-11 06:47:50

标签: haskell

我在使用monad-list构建函数时遇到问题

 > multab 4
 ["1*1=1","1*2=2","1*3=3","1*4=4","2*2=4","2*3=6","2*4=8","3*3=9","3*4=12","4*4=16"]

所以我想开始:

multab :: Integer -> [String]

其余的,你想提出任何建议吗?

提前致谢。

4 个答案:

答案 0 :(得分:8)

基本上你想要生成一个条目列表然后打印它们。

让我们从条目开始。这些由两个整数及其产品组成。因此,让我们定义一个类型同义词来保存两个整数

type Entry = (Integer, Integer)

和计算这些整数乘积的评估函数,

eval :: Entry -> Integer
eval = uncurry (*)

然后,我们定义一个生成条目的函数:

gen :: Integer -> [Entry]
gen n = [(i, j) | i <- [1 .. n], j <- [i .. n]]

例如:

> gen 4
[(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,3),(3,4),(4,4)]

接下来,我们需要能够打印一个条目:

showEntry :: Entry -> String
showEntry e@(i, j) = show   i ++ "*"    ++ show j ++ "=" ++ show (eval  e)

例如:

> showEntry (2, 3)
"2*3=6"

最后,让我们将这些部分粘合在一起:

multab :: Integer -> [String]
multab = map showEntry . gen

我们走了:

> multab 4
["1*1=1","1*2=2","1*3=3","1*4=4","2*2=4","2*3=6","2*4=8","3*3=9","3*4=12","4*4=16"]

答案 1 :(得分:2)

执行此操作的自然方法是生成包含(i, j)i <的所有对= j的列表,然后在其上映射(\(i, j) -> show i ++ "*" ++ show j ++ "=" ++ show (i*j))。生成此类列表最明显的方法是编写[(i, j) | i <- [1..n], j <- [1..n], i <= j]。尽管做[1..n] >>= list where list i = map (\k -> (i, k)) [i..n]可能更好,因为这不会进行任何过滤(因为它不会生成不需要的对)。

答案 2 :(得分:2)

以下是基于Karolis回答的一些临时解决方案。

> let nonDec xs = and $ zipWith (>=) (drop 1 xs) xs
nonDec :: Ord b => [b] -> Bool

> let getSets s n = filter nonDec $ replicateM n s
getSets :: Ord b => [b] -> Int -> [[b]]

> getSets [1,2,3,4] 2
[[1,1],[1,2],[1,3],[1,4],[2,2],[2,3],[2,4],[3,3],[3,4],[4,4]]

> let showExp = \[i,j] -> show i ++ "*" ++ show j ++ "=" ++ show (i*j)
showExp :: [Integer] -> [Char]

> map showExp $ getSets [1,2,3,4] 2
["1*1=1","1*2=2","1*3=3","1*4=4","2*2=4","2*3=6","2*4=8","3*3=9","3*4=12","4*4=16"]

因此,multab\n -> map showExp $ getSets [1..n] 2

答案 3 :(得分:1)

作为其他答案的替代方案,使用List作为Monad。

multab :: Integer -> [String]
multab n = do
    i <- [1..n]
    j <- [i..n]
    return $ show i ++ "*" ++ show j ++ "=" ++ show (i*j)

前两个规则将每对整数(i,j)j <= i <= n绑定在一起。最后一条规则返回打印值。

更实际的可能是列表理解版本

multab2 :: Integer -> [String]
multab2 n =
    [ show i ++ "*" ++ show j ++ "=" ++ show (i*j)
    | i <- [1..n]
    , j <- [i..n] ]

这可以直接翻译成monad版本,如结构所示,尽管这不是最有效的翻译。此外,这相当于您从dblhelix的答案中内联所有函数时所获得的内容。