试图从演示文稿“为什么Monads很重要?”中理解一个Haskell代码示例。

时间:2014-03-28 16:58:45

标签: haskell monads

我在看presentation:“为什么Monads很重要?”

我简化了编译和运行的一个代码example(请参见下文),但我仍然不明白它是如何工作的。

更准确地说:我不懂composePref函数。根据类型定义,它应该采用Ize类型的 2 参数并返回Ize类型的一个结果。 (Ize在匈牙利语中意为“whatdoyoucallit”/ thingy / something。)

但它需要三个参数(f g x),有人可以解释一下composePref函数的工作原理以及f,g,x,y和c的类型是什么?

我必须承认我是Haskell的初学者。也许我不明白在这种情况下如何使用curry?

module Dependence where
main = putStrLn (f "foo" cfg)
         where f = right `composePref` right `composePref` left
               cfg = 2

left :: Ize
left s = \i -> (repeatString i "< ") ++ s

right ::Ize
right s = \i -> s ++ (repeatString i " >")

repeatString :: Integer -> String -> String
repeatString i s = if (i <= 0)
                    then ""
                    else s ++ repeatString (i - 1) s

type Ize = String -> Integer -> String

composePref :: Ize -> Ize -> Ize
composePref f g x = \c -> let y =  (g x) c 
                          in       (f y) c

产生输出:

< < foo > > > >

3 个答案:

答案 0 :(得分:6)

你是正确的认为它是允许这种行为的currying。如果我们查看Ize的定义,它只是String -> Integer -> String的类型同义词。如果我们将其插入到composePref的类型签名中,我们就会得到

composePref :: (String -> Integer -> String) -> (String -> Integer -> String) -> (String -> Integer -> String)

(我希望你现在看到为什么使用类型别名,它会大大缩短签名)。由于类型签名中的->是右关联的,因此意味着类似

a -> b -> c -> d

相当于

a -> (b -> (c -> d))

因此我们可以进一步简化签名(使用一些额外的类型别名,因为我不想全部输入)

type I = Integer
type S = String

composePref :: (S -> I -> S) -> (S -> I -> S) -> S -> I -> S
composePref f g x = \c -> ...

然后f :: (S -> I -> S)g :: (S -> I -> S)x :: S。我包括了那个labmda的开头,所以我可以说c :: I。您实际上可以将此函数编写为:

composePref :: Ize -> Ize -> Ize
composePref f g x c = let y = (g x) c in (f y) c

这相当于

composePref f g x c = let y = g x c in f y c
-- (map show) [1, 2, 3] === map show [1, 2, 3]

或者

composePref f g x c = f (g x c) c

甚至

composePref f g = \x c -> f (g x c) c

这些都是composePref的等效定义。我认为最后一个可能最清楚的是它是一个函数,它接受两个函数并返回一个相同类型的新函数。


为了让它更加清晰,我会用类型注释写一些非法语法,你真的不应该使用它们:

composePref (f :: Ize) (g :: Ize) = h
    where
        h :: Ize
        h (x :: String) (c :: Integer) =
            let (y :: String) = (g x) c
            in (f y) c

答案 1 :(得分:3)

如果你扩展了函数中最后一个Ize的类型,你会得到:

composePref :: Ize -> Ize -> (String -> Integer -> String)
composePref f g x = \c -> let y =  (g x) c 
                          in       (f y) c

相同
composePref :: Ize -> Ize -> String -> Integer -> String

也与:

相同
composePref :: Ize -> Ize -> String -> (Integer -> String)

更符合您对composePref的定义。现在fg都是Ize,而x是字符串而cInteger

答案 2 :(得分:1)

您可以使用以下替代定义,如果这样可以更清楚

 composePref :: Ize -> Ize -> Ize
 composePref f g = \x -> \c -> let y =  (g x) c 
                               in       (f y) c