如何访问Haskell元组中的第n个元素

时间:2013-10-07 11:10:23

标签: haskell tuples ghc

我有这个:

 get3th (_,_,a,_,_,_) = a

在GHCI中工作正常,但我想用GHC编译它,它给出了错误。如果我想编写一个函数来获取元组的第n个元素并且能够在GHC中运行我该怎么办? 我的所有程序如下所示,我应该怎么做?

 get3th (_,_,a,_,_,_) = a


 main = do 

    mytuple  <- getLine 
    print $  get3th mytuple

3 个答案:

答案 0 :(得分:0)

getLine的类型为IO String,因此您的程序不会键入check,因为您提供的是String而不是元组。

如果提供了适当的参数,您的程序将起作用,即:

main = do 
  print $  get3th (1, 2, 3, 4, 5, 6)

答案 1 :(得分:0)

您的问题是getLine为您提供String,但您需要某种元组。您可以通过将String转换为元组来解决问题,例如使用内置的read函数。这里的第三行尝试将String解析为Int的六元组。

main = do
  mystring <- getLine

  let mytuple = read mystring :: (Int, Int, Int, Int, Int, Int)

  print $ get3th mytuple

但是请注意,虽然这对于学习类型等很有用,但是在实践中不应该编写这种代码。至少有两个警示标志:

  1. 你有一个元组超过三个的元组。很少需要这样的元组,并且通常可以用列表,向量或自定义数据类型替换。元组很少被临时用于将两种数据合并为一个值。如果您经常开始使用元组,请考虑是否可以创建自己的数据类型。

  2. 使用read读取结构并不是一个好主意。 read会在任何微小的错误中以可怕的错误消息爆炸您的程序,这通常不是您想要的。如果需要解析结构,最好使用真正的解析器。 read对于简单的整数就足够了,但仅限于此。

答案 2 :(得分:0)

在我看来,你的混淆是在元组和列表之间。当你第一次见到Haskell时,这是一个可以理解的混乱,因为许多其他语言只有一个类似的结构。元组使用圆形的parens:(1,2)。其中包含n个值的元组是一个类型,每个值可以是不同的类型,从而产生不同的元组类型。所以(Int, Int)是与(Int, Float)不同的类型,两者都是两个元组。前奏中有一些函数是两个元组的多态,即fst :: (a,b) -> a取第一个元素。 fst很容易使用模式匹配来定义,就像您自己的函数一样:

fst (a,b) = a

请注意,fst (1,2)的评估结果为1,但fst (1,2,3)版的类型错误,无法编译。

现在,另一方面,列表可以是任何长度,包括零,并且仍然是相同的类型;但每个元素必须是相同的类型。列表使用方括号:[1,2,3]。类型为a的列表的类型写为[a]。列表是通过将值附加到空列表[]来构建的,因此包含一个元素的列表可以键入[a],但这是a:[]的语法糖,其中: cons 运算符,它将值附加到列表的头部。像元组可以模式匹配,你可以使用空列表和cons运算符来模式匹配:

head :: [a] -> a
head (x:xs) = x

模式匹配意味着x的类型为a,而xs的类型为[a],它是我们想要head的前者。 (这是一个前奏函数,有一个类似的函数tail。)

请注意head是一个部分函数,​​因为我们无法定义它在空列表中的作用。在空列表中调用它将导致运行时错误,因为您可以在GHCi中自行检查。更安全的选择是使用Maybe类型。

safeHead :: [a] -> Maybe a
safeHead (x:xs) = Just x
safeHead [] = Nothing
Haskell中的

String只是[Char]的同义词。因此,所有这些列表函数都可用于字符串,getLine返回String

现在,在您的情况下,您需要第3个元素。您可以通过以下两种方式执行此操作:您可以拨打tail几次,然后拨打head,或者您可以将模式匹配为(a:b:c:xs)。但是前奏中有另一个效用函数,(!!)得到第n个元素。 (写这个功能是一个非常好的初学者练习)。所以你的程序可以编写

main = do
    myString <- getLine
    print $ myString !! 2  --zero indexed

测试给出

Prelude> main
test
's'

所以请记住,我们()元组并且严格按照给定的长度,但可以有不同类型的成员;列表使用'[]',可以是任意长度,但每个元素必须是相同的类型。并且String是真正的字符列表。

修改

顺便说一句,我想如果你有兴趣,我会提到有一种更简洁的方式来编写这个主要功能。

main = getLine >>= print . (!!3)