帮助可能的Haskell类型推理测验问题

时间:2010-05-11 21:03:24

标签: haskell type-inference inferred-type

foldr:: (a -> b -> b) -> b -> [a] -> b
map :: (a -> b) -> [a] -> [b]
mys :: a -> a
(.) :: (a -> b) -> (c -> a) -> c -> b

推断的类型是什么:
a.map mys ::
b.mys map ::
c.foldr map ::
d.foldr map.mys ::

我尝试使用mys n = n + 2创建mys,但其类型是

mys :: Num a => a -> a

'Num a =>之间有什么区别? a - > a'和'只是'a - >一个'?或者'Num a =>'是什么意思?难道mys只会采用Num类型吗?

所以无论如何,
a)我得到了[a] - > [a]我认为因为它只需要一个列表并根据我对mys的定义将其返回+ 2 b)(a - > b) - > [a] - > [b]我认为因为地图仍然需要带两个参数,如(* 3)和一个列表然后返回[a]进入mys并返回[b]
c)我不知道该怎么做1.
d)我不知道如何做到这一点1,但map.mys意味着先做mys然后映射到右边?

我的答案和想法是否正确?如果没有,为什么不呢?

谢谢!

1 个答案:

答案 0 :(得分:3)

(更新:显然我的原始答案对OP没有太大帮助...请参阅下面的第二个HR作为附录。)


在这种情况下,您真正​​想要做的是启动ghci并使用:t找出各种表达式的类型。 E.g。

:t foldr map
-- answer: foldr map :: [b] -> [b -> b] -> [b]

如果您需要先定义名称,请使用let(在Haskell源文件中不需要):

let mys = undefined :: a -> a
:t map mys
-- answer: [a] -> [a]

请注意undefined使用显式类型签名。找到各种形式的表达式类型是完全可以的,甚至在实际代码中作为早期规划阶段的占位符也很有用。

Num a =>a上的类型类约束;见例如Type Classes and Overloading来自“Haskell的温和介绍,版本98”或来自“真实世界Haskell”的Chapter 6. Using Typeclasses以获取更多信息。 (基本上,它做你认为它做的。: - ))


以上内容对于验证您的答案非常有用(类型类的资源也很好)。至于如何自己解决这类问题:

类型推断是所谓的“统一算法”的应用。谷歌为一些资源“统一”;如果您在查询中添加编程语言的名称,则可能会找到示例实现。

关于如何处理手边的例子......

一个。 map mysmap采用类型为a -> b的函数,并返回类型为[a] -> [b]的函数。通常,a可能与b不同,但mys的类型为a -> a,因此返回的函数的类型为[a] -> [a]

这是一些统一手:

(a -> b) -> [a] -> [b]`  
(a -> a)`
      ^-- at this point we unify a with b;
          when propagated to the return type,
          this produces [a] -> [a]

mys mapmys是一个函数,它接受某种类型的对象并返回相同类型的对象。特别是,如果你传递一个(a -> b) -> [a] -> [b]类型的参数,那将是返回值的类型。

顺便说一下,只有一个“有趣”(非undefined)函数,其类型签名为a -> a(没有类型类约束),即id。请参阅Philip Wadler的论文“免费定理”。 (您可以从this page下载)进行扩展讨论。

℃。 foldr map:首先,请注意a签名中的bfoldrmap签名中的mapa签名无关。将c的{​​{1}}重命名为bd重命名为map :: (c -> d) -> [c] -> [d]并使用签名(a -> b -> b)更方便明显如下。另请注意,(a -> (b -> b))只是编写(a -> (b -> b)) (c -> d) -> [c] -> [d] 的简单方法。

更多的手统一(以下解释):

foldr

这里发生的是(a -> (b -> b))采用类型为map的函数参数。如果您传递a作为该参数,则c -> db统一,[c][d]统一,然后再与c统一,这意味着d等于foldr

b -> [a] -> b的返回值的类型为[c] -> [c -> c] -> [c] ^-- c equals d, right? ;替换前一段中获得的更具体的类型,我们得到

c

map来自我们更改的b签名;使用原始[b] -> [b -> b] -> [b] ,这变为

foldr map . mys

d。 (foldr map) . mys:这实际上是foldr (map . mys),而不是{{1}} - 函数应用程序(“隐形运算符”)绑定最强!结合一个。和c。从上面解决这个问题留给读者作为练习。 ; - )