Where子句中的类型说明



我想做一些非常简单的事情作为家庭作业的一部分。我所需要做的就是写一个函数,它接受一个由代表三角形底长和高长的2元组数字组成的列表,并返回一个与这些三角形对应的面积列表。其中一个要求是,我通过定义函数并在where子句中声明其类型来实现这一点。到目前为止,我所尝试的一切都无法编译,以下是我得到的:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: (Num, Num) -> Num --this uses 4 preceding spaces 
triArea (base, height) = base*height/2

这与错误The type signature for ‘triArea’ lacks an accompanying binding失败,这对我来说听起来像triArea没有在where子句中定义。好的,让我们缩进它以匹配where:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: (Num, Num) -> Num --this uses 4 preceding spaces 
    triArea (base, height) = base*height/2 --... and so does this

这个不能编译特别没有信息的错误消息parse error on input triArea。为了好玩,让我们试着再缩进一点,因为我不知道还能做什么:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: (Num, Num) -> Num --this uses 4 preceding spaces 
        triArea (base, height) = base*height/2 --this has 8

但是,没有骰子,失败了相同的parse error消息。我试着用相等的4个空格的制表符替换这些空格,但没有的帮助。前两个使用制表符会产生与使用空格相同的错误,但最后一个,如下所示:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: (Num, Num) -> Num --this uses a preceding tab character 
        triArea (base, height) = base*height/2 --this has 2

给出错误信息

Illegal type signature: ‘(Num, Num) -> Num triArea (base, height)’
  Perhaps you intended to use ScopedTypeVariables
In a pattern type-signature

,我不知道它想说什么,但它似乎突然忽略了换行符。我一直在阅读"Learn You a Haskell",我应该能够通过前三章提供的信息做到这一点,但是我已经搜索了那些章节,它们从未指定在这些章节中where子句中定义的函数类型。为了记录,他们的例子似乎不尊重空格,我复制了其中一个的样式:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: (Num, Num) -> Num --4 preceding spaces
          triArea (base, height) = base*height/2 --10 preceding spaces

,但这也无法编译,吐出完全无法理解的错误信息:

Expecting one more argument to ‘Num’
    The first argument of a tuple should have kind ‘*’,
      but ‘Num’ has kind ‘* -> GHC.Prim.Constraint’
    In the type signature for ‘triArea’: triArea :: (Num, Num) -> Num
    In an equation for ‘calcTriangleAreas’:
        calcTriangleAreas xs
          = [triArea x | x <- xs]
          where
              triArea :: (Num, Num) -> Num
              triArea (base, height) = base * height / 2

我找不到任何当我谷歌/hoogle它,我已经看了这个问题,但它不仅是显示haskell太远了但根据内容,我不相信他们有和我一样的问题。我试过指定calcTriangleAreas的类型,我试过在triArea的规格中将类型混叠为Floating,坦率地说,我已经走极端了。我的文件的第一行是module ChapterThree where,但除此之外,我在每个示例中展示的代码是整个文件。

我正在32位Linux Mint 18上工作,并且我正在编译ghc ChapterThree.hs Chapter3UnitTests.hs -o Test,其中第三章。这是我的文件,单元测试是我的老师给的,所以我可以很容易地判断我的程序是否工作(它从来没有得到第三章单元测试的编译步骤。所以我不认为内容会很重要),我的ghc版本是7.10.3。

编辑:请注意,如果我只是完全删除类型规范,一切都编译得很好,并且该函数通过了所有相关的单元测试。

请把我从疯狂中拯救出来。

你的最后一个例子是正确的,但是你写的类型没有意义。Num类约束,而不是类型。你可能想写:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: Num a => (a, a) -> a
          triArea (base, height) = base*height/2 

规则是:赋值必须对齐。

(/)要求Fractional类:

calcTriangleAreas xs = [triArea x | x<-xs]
    where triArea:: Fractional a => (a, a) -> a
          triArea (base, height) = base*height/2 

注意,缩进级别where的缩进级别没有任何关系。例如,您可以这样编写代码:

calcTriangleAreas xs = [triArea x | x<-xs] where
    triArea:: Fractional a => (a, a) -> a
    triArea (base, height) = base*height/2 

缩进级别由where/let中的第一个赋值或do块的第一行定义。所有其他行必须与这一行对齐。

所以这些都是正确的:

f x = y where
  a = b
  y = ...
f x = y
  where a = b
        y = ...
f x = y
  where
    a = b
    y = ...

吐出完全无法理解的错误信息:

Expecting one more argument to ‘Num’
   The first argument of a tuple should have kind ‘*’,
     but ‘Num’ has kind ‘* -> GHC.Prim.Constraint’

为了补充巴库里乌的回答,让我为你解码一下。

错误提示——逐行:

  • Num期待更多的参数——我们应该从一些a中写Num a
  • (,)这样的元组类型需要一个类型作为参数。语句"应该有kind *"意味着"应该是一种类型"。Haskell的分类系统将*关联为"类类型"。例如,Int :: *String :: *(Maybe Char, [Int]) :: *。一元类型构造函数(如Maybe[])不是类型,而是从类型到类型的函数。我们写Maybe :: *->*[] :: *->*。它们的类型*->*使得有可能声明,由于Maybe :: *->*Char :: *,我们有Maybe Char :: *("是一种类型")类似于普通的值级函数。pair类型构造函数的类型为(,) :: *->*->*:它期望两个类型,并提供一个类型。
  • Num有种类*-> Constraint。这意味着,对于每种类型T, Num T的类型将是Constraint,而不是(,)所期望的*。这会触发一个类型错误。类型Constraint被赋予类型类约束,如Eq IntOrd BoolNum Int。这些不是类型,而是对类型的需求。当我们使用(+) :: Num a => a->a->a时,我们看到(+)适用于任何类型a,只要该类型满足Num a,即是数字。由于Num T不是类型,我们不能写Maybe (Num T)[Num T],我们只能写例如Maybe a,并在上下文中要求a属于Num类型类。

最新更新