在Where子句中键入规范

bfi*_*eck 3 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
Run Code Online (Sandbox Code Playgroud)

这失败了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
Run Code Online (Sandbox Code Playgroud)

这个无法编译特别无法提供的错误消息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
Run Code Online (Sandbox Code Playgroud)

但是,没有骰子,失败的同样的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
Run Code Online (Sandbox Code Playgroud)

给出错误消息

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

我不知道那是什么意思,但似乎突然忽略了新行.我一直在阅读"了解你一个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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

当我google/hoogle它时,我找不到任何东西,而且我已经看过这个问题了,但是它不仅显示haskell太高级我不能阅读,但基于内容我不相信它们是与我有同样的问题.我已经试过指定的类型calcTriangleAreas,我尝试了在规范走样类型triAreaFloating坦率地说我在我的穷途末路.我文件的顶行是module ChapterThree where,但除此之外,我在每个示例中显示的代码都是整个文件.

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

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

拜托,救我脱离疯狂.

Bak*_*riu 6

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

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

规则是:分配必须对齐.

而且(/)要求Fractional上课:

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

需要注意的是缩进级别符合的缩进级别任何关系where.例如,您可以用这种方式编写代码:

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

缩进级别是通过在所述第一分配定义where/ let或一个的第一行do的块.所有其他行必须与该行对齐.

所以这些都是正确的:

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

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

f x = y
  where
    a = b
    y = ...
Run Code Online (Sandbox Code Playgroud)

  • @bfieck请不要使用标签.每个缩进使用两个空格.每个人都会对你更开心:-) (5认同)
  • 不鼓励使用制表符*因为*Haskell不会在任何级别强制执行任何特定数量的缩进.因为不同用户可以将制表符显示为不同数量的空白,所以*apparent*缩进可能与*actual*缩进不同. (4认同)
  • @bfieck当混合使用制表符和空格时,在大多数编辑器中,很容易看到似乎正确缩进的代码,而不是.从历史上看,Haskell 98委员会决定在检查缩进时将标签计为8个空格.更严格的要求本来会更好.今天,如果您使用标签,GHC会发出警告.有[好的建议](http://dmwit.com/tabs/)但是大多数社区都认为从长远来看避免标签更简单. (2认同)
  • 使用*only*tabs会更糟糕,因为现在我的缩进必须在每个级别缩进相同的数量,而不考虑启动缩进的构造.`let`表达式的第二行和后续行通常缩进4个空格,而`where`表达式的那些行缩进6个空格.许多人将类型签名与每行一种类型对齐,缩进由函数名称的长度指定; 类似的逻辑应用于使用记录语法定义的数据类型.没有固定的标签大小将适应该样式. (2认同)