0

I'm trying to grab a random item from a string list and save that into another string list but I can't get my code to work.

    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])

I'm getting parse error on input '<-' but I'm sure there are more issues then that. There is also the issue that the list may contain the same dishes two days in a row which is not what I want and I guess I can remove duplicates but that also would remove the number of items in the list which I want to stay the same as the number in the list.

Anyone have a good idea how I could solve this? I have been searching for a day now and I can't find something useful for me but that's just because I'm looking in the wrong places. Any suggestion on how I can do this or where I can find the info will be greatly appreciated!

4

2 回答 2

5

它不起作用的原因是 doif...then. (在 a 之后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 iothingf <$> 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- 组合函数show并将其putStrLn应用于.$item

于 2012-09-19T19:11:39.847 回答
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"

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

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"]
于 2012-09-19T22:27:39.597 回答