来自元组的函数 - Haskell

时间:2018-01-02 00:51:35

标签: haskell pattern-matching

对于那些善于使用Haskell的人而言,这是一个简单的问题! 为什么我写:

.loc

我获得了一个功能:

let a b = (5,6)

此外,b未实例化。我试图理解它是徒劳的。 谢谢你的帮助!

2 个答案:

答案 0 :(得分:8)

let a b = (5, 6)

您正在定义一个名为a的函数,它接受一个名为b的参数。此函数忽略其参数并返回(5, 6)。我假设您希望ab分别绑定到56,在这种情况下,您需要以下语法。

let (a, b) = (5, 6)

答案 1 :(得分:4)

答案详细说明了为什么Haskell会提出具体的结果:

好的,让我们分解吧。在Haskell中,数字常量可以有多个可能的类型,因此5可以是IntIntegerWord等,(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的函数并返回一对未知类型ab的数字:p -> (a,b)

正如Sivio Mayolo打败我说的那样,如果你想绑定变量ab,你可以写(a,b) = (5,6)

P.S:

HTNW建议我多谈一下这些数字类型的价值。 The Haskell 2010 Report说:“整数字面表示函数fromInteger应用于类型Integer的适当值。”

因此,常量5相当于(fromInteger (5::Integer))

fromInteger定义在哪里?作为类型类Num的一部分。它的类型为fromInteger :: (Num a) => Integer -> a。也就是说,每个instance类型类Num(包括IntDouble等等)都有自己定义的fromInteger多态版本,将Integer转换为该类型的值。

如果编译器可以推断出常量的类型,或者因为你提供了类型注释,或者因为你在需要特定类型的表达式中使用它,那么它将知道要调用哪个版本的fromInteger获得该类型的常量。 (事实上​​,它肯定会在编译时优化掉调用,只是在运行时使用结果。)如果你把它完全放到编译器上,GHC会选择Integer并给你一个警告。

如果您尝试绑定x = 5然后使用x作为任何类型的Num,它都会有效 - 但如果您尝试将其用作两个不同 types,编译器将无法解析它。因此,如果您需要在一行中使用x作为Int,然后又希望稍后将其作为Double传递,则需要将转换写入{{ 1}}为Double。这样,(fromIntegral x)始终是x,每个人都很开心。

类型系统可能但不允许的转换示例:与C不同,尝试将数字文字用作Int将不起作用,因为Char不是实例Char。但是,它是Num,因此您可以使用EnumfromEnumtoEnumChar之间进行转换。

所以,如果你在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要转换为:: CharEnum,因此GHCI可以推断它应该将{7}从Char转换为Integer Int。 Haskell从C中借用了用于ASCII / Unicode代码点7的Char转义码。(对于 alert ,如果你在终端上键入control-G,它曾经对你发出哔哔声。仍在Linux控制台中工作,或者至少使窗口闪烁。)