如何将x元组添加到列表中x次?

时间:2011-10-10 16:29:33

标签: list haskell tuples

我对Haskell中的元组和列表有疑问。我知道如何将输入添加到元组特定次数。现在我想将元组添加到未知次数的列表中;由用户决定他们想要添加多少个元组。

如果我事先不知道X,如何将元组添加到列表中x次?

5 个答案:

答案 0 :(得分:4)

你可能有很多意思。例如,如果您想要单个值的几个副本,则可以使用前奏中定义的replicate

replicate :: Int -> a -> [a]
replicate 0 x = []
replicate n | n < 0     = undefined
            | otherwise = x : replicate (n-1) x

在ghci:

Prelude> replicate 4 ("Haskell", 2)
[("Haskell",2),("Haskell",2),("Haskell",2),("Haskell",2)]

或者,也许你真的想做一些IO来确定列表。然后一个简单的循环将会:

getListFromUser = do
    putStrLn "keep going?"
    s <- getLine
    case s of
        'y':_ -> do
            putStrLn "enter a value"
            v <- readLn
            vs <- getListFromUser
            return (v:vs)
        _ -> return []

在ghci:

*Main> getListFromUser :: IO [(String, Int)]
keep going?
y
enter a value
("Haskell",2)
keep going?
y
enter a value
("Prolog",4)
keep going?
n
[("Haskell",2),("Prolog",4)]

当然,这是一个特别糟糕的用户界面 - 我相信你可以提出十几种方法来改进它!但至少应该通过以下模式:您可以使用[]之类的值和:之类的函数来构建列表。还有许多其他更高级别的函数用于构造和操作列表。

P.S。元组列表没有什么特别之处(与其他事物的列表相比);以上功能显示,从不提及它们。 =)

答案 1 :(得分:1)

抱歉,你不能 1 。元组和列表之间存在根本区别:

  • 元组总是有一定数量的元素,在编译时已知 。具有不同元素数量的元组实际上是不同的类型。
  • 列出一个包含所需数量的元素。列表中的元素数量不需要在编译时知道。
  • 元组可以包含任意类型的元素。由于你可以使用元组的方式总是确保没有类型不匹配,这是安全的。
  • 另一方面,列表的所有元素必须具有相同的类型。 Haskell是一种静态类型的语言;这基本上意味着所有类型在编译时都是已知的。

由于这些原因,你不能。如果它不知道,有多少元素适合元组,你就不能给它一个类型。

我猜你从用户那里获得的输入实际上是一个像"(1,2,3)"这样的字符串。尝试直接将它作为一个列表,而不是之前使它成为一个元组。你可以使用模式匹配,但这是一个有点偷偷摸摸的方法。我只是从字符串中删除了打开和关闭的paranthesis并用括号替换它们 - 瞧它就成了一个列表。

tuplishToList :: String -> [Int]
tuplishToList str = read ('[' : tail (init str) ++ "]")

修改

抱歉,我没有看到您的最新评论。你试图做的并不是那么困难。我将这些简单的函数用于我的任务:

  • words strstr拆分为以前用空格分隔的单词列表。输出是String的列表。 警告:仅当元组中的字符串不包含空格时才有效。实施更好的解决方案留给读者作为练习。

  • map f lstf应用于lst的每个元素

  • read是一个神奇的函数,它从String中生成数据类型。它只有在您之前知道输出应该是什么时才有效。如果您真的想了解其工作原理,请考虑为您的特定用例实施read

你走了:

tuplish2List :: String -> [(String,Int)]
tuplish2List str = map read (words str)

1 正如其他一些人可能指出的那样,有可能使用模板和其他黑客,但我不认为这是一个真正的解决方案。

答案 2 :(得分:0)

在进行函数式编程时,通常最好考虑操作的组合而不是单个步骤。因此,我们可以先将输入分为字符串列表,然后将每个字符串转换为元组,而不是像将元组一次一个地添加到列表中那样思考它。

假设每个元组都写在一行上,我们可以使用lines拆分输入,然后使用read来解析每个元组。为了使其适用于整个列表,我们使用map

main = do input <- getContents
          let tuples = map read (lines input) :: [(String, Integer)]
          print tuples

我们试一试。

$ runghc Tuples.hs
("Hello", 2)
("Haskell", 4)

在这里,我按 Ctrl + D 将EOF发送到程序,(或Windows上的 Ctrl + Z ),然后打印结果。

[("Hello",2),("Haskell",4)]

如果你想要更具互动性的东西,你可能需要做自己的递归。有关此示例,请参阅Daniel Wagner's answer

答案 3 :(得分:0)

一个简单的解决方案是使用列表理解,如此(在GHCi中完成):

Prelude> let fstMap tuplist = [fst x | x <- tuplist]
Prelude> fstMap [("String1",1),("String2",2),("String3",3)]
["String1","String2","String3"]
Prelude> :t fstMap
fstMap :: [(t, b)] -> [t]

这适用于任意数量的元组 - 与用户想要使用的数量一样多。

要在代码中使用它,您只需编写:

fstMap :: Eq a => [(a,b)] -> [a]
fstMap tuplist = [fst x | x <- tuplist]

我给出的例子只是一种可能的解决方案。顾名思义,当然,你可以写:

fstMap' :: Eq a => [(a,b)] -> [a]
fstMap' = map fst

这是一个更简单的解决方案。

答案 4 :(得分:0)

我猜这个,因为这是一个班级,你一直在研究Haskell for&lt; 1周,你实际上不需要做任何输入/输出。那比你可能的要先进一点。所以:

  • 正如其他人所说,map fst将获取任意长度的元组列表,并返回第一个元素。你说你知道怎么做。细

  • 但是元组如何首先进入列表?好吧,如果你有一个元组列表并想要添加另一个,(:)就可以了。像这样:

    oldList = [("first", 1), ("second", 2)]
    newList = ("third", 2) : oldList
    

    你可以随心所欲地多次这样做。如果您还没有元组列表,则列表为[]

这可以做你需要的一切吗?如果没有,具体是什么缺失?

编辑:使用更正后的类型:

Eq a => [(a, b)]

这不是函数的类型。它是元组列表的类型。只需让用户在提示符下键入yourFunctionName后跟[ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)]