繁体   English   中英

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

[英]How do I add x tuples into a list x number of times?

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

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

您可能会说很多话。 例如,如果你想有一个单一值的几个副本,您可以使用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)]

当然,这是一个特别糟糕的用户界面-我相信您可以想出很多改进方法! 但是,至少,这种模式应该会发光:您可以使用[]等值和:类的函数来构造列表。 还有很多其他许多用于构造和操作列表的高级功能。

PS:元组列表(与其他列表相比)没有什么特别的地方; 以上功能通过不提及它们来显示。 =)

抱歉,您不能1 元组和列表之间存在根本差异:

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

由于这些原因,您不能这样做。 如果不知道元组中可以容纳多少个元素,则无法为其指定类型。

我猜您从用户那里得到的输入实际上是一个像"(1,2,3)"类的字符串。 尝试直接将其设为列表,而之前未使其成为元组。 您可以为此使用模式匹配,但这是一种稍微偷偷摸摸的方法。 我只是从字符串中删除了打开和关闭状态,并用括号替换了它们,瞧,它就变成了一个列表。

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

编辑

抱歉,我没有看到您的最新评论。 您尝试做的并不困难。 我将以下简单功能用于任务:

  • words str分割str成凡空格分开之前的单词列表。 输出是String的列表。 注意 :仅当元组中的字符串不包含空格时,此方法才有效。 实施更好的解决方案留给读者练习。

  • map f lst适用f到的每个元素lst

  • read是一个魔术函数,可以从字符串中获取数据类型。 仅当您之前知道输出应该是什么时,它才起作用。 如果您真的想了解它是如何工作的,请考虑针对您的特定用例实现read

在这里,您去:

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

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

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

假设每个元组写在一行上,我们可以使用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的答案

一个简单的解决方案是使用列表理解,例如(在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

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

我猜想是因为这是一堂课,而且您学习Haskell的时间少于1周,所以您实际上不需要进行任何输入/输出。 但是,这比您可能要先进一些。 所以:

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

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

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

    您可以随意执行多次。 而且如果您还没有元组列表,则您的列表为[]

这样可以满足您的所有需求吗? 如果没有,具体缺少什么?

编辑:具有更正的类型:

Eq a => [(a, b)]

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM