从列表中获取一个字符串并将其保存到另一个列表中?

时间:2012-09-19 18:12:15

标签: haskell

我试图从字符串列表中抓取一个随机项并将其保存到另一个字符串列表中,但我无法让我的代码工作。

    import System.Random
    import Control.Applicative ( (<$>) )

    food = ["meatballs and potoes","veggisoup","lasagna","pasta bolognese","steak and fries","salad","roasted chicken"]


    randomFood xs = do
              if (length xs - 1 ) > 0 then 
                 [list] <- (fmap (xs!!) $ randomRIO (0, length xs -1))
                 else
                 putStrLn (show([list])

我在输入中得到解析错误&#39;&lt; - &#39;但我确定还有更多的问题:/还有一个问题,列表可能连续两天包含相同的菜肴,这不是我想要的,我想我可以删除重复,但这也将删除数量列表中的项目,我希望保持与列表中的数字相同。

任何人都知道我如何能够拯救这个?我一直在寻找一天,我找不到对我有用的东西,但那仅仅是因为我在错误的地方寻找。关于我如何能够做到这一点或者我可以在哪里找到信息的任何建议都将受到极大关注!

//问候

2 个答案:

答案 0 :(得分:5)

它不起作用的原因是您需要在do之后另一个 if...then。 (在then之后,您需要一个表达式,而不是pattern <- expression。)

randomFood :: String -> IO ()  -- type signature: take a String and do some IO.
randomFood xs = do
          if length xs > 1 then do
             [list] <- (fmap (xs!!) $ randomRIO (0, length xs -1))
             else
             putStrLn (show([list])

但是仍然没有编译,因为你实际上没有对你的列表做任何事情。 在每个do块的末尾,您需要一个表达式来返回。 我认为如果xs的长度太短,你仍打算打印一些东西,如果有多个可供选择,你可能打算打印所选的食物。

更好的是:

randomFood :: String -> IO () 
randomFood xs | length xs <= 1 = putStrLn $ show xs
randomFood xs | otherwise = do
             item <- (xs!!) <$> randomRIO (0, length xs -1)
             putStrLn $ show(item)

这种| boolean test =语法更适合基于输入的条件答案。

我将[list]更改为item,因为您是随机选择单个项目,而不是项目列表。 Haskell非常乐意让你放[list],因为其中包含一个字符的任何字符串都匹配[list]。 例如,"h" = [list] list='h',因为“h”是['h']的缩写。任何更长的字符串都会为您提供Pattern match failure。特别是,您指定的所有食物都有多个字符,因此使用此定义randomFood将无法正常工作! item将匹配您的randomRIO表达式返回的任何内容,因此没问题。

您导入<$>然后没有使用它,但它是一个不错的运算符,因此我已将fmap f iothing替换为f <$> iothing

我终于意识到我用短名单做错了;如果我randomFood ["lump of cheese"]我将获得["lump of cheese"],这与randomFood ["lump of cheese"]不一致,这会给我"lump of cheese"。 我认为我们应该将短列表与空列表分开,这使我们能够进行更多的模式匹配和更少的布尔值:

randomFood :: String -> IO () 
randomFood []        = putStrLn "--No food listed, sorry.--"
randomFood [oneitem] = putStrLn . show $ oneitem 
randomFood xs = do
         item <- (xs!!) <$> randomRIO (0, length xs -1)
         putStrLn . show $ item

这为randomFood提供了三种不同的定义,具体取决于输入的内容。

此处我还将putStrLn (show (item))替换为putStrLn . show $ item - 撰写函数showputStrLn并将其应用于$ {{1} }}

答案 1 :(得分:2)

几点需要注意:

  • 不要混用纯净和不纯的代码。
  • 尝试将库用于任务,而不是重复已编写的内容。

以下是使用random-fu库的代码

import Data.Random
import Control.Applicative

food :: [String]
food = ["meatballs and potoes","veggisoup","lasagna","pasta bolognese","steak and fries","salad","roasted chicken"]

randomFood :: [String] -> RVar (Maybe String)
randomFood [] = return Nothing
randomFood xs = Just <$> randomElement xs

main :: IO ()
main = (sample $ randomFood food) >>= print

这就像是从列表中随机选择一个元素。

> main 
Just "steak and fries"
> main 
Just "meatballs and potoes"

如果您只想输出上述列表的随机排列,可以使用shuffle之类的

main = (sample $ shuffle food) >>= print

示例

 > main 
 ["meatballs and potoes","lasagna","steak and fries","roasted chicken","salad","pasta bolognese","veggisoup"]
 > main 
 ["roasted chicken","veggisoup","pasta bolognese","lasagna","steak and fries","meatballs and potoes","salad"]