Haskell 获取 IO 列表元素
Haskell getting IO list elements
我有一个由元组组成的类型同义词 Card。我还有一个类型同义词 Deck 定义为 [Card](卡片列表)。
由于文件读取,我被 IO monad 卡住了,具体来说,我有一个 IO Deck 类型的对象。我将如何检索卡片列表的各个元素?由于 IO monad,该类型似乎不再是列表,所以我不能使用 !!运算符。
假设这些是您的类型:
type Card = (Int, Int)
type Deck = [Card]
someDeck :: IO Deck
someDeck = undefined -- Some sample IO Deck which you have (from reading file etc.)
然后你可以使用 monad do-notation 来访问 Deck
:
{-# LANGUAGE ScopedTypeVariables #-}
testFun :: IO Deck
testFun = do
(x :: Deck) <- someDeck
-- Operate here on the x value
return []
<-
将从 IO Deck
中提取 Deck
。请注意,此处 x
的类型为 Deck
。您可以在 let 表达式中对其应用纯函数。另一种方法是使用 fmap
,它更简单但不太直观,除非您已经习惯了。
您应该将用于加载牌组的代码与游戏本身分开,然后在某处将两者组合在一起。模板可以是:
import System.Environment (getArgs)
solve :: Deck -> Deck
solve deck = -- do something here
loadDeckFromFile :: FilePath -> IO Deck
loadDeckFromFile fp = -- load deck code here
main :: IO ()
main = do
deckFile <- fmap head getArgs
deck <- loadDeckFromFile deckFile
let solvedDeck = solve deck
putStrLn "Starting deck:"
print deck
putStrLn "\nSolved deck:"
print solvedDeck
你的主要问题是你根本不知道如何操作 monad,所以这里有一些提示:
Monads 有一些函数可以让它们被操纵。这些源于 monad 类型类中定义的基本类型,return
和 >>=
(又名 'bind')。
return
允许构造一个 monad,而 >>=
首先接受一个 monad,然后是一个构造 monad 的函数,并将该函数应用于给定的值。这是您在您的案例中使用它的方式:
-- Imagine your list to be here:
ioList :: IO [Int]
ioList = return [1,2,3,4,5]
-- If we were to print the second element...
main = ioList >>= ( \a -> return (a !! 1) ) >>= print
-- We could write this in do-notation, syntactic sugar for the above:
main = do
list <- ioList
print (list !! 1)
也可以使用 Control.Monad
中的函数 liftM
,它接受一个函数并将其应用于 monad,如下所示:
import Control.Monad
main = print (liftM (!! 1) ioList)
您可以找到更多操作 monad 的方法,以及对所涉及的各种类型签名的解释,以及 do-notation 和其他 here。
我有一个由元组组成的类型同义词 Card。我还有一个类型同义词 Deck 定义为 [Card](卡片列表)。
由于文件读取,我被 IO monad 卡住了,具体来说,我有一个 IO Deck 类型的对象。我将如何检索卡片列表的各个元素?由于 IO monad,该类型似乎不再是列表,所以我不能使用 !!运算符。
假设这些是您的类型:
type Card = (Int, Int)
type Deck = [Card]
someDeck :: IO Deck
someDeck = undefined -- Some sample IO Deck which you have (from reading file etc.)
然后你可以使用 monad do-notation 来访问 Deck
:
{-# LANGUAGE ScopedTypeVariables #-}
testFun :: IO Deck
testFun = do
(x :: Deck) <- someDeck
-- Operate here on the x value
return []
<-
将从 IO Deck
中提取 Deck
。请注意,此处 x
的类型为 Deck
。您可以在 let 表达式中对其应用纯函数。另一种方法是使用 fmap
,它更简单但不太直观,除非您已经习惯了。
您应该将用于加载牌组的代码与游戏本身分开,然后在某处将两者组合在一起。模板可以是:
import System.Environment (getArgs)
solve :: Deck -> Deck
solve deck = -- do something here
loadDeckFromFile :: FilePath -> IO Deck
loadDeckFromFile fp = -- load deck code here
main :: IO ()
main = do
deckFile <- fmap head getArgs
deck <- loadDeckFromFile deckFile
let solvedDeck = solve deck
putStrLn "Starting deck:"
print deck
putStrLn "\nSolved deck:"
print solvedDeck
你的主要问题是你根本不知道如何操作 monad,所以这里有一些提示:
Monads 有一些函数可以让它们被操纵。这些源于 monad 类型类中定义的基本类型,return
和 >>=
(又名 'bind')。
return
允许构造一个 monad,而 >>=
首先接受一个 monad,然后是一个构造 monad 的函数,并将该函数应用于给定的值。这是您在您的案例中使用它的方式:
-- Imagine your list to be here:
ioList :: IO [Int]
ioList = return [1,2,3,4,5]
-- If we were to print the second element...
main = ioList >>= ( \a -> return (a !! 1) ) >>= print
-- We could write this in do-notation, syntactic sugar for the above:
main = do
list <- ioList
print (list !! 1)
也可以使用 Control.Monad
中的函数 liftM
,它接受一个函数并将其应用于 monad,如下所示:
import Control.Monad
main = print (liftM (!! 1) ioList)
您可以找到更多操作 monad 的方法,以及对所涉及的各种类型签名的解释,以及 do-notation 和其他 here。