Where 子句中的类型说明
Type Specification in a Where Clause
作为家庭作业的一部分,我正在尝试做一些非常简单的事情。我需要做的就是编写一个函数,该函数接收表示三角形底长和高长的二元组数字列表,以及 return 与这些三角形对应的区域列表。其中一个要求是我通过定义一个函数并在 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
,对我来说这听起来像是没有在 where 子句中定义 triArea。好的,让我们缩进它以匹配 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-space 制表符替换其中每一个中的间距,但那没有
帮助。前两个使用制表符产生与 spaces 相同的错误,但最后一个产生的错误如下所示:
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
当我 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.
编辑:请注意,如果我完全删除类型规范,一切都可以正常编译,并且该函数通过所有相关的单元测试。
求求你,救救我吧。
你最后的例子是正确的,但是你写的类型没有意义。 Num
是 class 约束 而不是类型。你可能想写:
calcTriangleAreas xs = [triArea x | x<-xs]
where triArea:: Num a => (a, a) -> a
triArea (base, height) = base*height/2
规则是:分配必须对齐。
此外 (/)
需要 Fractional
class:
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 = ...
spitting out the utterly incomprehensible error message:
Expecting one more argument to ‘Num’
The first argument of a tuple should have kind ‘*’,
but ‘Num’ has kind ‘* -> GHC.Prim.Constraint’
为了补充 Bakuriu 的回答,让我为您解码。
错误说 -- 逐行:
Num
还需要一个参数——我们应该从一些 a
写成 Num a
- 像
(,)
这样的元组类型需要一个类型作为参数。语句 "should have kind *
" 表示 "should be a type"。 Haskell 的分类系统将 *
关联为 "kind of types"。我们有例如Int :: *
、String :: *
和 (Maybe Char, [Int]) :: *
。 Maybe
和 []
等一元类型构造函数不是类型,而是从类型到类型的函数。我们写 Maybe :: *->*
和 [] :: *->*
。它们的种类 *->*
使得可以声明,由于 Maybe :: *->*
和 Char :: *
,我们有类似于普通值级函数的 Maybe Char :: *
("is a type")。 pair 类型构造函数具有种类 (,) :: *->*->*
:它需要两种类型并提供一种类型。
Num
种类 *-> Constraint
。这意味着,对于每个类型 T
,Num T
的种类将是 Constraint
,而不是 (,)
预期的 *
。这会触发一种错误。种类 Constraint
被赋予类型类约束,例如 Eq Int
、Ord Bool
或 Num Int
。这些不是类型,而是对类型的要求。当我们使用 (+) :: Num a => a->a->a
时,我们看到 (+)
适用于任何类型 a
,只要该类型满足 Num a
,即是数字。由于 Num T
不是类型,我们不能写 Maybe (Num T)
或 [Num T]
,我们只能写例如Maybe a
并要求 a
属于类型类 Num
.
作为家庭作业的一部分,我正在尝试做一些非常简单的事情。我需要做的就是编写一个函数,该函数接收表示三角形底长和高长的二元组数字列表,以及 return 与这些三角形对应的区域列表。其中一个要求是我通过定义一个函数并在 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
,对我来说这听起来像是没有在 where 子句中定义 triArea。好的,让我们缩进它以匹配 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-space 制表符替换其中每一个中的间距,但那没有
帮助。前两个使用制表符产生与 spaces 相同的错误,但最后一个产生的错误如下所示:
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
当我 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.
编辑:请注意,如果我完全删除类型规范,一切都可以正常编译,并且该函数通过所有相关的单元测试。
求求你,救救我吧。
你最后的例子是正确的,但是你写的类型没有意义。 Num
是 class 约束 而不是类型。你可能想写:
calcTriangleAreas xs = [triArea x | x<-xs]
where triArea:: Num a => (a, a) -> a
triArea (base, height) = base*height/2
规则是:分配必须对齐。
此外 (/)
需要 Fractional
class:
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 = ...
spitting out the utterly incomprehensible error message:
Expecting one more argument to ‘Num’ The first argument of a tuple should have kind ‘*’, but ‘Num’ has kind ‘* -> GHC.Prim.Constraint’
为了补充 Bakuriu 的回答,让我为您解码。
错误说 -- 逐行:
Num
还需要一个参数——我们应该从一些a
写成 - 像
(,)
这样的元组类型需要一个类型作为参数。语句 "should have kind*
" 表示 "should be a type"。 Haskell 的分类系统将*
关联为 "kind of types"。我们有例如Int :: *
、String :: *
和(Maybe Char, [Int]) :: *
。Maybe
和[]
等一元类型构造函数不是类型,而是从类型到类型的函数。我们写Maybe :: *->*
和[] :: *->*
。它们的种类*->*
使得可以声明,由于Maybe :: *->*
和Char :: *
,我们有类似于普通值级函数的Maybe Char :: *
("is a type")。 pair 类型构造函数具有种类(,) :: *->*->*
:它需要两种类型并提供一种类型。 Num
种类*-> Constraint
。这意味着,对于每个类型T
,Num T
的种类将是Constraint
,而不是(,)
预期的*
。这会触发一种错误。种类Constraint
被赋予类型类约束,例如Eq Int
、Ord Bool
或Num Int
。这些不是类型,而是对类型的要求。当我们使用(+) :: Num a => a->a->a
时,我们看到(+)
适用于任何类型a
,只要该类型满足Num a
,即是数字。由于Num T
不是类型,我们不能写Maybe (Num T)
或[Num T]
,我们只能写例如Maybe a
并要求a
属于类型类Num
.
Num a