【问题标题】:Type Inferring of function HaskellHaskell函数的类型推断
【发布时间】:2014-05-13 14:57:10
【问题描述】:

我试图推断以下类型:

((.) foldr)

我手动推断的类型与一个 ghci 推断不同。这是我的工作:

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

现在我的第一个疑问。 Foldr 必须与 b->c 统一 foldr 必须与 (b->c) 统一,但实现它的方法不止一种;喜欢

b ~ (a'->b'->b')
c ~ b'->[a']->b'

或者..

b ~ (a'->b'->b')b'->[a']
c ~ b'

我怎么知道要吃哪个?

在 ghci 中做不同的例子,我得出的结论是,haskell 试图以非贪婪的方式统一第一个参数的类型(这个结论完全是实验性的,可能是完全错误的,也许这是我得出错误类型的原因对于函数,但这是我在haskell上尝试过的类型推断的想法)。所以,假设这是真的,配置haskell首先尝试统一是:

b ~ (a'->b'->b')
c ~ b'->[a']->b'

那么现在..

(.)foldr :: (a->b)->a->c

代入 b 和 c:

    (.)foldr :: (a-> (a'->b'->b') )->a->b'->[a']->b' 

这足够接近我唯一的问题是表达式中的括号 (a'->b'->b') 当您无法删除原始文件夹中的那些时,为什么我可以删除它们,并且该功能将成为文件夹的输入。为什么在应用合成函子后可以使用部分应用?有这样的规定吗? 我也想如果有人可以确认或拒绝“非贪婪”类型匹配..

【问题讨论】:

    标签: function haskell types


    【解决方案1】:

    -> 的关联性

    在 Haskell 中,唯一的函数类型是 a -> b,这是一个接受 a 并“返回”b 的函数。因此,函数类型为:

    a -> b -> c
    

    是隐含的:

    a -> (b -> c)
    

    这是一个接受a 并返回一个接受b 并返回c 的函数的函数。你只需要记住->right associative。这是允许柯里化的“机制”。

    答案

    我怎么知道要吃哪个?

    所以,在你的例子中:

    foldr:: (a' -> b' -> b') -> b' -> [a'] -> b'
    

    变成:

    foldr:: (a' -> b' -> b') -> (b' -> ([a'] -> b'))
    

    如您所见,推断类型a -> b 的唯一方法是将(a'->b'->b') 分配给a 并将(b'->([a']->b')) 分配给b


    当你无法删除原始文件夹中的那些时,为什么我可以删除它们,并且该函数将成为文件夹的输入?

    因为函数组合后,类型为:

    (a -> (a' -> b' -> b')) -> a -> b' -> [a'] -> b'
    -- ^^^^^^^^^^^^^^^^^^^^
    

    让我们专注于第一部分:

    (a -> (a' -> b' -> b'))
    

    对于-> 的右结合性,这等于:

    (a -> (a' -> (b' -> b')))
    

    也等于:

    (a -> a' -> b' -> b')
    

    对于相同的关联规则。


    为什么在应用合成函子后可以使用部分应用?有规定吗?

    当您有一个函数采用超过 1 个“参数”时(或者更准确地说,当您有一个返回函数的函数时),始终可以应用部分应用程序。

    【讨论】:

    • 因此,如果我理解正确,请删除此处的括号,因为在这种情况下,它们不会对此处使用柯里化的可能性施加限制。如果是(a -> ((a' -> b') -> b')) 而不是(a -> (a' -> b' -> b')),那么在这种情况下,生成的类型会以(a' -> b') -> b' 的形式加上括号,对吗?
    • @user3558296,使用柯里化的能力并不取决于你放置了多少括号(只要类型保持相同)。如果你有 (a -> ((a' -> b') -> b')) 并且如果你用一个元素对它进行柯里化,你会收到一个 (a' -> b') -> b' 类型的函数,是的。
    【解决方案2】:

    在类型签名中,(->) 是右结合的,这意味着

    a -> b -> c
    

    这是一个函数的类型,它接受a类型的参数并返回另一个b -> c类型的函数,等于

    a -> (b -> c)
    

    但是不等于

    (a -> b) -> c
    

    这是一个函数的类型,它将另一个 a -> b 类型的函数作为其唯一参数并返回一个 c 类型的值。

    问题一:

    我怎么知道要吃哪个?

    你应该选择第一个版本,就像你已经做的那样,因为

    (a'->b'->b')->b'->[a']->b'
    

    等于

    (a'->b'->b')->(b'->[a']->b')
    

    这叫currying,不是贪心。

    问题 2:

    为什么不能删除原始文件夹中的那些,我可以删除它们

    同样的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-10
      • 1970-01-01
      • 2016-01-24
      • 2013-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多