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

如何访问Haskell元组中的第n个元素,haskell,tuples,ghc,Haskell,Tuples,Ghc,我有这个: get3th (_,_,a,_,_,_) = a 它在GHCI中运行良好,但我想用GHC编译它,它给出了错误。如果我想编写一个函数来获取元组的第n个元素,并能够在GHC中运行,我应该怎么做? 我的所有程序如下所示,我应该如何处理 get3th (_,_,a,_,_,_) = a main = do mytuple <- getLine print $ get3th mytuple get3th(u,u,a,u,u,u,u)=a main=

我有这个:

 get3th (_,_,a,_,_,_) = a
它在GHCI中运行良好,但我想用GHC编译它,它给出了错误。如果我想编写一个函数来获取元组的第n个元素,并能够在GHC中运行,我应该怎么做? 我的所有程序如下所示,我应该如何处理

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


 main = do 

    mytuple  <- getLine 
    print $  get3th mytuple
get3th(u,u,a,u,u,u,u)=a
main=do

mytuplegetLine的类型是
IO字符串
,因此您的程序不会进行类型检查,因为您提供的是
字符串
,而不是元组

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

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

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

main = do
  mystring <- getLine

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

  print $ get3th mytuple
main=do

mystring在我看来,您的困惑在于元组和列表之间。当您第一次遇到Haskell时,这是可以理解的困惑,因为许多其他语言只有一个类似的结构。元组使用圆形参数:
(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]
类型,这是我们想要的
头部的前者。(这是一个前奏功能,还有一个类似的功能
tail

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

safeHead :: [a] -> Maybe a
safeHead (x:xs) = Just x
safeHead [] = Nothing
Haskell中的
String
只是
[Char]
的同义词。所以所有这些列表函数都可以在字符串上使用,
getLine
返回一个
String

现在,在你的例子中,你需要第三个元素。有几种方法可以做到这一点,你可以调用
tail
几次,然后调用
head
,或者你可以像
(a:b:c:xs)
那样进行模式匹配。但是前奏曲中还有另一个实用函数,
(!!)
,它获取第n个元素。(编写此函数是一个非常好的初学者练习)。这样你的程序就可以写了

main = do
    myString <- getLine
    print $ myString !! 2  --zero indexed
所以请记住,元组us
()
,严格来说是给定长度的,但可以有不同类型的成员;列表使用“[]”,可以是任意长度,但每个元素必须是相同的类型。和
String
s实际上是字符列表

编辑

顺便说一句,如果你感兴趣的话,我想我应该提到有一种更简洁的方法来编写这个主函数

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

请注意,使用大于
(a,b)
@leftaround的元组通常是一个坏主意。关于为什么这是一个坏主意?@AmiTavory:因为您不能使用
fst
snd
访问元素。好的,有各种各样的库函数可以将作业推广到更大的元组,但是这些函数需要类多态性,这会使事情变得不必要的复杂。通常,当有两个以上的元素需要处理时,最好做一个合适的
数据
记录,这样就可以清楚地了解每个字段的含义。如果您在本地需要它,您也可以只嵌套元组
((a,b)、(c,d))
可以单独使用
fst
snd
解构。@leftaround非常感谢@左撇子一旦你的导师交给你一个包含48个11元组的列表来处理作业,你别无选择,你必须从庞大的元组开始,不管你如何处理,你最终必须输入2次(从变异元组转换为记录格式)。如果能够更快地访问某些内容以离开这样的情况,最好不必键入两次(如果手动添加ACCESOR,则可以键入更多)。我不是在编造,这确实发生了。这是真的,它是这样工作的,但是在这里我如何为IO提供合适的参数呢?正如@leftaroundabout所提到的,元组大于(a,b)是个坏主意。如果您仍然想执行此操作,请在do块中获取六个输入,并将它们作为元组提供给函数。(或者您可以根据您的约束将字符串转换为六个元组。)我是Haskell的初学者,您的意思是“在do块中获取六个输入并将它们作为元组提供给函数”意味着添加一个let temp=my tuple?Re:point#2:还有
readMaybe
now(),这不会因为mistake@amindfv的确我建议总是使用
readMaybe
readother
而不是
read
。霍维夫
main = getLine >>= print . (!!3)