I am trying to strip away do notation in the Database.sh file from https://haskell-at-work.com/episodes/2018-01-19-domain-modelling-with-haskell-data-structures.html
But I am having an Error and I have no Idea why. (Probably just means I don't know about Haskell)
This is a continuation of Haskell Passing from do notation to Applicative
Haskell Code:
Project.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)
Database
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
Error
After running 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 = []
| ^^
CodePudding user response:
In
let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
It looks like you are trying to make a list of the results of those two actions? That doesn't work because the first argument of (<$>)
has to be a function, and []
is not a function (among other reasons). If you want to keep this notation, you should replace with a pairing function:
pair x y = [x, y]
then
let rtn = pair <$> ...
But really I think the appropriate combinator here is sequenceA
sequenceA :: (Applicative f) => [f a] -> f [a]
which takes a list of actions, and gives back an action returning a list of results.
So:
let rtn = sequenceA [Sale . Money <$> getStdRandom (randomR (0, 4000)),
Purchase . Money <$> getStdRandom (randomR (0, 4000))]
Oh, and there should not be a pure
to return this. It's already of the correct type, it does not need to be lifted into IO
.
Incidentally, getStdRandom . randomR
is also known as randomRIO
.