1 haskell types unification ghci inferred-type
这里有很多线程来推导组合函数的推断类型,但我仍然相当困惑.我发现的帖子都没有给出关于如何统一类型的一般性解释.
我的考试学习指南有问题,而且我很难搞清楚.
8)什么是(.)地图的推断类型uncurry :: ________
我能够在大多数时间推导推断类型,但我仍然有点困惑.例如,我知道要获得(.)map uncurry的答案,您需要首先派生地图类型uncurry.我能做到这一点
鉴于以下类型
map :: (a -> b) -> [a] -> [b]
uncurry :: (a -> b -> c) -> (a, b) -> c
Run Code Online (Sandbox Code Playgroud)
我将地图中的函数(a - > b)与uncurry统一起来
a = a ? b ? c
b = (a, b) ? c
Run Code Online (Sandbox Code Playgroud)
然后答案是地图[a] - > [b]的另一半,其中a和b的新值如此
map uncurry :: [ a -> b -> c ] -> [ (a, b) -> c]
Run Code Online (Sandbox Code Playgroud)
然后你需要统一
(.) :: (b -> c) -> (a -> b) -> a -> c
map uncurry :: [ a -> b -> c ] -> [ (a, b) -> c]
Run Code Online (Sandbox Code Playgroud)
答案应该是
(.) map uncurry :: (a -> b1 -> b) -> [(a, b1)] -> [b]
Run Code Online (Sandbox Code Playgroud)
但我不明白b1来自哪里或基本上是如何完成的.我认为我真正需要的是对一般类型统一的解释.统一两种类型的方法是什么?如何知道两种类型是否无法统一.
如果有人能够一步一步地解释如何导出(.)地图,我会非常感激.
->
关联到右侧.让我们通过你的例子.
类型
(.) :: (b -> c) -> (a -> b) -> a -> c
map :: (a -> b) -> [a] -> [b]
uncurry :: (a -> b -> c) -> (a, b) -> c
Run Code Online (Sandbox Code Playgroud)
为每个函数赋予非重叠类型名称
首先,这是令人困惑的,因为有很多a
s并且它们并不都意味着相同的东西,所以我每次都要用新的字母重命名类型.
(.) :: (b -> c) -> (a -> b) -> a -> c
map :: (d -> e) -> [d] -> [e]
uncurry :: (f -> g -> h) -> (f, g) -> h
Run Code Online (Sandbox Code Playgroud)
支持类型,与右侧相关联
(.) :: (b -> c) -> ((a -> b) -> a -> c)
map :: (d -> e) -> ([d] -> [e])
uncurry :: (f -> (g -> h)) -> ((f, g) -> h)
Run Code Online (Sandbox Code Playgroud)
现在让我们来看看表达式(.) map uncurry
.正如您现在已经意识到的那样,将运算符.
放在括号中会将其转换为遵循正常函数规则的函数,因此
(.) map uncurry
意味着((.) map) uncurry
,首先要统一的类型来自(.)
和map
.
现在(.)
有第一个参数(b->c)
,所以(b->c)
必须与以下类型统一map
:
(.) :: ( b -> c ) -> ((a -> b) -> (a -> c))
map :: (d -> e) -> ([d] -> [e])
Run Code Online (Sandbox Code Playgroud)
当我们替代b ~ (d->e)
和c ~ ([d]->[e])
在类型(.)
,我们得到:
(.) :: ((d->e) -> ([d]->[e])) -> ((a -> (d->e)) -> (a -> ([d]->[e])))
Run Code Online (Sandbox Code Playgroud)
因此map
成为第一个参数,因此当我们提供它时,它会从类型签名中消失
(.) map :: ((a -> (d->e)) -> (a -> ([d]->[e])))
Run Code Online (Sandbox Code Playgroud)
检查像ghci或拥抱这样的翻译
Hugs> :t (.) map
(map .) :: (a -> b -> c) -> a -> [b] -> [c]
Run Code Online (Sandbox Code Playgroud)
是的 - 当我们因->
右关联而添加括号时,它们是相同的.
好的,现在我们有
(.) map :: ((a -> (d->e)) -> (a -> ([d]->[e])))
uncurry :: (f -> (g -> h)) -> ((f, g) -> h)
Run Code Online (Sandbox Code Playgroud)
现在,由于它们看起来相同,因此匹配这两个第一个参数非常诱人,但当然我们需要将第一个参数(.) map
与整个类型匹配uncurry
:
将第一个参数的类型与该参数的整个类型相匹配
(.) map :: (( a -> ( d -> e)) -> (a -> ([d]->[e])))
uncurry :: (f->(g->h)) -> ((f,g) -> h)
Run Code Online (Sandbox Code Playgroud)
给予a ~ (f->(g->h))
,d ~ (f,g)
和e ~ h
:
(.) map :: (((f->(g->h)) -> ((f,g)-> h)) -> ((f->(g->h)) -> ([(f,g)]->[h])))
Run Code Online (Sandbox Code Playgroud)
并将其应用于uncurry给出
(.) map uncurry :: ((f->(g->h)) -> ([(f,g)]->[h])))
Run Code Online (Sandbox Code Playgroud)
请与口译员核实
Hugs> :t (.) map uncurry
map . uncurry :: (a -> b -> c) -> [(a,b)] -> [c]
Run Code Online (Sandbox Code Playgroud)
太棒了 - 我们做到了!
如果我们举例length . map (.) $ repeat id ++ [] ++ []
,我们将需要所有这些运算符的固定,但我们可以首先包含函数应用程序,因为它们优先:
length . map (.) $ repeat id ++ [] ++ []
length . (map (.)) $ (repeat id) ++ [] ++ []
Run Code Online (Sandbox Code Playgroud)
按优先顺序排列运算符
使用:i
解释器的命令查找运算符的固定性,并按顺序排列,最高:
infixr 9 .
infixr 5 ++
infixr 0 $
Run Code Online (Sandbox Code Playgroud)
最高优先级运算符.
首先包含在括号中:
(length . (map (.))) $ (repeat id) ++ [] ++ []
Run Code Online (Sandbox Code Playgroud)
然后++
,它与右边相关联:
(length . (map (.))) $ ((repeat id) ++ ([] ++ []))
Run Code Online (Sandbox Code Playgroud)
并且只有一次使用,$
所以我没有打扰它.
如果你喜欢,你可以转换操作符,如++
以功能(++)
,但我并不相信,这将帮助你,所以我会离开它是,刚刚记住的第一个参数是向左.
从嵌套最多的括号开始通常会有所帮助.