将值存储在数据结构Haskell中

rex*_*lia 3 haskell ghci

我试图在一些数据结构中存储随机生成的骰子值,但不知道在Haskell中如何准确地执行它.到目前为止,我只能生成随机整数,但我希望能够将它们与相应的颜色值进行比较并存储颜色(不能真正设想函数的外观).这是我的代码 -

module Main where

import System.IO
import System.Random
import Data.List

diceColor = [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]
diceRoll = []

rand :: Int -> [Int] -> IO ()
rand n rlst = do
       num <- randomRIO (1::Int, 6)
       if n == 0
        then printList rlst       -- here is where I need to do something to store the values
        else rand (n-1) (num:rlst)

printList x = putStrLn (show (sort x))

--matchColor x = doSomething()

main :: IO ()
main = do
    --hSetBuffering stdin LineBuffering
    putStrLn "roll, keep, score?"
    cmd <- getLine
    doYahtzee cmd
    --rand (read cmd) []

doYahtzee :: String -> IO ()
doYahtzee cmd = do
if cmd == "roll" 
    then do rand 5 []
        else putStrLn "Whatever"
Run Code Online (Sandbox Code Playgroud)

在此之后,我希望能够让用户保持相同的骰子(如积累点)并让他们选择重新掷骰子 - 我认为这可以通过遍历数据结构(具有骰子值)并将重复骰子计数为点并将它们存储在另一个数据结构中.如果用户选择重新滚动,则他必须能够再次调用随机并替换原始数据结构中的值.

我来自OOP背景,Haskell是我的新领域.非常感谢帮助.

Jed*_*dai 6

所以,有几个问题,让我们一个接一个:

第一:如何使用System.Random(这是一个缓慢的生成器,但对于您的应用程序,性能并不重要)的函数生成除整数之外的其他内容.有几种方法,你的列表,你必须编写一个函数intToColor:

intToColor :: Int -> String
intToColor n = head . filter (\p -> snd p == n) $ [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]
Run Code Online (Sandbox Code Playgroud)

不是很好.虽然你可以做得更好,如果你用(键,值)顺序编写对,因为有一点点支持Data.List中的"关联列表"与查找功能:

intToColor n = fromJust . lookup n $ [(1,"Black"),(2,"Green"),(3,"Purple"),(4,"Red"),(5,"White"),(6,"Yellow")]
Run Code Online (Sandbox Code Playgroud)

或者当然,你可以在列表中忘记这个Int键的业务从1到6,因为列表已经被Int索引:

intToColor n = ["Black","Green","Purple","Red","White","Yellow"] !! n
Run Code Online (Sandbox Code Playgroud)

(注意这个函数有点不同,因为intToColor 0现在是"黑色"而不是intToColor 1,但考虑到你的目标,这并不是很重要,如果真的让你震惊,你可以写"!!(n-1)"代替)

但是因为你的颜色不是字符串而且更像是符号,所以你应该创建一个颜色类型:

data Color = Black | Green | Purple | Red | White | Yellow deriving (Eq, Ord, Show, Read, Enum)
Run Code Online (Sandbox Code Playgroud)

所以现在Black是Color类型的值,你可以在你的程序中的任何地方使用它(如果你写Blak,GHC会抗议)并且由于自动推导的魔力,你可以比较Color值,或者显示它们,或者使用toEnum将Int转换为颜色!

所以现在你可以写:

randColorIO :: IO Color
randColorIO = do
   n <- randomRIO (0,5)
   return (toEnum n)
Run Code Online (Sandbox Code Playgroud)

其次,您希望在数据结构中存储骰子值(颜色),并提供保持相同抛出的选项.所以首先应该存储几次抛出的结果,给定最大同时抛出次数(5)和数据的复杂性,一个简单的列表很多,并且给出了在Haskell中处理列表的函数数量,这是一个不错的选择.

所以你想抛出几个骰子:

nThrows :: Int -> IO [Color]
nThrows 0 = return []
nThrows n = do
   c <- randColorIO
   rest <- nThrows (n-1)
   return (c : rest)
Run Code Online (Sandbox Code Playgroud)

这是一个很好的第一种方法,这就是你所做的,或多或少,除了你使用if而不是模式匹配,你有一个显式的累加器参数(你要去尾递归吗?),除了严格累加器(Int)之外并不是更好而不是列表).

当然,Haskell提升高阶函数而不是直接递归,所以让我们看看组合器,用Hoogle搜索"Int - > IO a - > IO [a]"给你:

replicateM :: Monad m => Int -> m a -> m [a]
Run Code Online (Sandbox Code Playgroud)

这正是你想要的:

nThrows n = replicateM n randColorIO
Run Code Online (Sandbox Code Playgroud)

(我不确定我是否会将其作为函数编写,因为我发现显式表达式更清晰,几乎一样短)

一旦你得到了抛出的结果,你应该检查哪些是相同的,我建议你看看排序,组,地图和长度来实现这个目标(将结果列表转换成相同结果的列表,而不是最多有效的数据结构,但在这个规模,最合适的选择).然后保持你几次获得的颜色只是使用过滤器的问题.

然后你应该写一些更多的函数来处理交互和评分:

type Score = Int
yahtzee :: IO Score
yahtzeeStep :: Int -> [[Color]] -> IO [[Color]] -- recursive
scoring :: [[Color]] -> Score
Run Code Online (Sandbox Code Playgroud)

因此,我建议保留并传输[[颜色]]以跟踪放在一边的内容.这应该足以满足您的需求.