我在看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 > > > >
答案 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
的定义。现在f
和g
都是Ize
,而x
是字符串而c
是Integer
答案 2 :(得分:1)
您可以使用以下替代定义,如果这样可以更清楚
composePref :: Ize -> Ize -> Ize
composePref f g = \x -> \c -> let y = (g x) c
in (f y) c