我正在尝试派生(.) (foldr(++)) (map (:))
我首先推导出foldr (++)
foldr :: (a1 -> b1 -> b1) -> b1 -> [a1] -> b1
(++) :: [a2] -> [a2] -> [a2]
a1 ~ [a2]
b1 ~ [a2]
b1 ~ [a2]
所以
foldr (++) :: [a2] -> [[a2]] -> [a2] ~ [a] -> [[a]] -> [a]
然后我推导出map (:)
map :: (a1 -> b1) -> [a1] -> [b1]
(:) :: a2 -> [a2] -> [a2]
a1 ~ a2
b1 ~ [a2] -> [a2]
所以
map (:) :: [a2] -> [[a2] -> [a2]] ~ [a] -> [[a] -> [a]]
最后是(.) (foldr(++)) (map (:))
(.) :: (b1 -> c1) -> (a1 -> b1) -> a1 -> c1
map (:) :: [a2] -> [[a2] -> [a2]]
foldr (++) :: [a3] -> [[a3]] -> [a3]
b1 ~ [a2]
c1 ~ [[a2] -> [a2]]
a1 ~ [a3]
b1 ~ [[a3]] -> [a3]
所以我得到
(.) (foldr(++)) (map (:)) :: a1 -> c1 ~ [a3] -> [[a2] -> [a2]]
但如果我向GHCi询问:t (.) (foldr(++)) (map (:))
,我会(.) (foldr(++)) (map (:)) :: [a] -> [[[a] -> [a]]] -> [[a] -> [a]]
哪个与我的结果不同,有什么帮助可以得到相同的结果?
谢谢,
安。
答案 0 :(得分:9)
在最后一步中,你混淆论证oder。您将b1 -> c1
与map (:)
类型统一,但您应将其与foldr (++)
类型统一。
更一般地,您可能想学习如何自己调试这些复杂的计算。最后进行健全性检查是很好的(在这种情况下,通过使用ghci检查结果)。如果完整性检查不起作用,那么下一步就是说出或写下每个步骤是什么以及为什么要这样做。在这种情况下,您会说"然后我将b1 -> c1
与map (:)
类型统一起来因为......",然后您会发现该错误,因为那里有'没理由这样做。
也许rubber duck debugging适合您,在那里您向橡皮鸭解释您的代码,并通过解释,您会看到代码的错误。
答案 1 :(得分:3)
我不太确定,但我认为您错过了为b1
生成两个约束的事实,因为在合成f . g
中g
的输出必须匹配f
的输入。通过从这个事实开始,然后替换输入和输出,可以更容易地推断出合成的类型:
map (:) :: [a] -> [[a] -> [a]]
foldr (++) :: [b ] -> [[b ]] -> [b ]
[b] ~ [[a] -> [a]]
b ~ [a] -> [a]
foldr (++) . map (:) :: [a] -> [[b ]] -> [b ]
~ [a] -> [[[a] -> [a]]] -> [[a] -> [a]]