我如何找出没有ghci的haskell表达式的类型?

时间:2018-07-31 12:18:16

标签: haskell lambda type-inference typing lambda-calculus

只要不包含任何奇怪的函数,例如mapfilterfoldr或其中的任何合成,我就很擅长推断lambda表达式的类型。但是,一旦我有类似的东西

\x y -> map x (y (. x))

我完全迷路了,无法终生解决不使用ghci的类型。

任何帮助将不胜感激

谢谢

2 个答案:

答案 0 :(得分:2)

我对“奇怪”的理解是,您的意思是高阶函数。此表达式包含两个:map :: (a -> b) -> [a] -> [b](.) :: (b -> c) -> (a -> b) -> a -> c。它也是一个lambda,因此本身可能是一个高阶函数。此处带括号的箭头是函数参数的类型。

map显示y必须返回x接受为参数的项目列表。因此它们具有部分签名x :: _yitem -> _outeritemy :: _yarg -> [_yitem],其中此map的返回值是[_outeritem]类型。请注意,我们尚不知道这些通配符中可以容纳多少个箭头。

(. x)转换为\l -> l . x,后者转换为\l r -> l (x r)。整个lambda是适合y的参数,因此y是一个高阶函数。 l必须接受x的返回值。该名称具有l :: _outeritem -> _lret(. x) :: (_outeritem -> _lret) -> _xarg -> _lret的名称,因为r被用作x的参数。哦,_xarg因映射为_yitem而为人所知。

好吧,这本身就是一堆令人困惑的步骤,所以让我们对结果进行排队:

type OuterLambda = _xtype -> _ytype -> MapRet
x :: _yitem -> _outeritem
type MapRet = [_outeritem]
y :: YArg -> [_yitem]
type YArg = (_outeritem -> _lret) -> _yitem -> _lret
y :: ((_outeritem -> _lret) -> _yitem -> _lret) -> [_yitem]

进步!它具有往返xy的每种类型的名称。但是我们的表达是lambda,因此我们必须接受这两个:

(_yitem -> _outeritem) -> 
(((_outeritem -> _lret) -> _yitem -> _lret) -> [_yitem]) ->
[_outeritem]

这是一种非常长的类型。让我们将其与山本雄二向我们展示的编译器推断类型进行比较:

(a0 -> b0) -> 
(((b0 -> c0) -> a0 -> c0) -> [a0]) -> 
[b0]

它匹配。我们在这里有很多功能顺序:表达式需要功能xy,而y需要功能本身具有l功能。而且,我们确实为之命名的所有类型可能反过来变得非常复杂。

答案 1 :(得分:0)

注释故意错误的类型(通常为())会为您提供帮助。
例如:

> (\x y -> map x (y (. x))) :: ()

<interactive>:1:2: error:
    • Couldn't match expected type ‘()’
                  with actual type ‘(a0 -> b0)
                                    -> (((b0 -> c0) -> a0 -> c0) -> [a0]) -> [b0]’
    • The lambda expression ‘\ x y -> map x (y (. x))’
      has two arguments,
      but its type ‘()’ has none
      In the expression: (\ x y -> map x (y (. x))) :: ()
      In an equation for ‘it’: it = (\ x y -> map x (y (. x))) :: ()

这篇文章中介绍了这个技巧:http://www.parsonsmatt.org/2018/05/19/ghcid_for_the_win.html