【问题标题】:Understanding Haskell's type system了解 Haskell 的类型系统
【发布时间】:2014-04-14 13:23:06
【问题描述】:

我有三个函数

boombangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs odd x]

length' xs = sum [1 | _ <- xs]

removeNonUppercase st = [x | x <- st, x `elem` ['A'..'Z']]

这是我得到的每个函数的类型(类型签名?)

*Main> :t boombangs
boombangs :: Integral a => [a] -> [[Char]]
*Main> :t length'
length' :: Num a => [t] -> a
*Main> :t removeNonUppercase 
removeNonUppercase :: [Char] -> [Char]

当我将整数数组传递给 removeNonUppercase 或将字符串传递给boombangs 时,Haskell 应该给我一个错误。它也是,但是我没有在任何地方指定类型,它怎么知道它是错误的。

还有为什么即使它们在相同的输入上工作,boombangs 和 removeNonUppercase 的类型也不同。

如果问题看起来含糊不清或完全无知,我深表歉意。我刚刚开始学习 Haskell,我正在慢慢地围绕这个主要使用 C 和 python 编程的范式展开思考。

任何用于了解更多关于 haskell 和类型系统的资源也将不胜感激。

【问题讨论】:

    标签: haskell


    【解决方案1】:

    GHC 使用类型推断来尝试猜测您的函数可能是什么类型。

    在boombangs 中,由于列表解析中的x &lt;- xs,它可以判断您正在传递一个列表,并且它可以判断列表元素必须具有Integral a =&gt; a 类型,因为您正在应用@ 987654324@ 到每个元素。由于列表理解中的文字 "BOOM" 和 "BANG",它知道您正在返回一个 Strings 列表。

    在length' 中,您的类型仅受sum 约束,这需要Num a =&gt; [a]。您的输入类型是任何类型的列表,因为您实际上并未对元素本身执行任何操作,但您确实表明该参数是_ &lt;- xs 的列表。

    在removeNonUpperCase 中,它看到您传入一个列表的原因与前两个函数相同,并且由于您要检查每个元素是否在列表['A'..'Z'] 中,所以每个元素必须是Char,因此您将获取Chars 的列表并返回Chars 的列表,因为没有对元素执行其他转换。由于String 只是[Char] 的别名,它完全知道类型。

    【讨论】:

    • 这对我来说有点令人着迷。作为后续,你能告诉我为什么长度的类型是length :: [a] -&gt; Int,而我的长度'有更长的length' :: Num a =&gt; [t] -&gt; a。我认为您的回答表明我的长度'由于 sum 函数而具有 Num a 位。内置长度与此有何不同。它可以对我的函数不能操作的类型进行操作吗?
    • 内置的length函数提供了类型签名,使用Int代替Integer、Float或Double效率更高。内置定义也与您的定义不同,但它本质上仍然基于+。 + 的类型是 Num a =&gt; a -&gt; a -&gt; a,因为我们希望该运算符处理所有数字,而不仅仅是 Int。类型签名之间唯一真正的区别是内置使用@​​987654351@ 的具体实例,而您的则更通用。在实践中,让它更通用是没有用的。
    【解决方案2】:

    当我没有在任何地方指定类型时,它怎么知道它是错误的。

    Haskell 编译器,在您的例子中是 GHC,可以进行类型推断,这意味着它可以(几乎总是)通过上下文信息确定表达式的类型。例如,对于

    mbangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs, odd x]
    

    您可以像这样手动推断其类型:

    1. 你通过列表​​理解来定义mbangs,所以xs必须是一个列表,并且

    2. 你在xs的元素上应用odd,因此xs的类型必须是(Integral a) =&gt; [a],因为odd的类型是(Integral a) =&gt; a -&gt; Bool。

    3. 另外,对于xs 的每个元素,您通过输出函数if x &lt; 10 then "BOOM" else "BANG" 生成一个String,

    4. 因此mbangs 的类型必须是Integral a =&gt; [a] -&gt; [[Char]],正如ghci 刚刚告诉你的那样。

    为什么即使在相同的输入上工作,boombangs 和 removeNonUppercase 的类型也不同。

    因为您在他们的列表理解定义中使用了不同的输出函数。

    【讨论】:

    • 因此,函数的类型包括其输入和输出。输出是类型中-&gt; 之后的位吗?
    【解决方案3】:

    对于boombangs,它可以通过您应用于 x 的运算符看到它不能是字符串。对于removeNonUpperCase,可以看出元素必须在['A'..'Z'],所以不能是整数。这也解释了为什么它们不能处理相同的输入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-01
      • 2012-06-29
      • 2014-04-15
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多