Haskell 从 do 符号传递到 Applicative
Haskell Passing from do notation to Applicative
我正在尝试从 https://haskell-at-work.com/episodes/2018-01-19-domain-modelling-with-haskell-data-structures.html
中删除 Database.sh 文件中的 do 符号
但是我有一个错误,我不知道为什么。 (可能只是意味着我不知道 Haskell)
Haskell代码:
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)
数据库
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
[2 of 2] Compiling Database ( Database.hs, Database.o )
Database.hs:12:5: error: parse error on input `<$>'
|
12 | <$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
| ^^^
这是一个简单的缩进错误。
请记住,let <definitions> in <expr>
的语法允许有一个包含 多个 定义的块。 “多个事物的块”1 基本上始终是 Haskell 中缩进重要的上下文,并且规则始终是块中的每个“事物”都必须开始在同一列 ,如果它们跨越多行,则续行必须比块的对齐列缩进更多。
这意味着这很好:
something = let foo = 1
bar = 2
baz = 3
in foo + bar + baz
因为 f
、b
和 b
开始 let
块中的每个方程都在同一列中。这个也不错:
something = let
foo = 1
bar = 2
baz = 3
in foo + bar + baz
因为方程式仍然完全一致。他们排列的位置实际上比 let
关键字本身缩进 less 无关紧要,in
关键字更远也无关紧要缩进。
但这很糟糕:
getTransactions :: ProjectId -> IO [Transaction]
getTransactions _ = let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
in
pure rtn
因为 let
中的定义块以 rtn = []
开始 。第一个定义中的所有内容都必须比 rtn
中的 r
缩进得更远。要更正它,您需要类似的东西:
getTransactions :: ProjectId -> IO [Transaction]
getTransactions _ = let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
in
pure rtn
您将以下行缩进更多的地方。或者(为了避免过度缩进)做这样的事情:
getTransactions :: ProjectId -> IO [Transaction]
getTransactions _ =
let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
in
pure rtn
您可以通过多种方式做到这一点;您也可以将 getTransactions
中的 =
放在下一行,或者您可以将 let
留在上一行,只将 rtn = []
向下移动,等等。但是一次你开始定义块,你必须继续规则,即块中条目的一部分必须进一步缩进;你不能重置 mid-block.
1 do
块有多个语句,let
和where
块有多个定义,case
块有多个分支、模块有多个导入和定义(通常我们将它们对齐在缩进级别 0,但你不必这样做),等等
其他任何缩进不重要,纯粹是约定俗成和可读性的问题(if/then/else
,in
部分let/in
、守卫或函数定义的其他部分等)
我正在尝试从 https://haskell-at-work.com/episodes/2018-01-19-domain-modelling-with-haskell-data-structures.html
中删除 Database.sh 文件中的 do 符号但是我有一个错误,我不知道为什么。 (可能只是意味着我不知道 Haskell)
Haskell代码:
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)
数据库
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
[2 of 2] Compiling Database ( Database.hs, Database.o )
Database.hs:12:5: error: parse error on input `<$>'
|
12 | <$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
| ^^^
这是一个简单的缩进错误。
请记住,let <definitions> in <expr>
的语法允许有一个包含 多个 定义的块。 “多个事物的块”1 基本上始终是 Haskell 中缩进重要的上下文,并且规则始终是块中的每个“事物”都必须开始在同一列 ,如果它们跨越多行,则续行必须比块的对齐列缩进更多。
这意味着这很好:
something = let foo = 1
bar = 2
baz = 3
in foo + bar + baz
因为 f
、b
和 b
开始 let
块中的每个方程都在同一列中。这个也不错:
something = let
foo = 1
bar = 2
baz = 3
in foo + bar + baz
因为方程式仍然完全一致。他们排列的位置实际上比 let
关键字本身缩进 less 无关紧要,in
关键字更远也无关紧要缩进。
但这很糟糕:
getTransactions :: ProjectId -> IO [Transaction]
getTransactions _ = let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
in
pure rtn
因为 let
中的定义块以 rtn = []
开始 。第一个定义中的所有内容都必须比 rtn
中的 r
缩进得更远。要更正它,您需要类似的东西:
getTransactions :: ProjectId -> IO [Transaction]
getTransactions _ = let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
in
pure rtn
您将以下行缩进更多的地方。或者(为了避免过度缩进)做这样的事情:
getTransactions :: ProjectId -> IO [Transaction]
getTransactions _ =
let rtn = []
<$> (Sale . Money <$> getStdRandom (randomR (0, 4000)))
<*> (Purchase . Money <$> getStdRandom (randomR (0, 4000)))
in
pure rtn
您可以通过多种方式做到这一点;您也可以将 getTransactions
中的 =
放在下一行,或者您可以将 let
留在上一行,只将 rtn = []
向下移动,等等。但是一次你开始定义块,你必须继续规则,即块中条目的一部分必须进一步缩进;你不能重置 mid-block.
1 do
块有多个语句,let
和where
块有多个定义,case
块有多个分支、模块有多个导入和定义(通常我们将它们对齐在缩进级别 0,但你不必这样做),等等
其他任何缩进不重要,纯粹是约定俗成和可读性的问题(if/then/else
,in
部分let/in
、守卫或函数定义的其他部分等)