【问题标题】:Haskell getting IO list elementsHaskell 获取 IO 列表元素
【发布时间】:2015-02-28 06:33:37
【问题描述】:

我有一个由元组组成的类型同义词 Card。我还有一个类型同义词 Deck 定义为 [Card](卡片列表)。

由于文件读取,我被 IO monad 卡住了,具体来说,我有一个类型为 IO Deck 的对象。我将如何检索卡片列表的各个元素?由于 IO monad,类型似乎不再是列表,所以我不能使用 !!运算符。

【问题讨论】:

标签: list haskell io element monads


【解决方案1】:

您的主要问题是您根本不知道如何操作 monad,所以这里有一些提示:

Monad 有一些函数可以让它们被操纵。这些源于 monad 类型类中定义的基本类型,return>>=(又名“绑定”)。

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

【讨论】:

  • 我认为说“操纵单子”有点误导。 monad 是一劳永逸的东西,一个数学概念,你不能操纵它!你也不能操纵monadic values(又名actions;我想这就是你的意思)。像&gt;&gt;= 这样的运算符不会操纵而是组合这样的动作。
  • @leftaroundabout 确实如此,但在初学者水平上,以一种更基本的方式来考虑它可能是一个更好的主意,而不是组合动作。我当然发现以前一种方式思考更容易。
  • 如何将其应用于过滤?我有 filter 谓词 iolist,其中 iolist 是 IO Deck,谓词是 Card -> Bool。我尝试使用liftM,但没有成功。
  • @wolx 如果你这样做liftM (filter predicate) ioList,它应该可以正常工作 - 它对我来说就像这样。您的问题可能是您没有像我在括号中那样将函数括起来。您还需要导入Control.MonadliftM 的来源。
  • 没关系,我使用 fmap 管理。 :) fmap (filter predicate) iolist Edit:你打败了我。再次感谢您!
【解决方案2】:

您应该将用于加载套牌的代码与游戏本身分开,然后在某处将两者结合在一起。模板可以是:

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

【讨论】:

    【解决方案3】:

    假设这些是你的类型:

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

    &lt;- 将从IO Deck 中提取Deck。请注意,x 在此处的类型为 Deck。您可以在 let 表达式中应用纯函数。另一种方法是使用fmap,它更简单但不太直观,除非你习惯了它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-07
      • 2013-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多