如果
*Main> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]
和
*Main> :t replicate
replicate :: Int -> a -> [a]
然后如何运作
*Main> :t concatMap . replicate
concatMap . replicate :: Int -> [b] -> [b]
下式给出:
*Main> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
我的意思是,我对函数组合的理解是replicate
应该返回concatMap
期望的任何参数,以便(.)
能够工作。但事实并非如此。那捕获的是什么?
答案 0 :(得分:19)
如果您在签名中添加括号然后将它们排成一行,它可能会帮助您查看正在发生的事情:
replicate :: Int -> (a -> [a])
concatMap :: (a -> [b]) -> ([a] -> [b])
现在,如果我们统一replicate
和concatMap
,b
的输出应该与a
的输入相符,这应该是相当明显的,在这种情况下,输出类型为作文是[b] -> [b]
。
答案 1 :(得分:9)
困难可能来自令人困惑的类型变量以及如何 你推理类型统一。诀窍是考虑,如 其他人说,( - >)是右关联的,这意味着你可以 像这样排队(为每个人制作新的类型变量 签名以避免混淆):
(.) :: (b -> c ) -> (a -> b ) -> a -> c
concatMap :: (q -> [r]) -> ([q] -> [r])
replicate :: (Int -> (s -> [s])
这实质上为我们提供了一些我们需要解决的限制。 假设“a~b”表示“a与b的类型相同”或 等价地“a可以用b代替。”
从上面我们可以推断出以下事实:
a ~ Int
b ~ (q -> [r]) ~ (s -> [s])
c ~ ([q] -> [r])
但是b的两个等价物告诉我们
(q -> [r]) ~ (s -> [s])
需要
q ~ s and [r] ~ [s]
然后我们将c重写为:
c ~ ([q] -> [r]) ==> ([s] -> [s]))
将a和c的替换插入原始 应用了两个函数的(。)类型产生
a -> c ~ Int -> ([s] -> [s])
当然现在采用ghci报告的形式:Int -> [b] -> [b]
。