代码之家  ›  专栏  ›  技术社区  ›  Delfin

Haskell从do符号到Applicative符号的传递(第2部分)

  •  2
  • Delfin  · 技术社区  · 3 年前

    我试图去掉数据库中的do符号。sh文件来自 https://haskell-at-work.com/episodes/2018-01-19-domain-modelling-with-haskell-data-structures.html

    但我有一个错误,我不知道为什么。(可能只是意味着我不知道哈斯克尔的事)

    这是本书的延续 Haskell Passing from do notation to Applicative

    哈斯克尔代码:

    项目hs
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    module Project where
    
    import           Data.Text (Text)
    
    newtype Money = Money
      { unMoney :: Double
      } deriving (Show, Eq, Num)
    
    newtype ProjectId = ProjectId
      { unProjectId :: Int
      } deriving (Show, Eq, Num)
    
    data Project
      = Project ProjectId
                Text
      | ProjectGroup Text
                     [Project]
      deriving (Show, Eq)
    
    data Budget = Budget
      { budgetIncome      :: Money
      , budgetExpenditure :: Money
      } deriving (Show, Eq)
    
    data Transaction
      = Sale Money
      | Purchase Money
      deriving (Eq, Show)
    
    
    数据库
    import           System.Random (getStdRandom, randomR)
    
    import Project
    
    getBudget :: ProjectId -> IO Budget
    getBudget _ = Budget
        <$> (Money <$> getStdRandom (randomR (0, 10000)))
        <*> (Money <$> getStdRandom (randomR (0, 10000)))
    
    getTransactions :: ProjectId -> IO [Transaction]
    getTransactions _ = 
      let rtn = []
           <$>  (Sale . Money <$> getStdRandom (randomR (0, 4000)))
           <*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
      in
        pure rtn
    

    错误

    跑步后 stack ghc Database.hs --package random

    
    Database.hs:12:13: error:
        * Couldn't match expected type: Transaction -> Transaction -> b
                      with actual type: [a0]
        * In the first argument of `(<$>)', namely `[]'
          In the first argument of `(<*>)', namely
            `[] <$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))'
          In the expression:
            [] <$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
              <*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
        * Relevant bindings include rtn :: f b (bound at Database.hs:12:7)
       |
    12 |   let rtn = []
       |             ^^
    
    
    1 回复  |  直到 3 年前
        1
  •  2
  •   luqui    3 年前

    在里面

    let rtn = []
         <$>  (Sale . Money <$> getStdRandom (randomR (0, 4000)))
         <*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
    

    看起来你想把这两个动作的结果列出来?这是行不通的,因为 (<$>) 必须是一个函数,而且 [] 不是一种功能(除其他原因外)。如果要保留此符号,应替换为配对函数:

    pair x y = [x, y]
    

    然后

    let rtn = pair <$> ...
    

    但实际上我认为合适的组合是 sequenceA

    sequenceA :: (Applicative f) => [f a] -> f [a]
    

    它获取一个操作列表,并返回一个返回结果列表的操作。

    所以:

    let rtn = sequenceA [Sale . Money <$> getStdRandom (randomR (0, 4000)),
                         Purchase . Money <$> getStdRandom (randomR (0, 4000))]
    

    哦,不应该有 pure 还这个。它已经是正确的类型,不需要提升到 IO .

    顺便提一句 getStdRandom . randomR 也被称为 randomRIO .