对于那些善于使用Haskell的人而言,这是一个简单的问题! 为什么我写:
.loc
我获得了一个功能:
let a b = (5,6)
此外,b未实例化。我试图理解它是徒劳的。 谢谢你的帮助!
答案 0 :(得分:8)
let a b = (5, 6)
您正在定义一个名为a
的函数,它接受一个名为b
的参数。此函数忽略其参数并返回(5, 6)
。我假设您希望a
和b
分别绑定到5
和6
,在这种情况下,您需要以下语法。
let (a, b) = (5, 6)
答案 1 :(得分:4)
答案详细说明了为什么Haskell会提出具体的结果:
好的,让我们分解吧。在Haskell中,数字常量可以有多个可能的类型,因此5
可以是Int
,Integer
,Word
等,(5,6)
可能有输入(Int, Integer)
,(Int, Int)
或其他内容。因此,GHC任意将其类型表示为(a,b)
,并将等待,看看您是否稍后在上下文中使用结果,以便推断出类型。如果没有,则默认为(Integer, Integer)
。
碰巧GHC为在等号左侧用作标识符的未知类型分配了相同的小写字母,但它们是相同名称的无关使用。您可以将a b =
更改为f _ = (5,6)
,如果这样可以更清楚地了解Haskell在字面上看到的内容。
您的声明a b
是名为a
的函数,其中包含一个参数b
。此参数未使用,因此除非您调用它,否则GHC无法为其推断出类型,并将其指定为p
。
所以你声明了一个带p
的函数并返回一对未知类型a
和b
的数字:p -> (a,b)
。
正如Sivio Mayolo打败我说的那样,如果你想绑定变量a
和b
,你可以写(a,b) = (5,6)
。
HTNW建议我多谈一下这些数字类型的价值。 The Haskell 2010 Report说:“整数字面表示函数fromInteger
应用于类型Integer
的适当值。”
因此,常量5
相当于(fromInteger (5::Integer))
。
fromInteger
定义在哪里?作为类型类Num
的一部分。它的类型为fromInteger :: (Num a) => Integer -> a
。也就是说,每个instance
类型类Num
(包括Int
,Double
等等)都有自己定义的fromInteger
多态版本,将Integer
转换为该类型的值。
如果编译器可以推断出常量的类型,或者因为你提供了类型注释,或者因为你在需要特定类型的表达式中使用它,那么它将知道要调用哪个版本的fromInteger
获得该类型的常量。 (事实上,它肯定会在编译时优化掉调用,只是在运行时使用结果。)如果你把它完全放到编译器上,GHC会选择Integer
并给你一个警告。
如果您尝试绑定x = 5
然后使用x
作为任何类型的Num
,它都会有效 - 但如果您尝试将其用作两个不同 types,编译器将无法解析它。因此,如果您需要在一行中使用x
作为Int
,然后又希望稍后将其作为Double
传递,则需要将转换写入{{ 1}}为Double
。这样,(fromIntegral x)
始终是x
,每个人都很开心。
类型系统可能但不允许的转换示例:与C不同,尝试将数字文字用作Int
将不起作用,因为Char
不是实例Char
。但是,它是Num
,因此您可以使用Enum
和fromEnum
在toEnum
和Char
之间进行转换。
所以,如果你在GHCI中尝试这个,你得到:
Int
Prelude> 7 :: Char
<interactive>:1:1: error:
• No instance for (Num Char) arising from the literal ‘7’
• In the expression: 7 :: Char
In an equation for ‘it’: it = 7 :: Char
不是Char
的实例,因此没有Num
版本转换为fromInteger
。
Char
这实际上是Prelude> toEnum 7 :: Char
'\a'
。每个toEnum (fromInteger 7) :: Char
都有一个Enum
函数,可以从toEnum
转换为Int
类型。最后的Enum
告诉GHCI要转换为:: Char
是Enum
,因此GHCI可以推断它应该将{7}从Char
转换为Integer
Int
。 Haskell从C中借用了用于ASCII / Unicode代码点7的Char
转义码。(对于 alert ,如果你在终端上键入control-G,它曾经对你发出哔哔声。仍在Linux控制台中工作,或者至少使窗口闪烁。)