我正试图从https://haskell-at-work.com/episodes/2018-01-19-domain-modelling-with-haskell-data-structures.html
但是我有一个错误,我不知道为什么。(可能只是意味着我不知道哈斯克尔(
Haskell代码:
项目.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
因为开始let
块中的每个方程的f
、b
和b
排在同一列。这也很好:
something = let
foo = 1
bar = 2
baz = 3
in foo + bar + baz
因为方程仍然是完全一致的。它们排列的位置实际上比let
关键字本身缩进更少并不重要,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 = []
下移,等等。但一旦你开始定义块,你就必须继续规则,即块中条目的所有部分都必须进一步缩进;你不能重置回中间块。
1do
块有多条语句,let
和where
块有多个定义,case
块有多个子分支,模块有多个导入和定义(通常我们在缩进级别0对齐这些,但您不必这样做(,等等。
其他任何东西的缩进都不重要,而且纯粹是惯例和可读性的问题(if/then/else
、let/in
的in
部分、函数定义的保护或其他部分等(