在Where子句

时间:2016-10-23 17:48:11

标签: haskell ghc

作为家庭作业的一部分,我试图做一些非常简单的事情。我需要做的就是编写一个函数,该函数接收表示三角形的基本长度和高度长度的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。只是为了好玩,让我们再尝试缩进它,因为idk还有什么可做的:

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

我不知道那是什么意思,但似乎突然忽略了新行。我一直在阅读&#34;了解你一个Haskell&#34;,我本来应该能够用前三章中提供的信息做到这一点,但我已经进行了搜索那些并且它们从未指定那些章节中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

当我google / hoogle时,我找不到任何内容,而且我已经查看了this question,但它不仅显示了haskell 提醒我阅读,但根据内容,我不相信他们会遇到与我相同的问题。我已尝试指定calcTriangleAreas的类型,并且我已尝试将triArea规范中的类型别名为Floating,坦率地说我是我的绳索结束了。我文件的第一行是module ChapterThree where,但除此之外,我在每个示例中显示的代码都是整个文件。

我正在使用32位Linux Mint 18,我正在使用ghc ChapterThree.hs Chapter3UnitTests.hs -o Test进行编译,其中ChapterThree.hs是我的文件,单元测试由我的老师给出,所以我可以很容易判断我的程序是否有效(它从未进入ChapterThreeUnitTests.hs的编译步骤,所以我认为内容不重要),而我的ghc版本是7.10.3。

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

拜托,救我脱离疯狂。

2 个答案:

答案 0 :(得分:6)

你的最后一个例子是正确的,但你写的类型没有意义。 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 = ...

答案 1 :(得分:0)

  

吐出完全不可理解的错误信息:

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

为了补充Bakuriu的答案,让我为你解读。

错误说 - 逐行:

  • Num期待再有一个论点 - 我们应该从某些Num a
  • 写出a
  • 诸如(,)之类的元组类型需要一个类型作为参数。声明&#34;应该有*&#34;意味着&#34;应该是一种类型&#34;。 Haskell的绑定系统将*关联为&#34;类型&#34;。我们有例如Int :: *String :: *(Maybe Char, [Int]) :: *。诸如Maybe[]之类的一元类型构造函数不是类型,而是从类型到类型的函数。我们写Maybe :: *->*[] :: *->*。他们的*->*种类可以说明,自Maybe :: *->*Char :: *以来,我们Maybe Char :: *(&#34;类型为&#34;)与普通价值相似级别的功能。对类型构造函数具有类(,) :: *->*->*:它需要两种类型并提供类型。
  • Num*-> Constraint种。这意味着,对于每种类型TNum 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