本文档为《Practical Web Development with Haskell Master the Essential Skills to Build Fast and Scalable Web Applications》勘误文档
操作系统 mac 10.15.7
1.安装stack[P19]
我采用curl方式进行安装
2.IDE [P21]
书中采用Haskero。但是经过blog确认,此插件已经不在维护,我安装VsCode和Haskell(legacy).所以跳过`stack build intero`
这里因为要安装旧版本的ghc,需要在stack.yaml中,更新下resolver为`lts-14.21`,并且屏蔽掉其他已经打开的resolver,这样才能下载8.4.2 8.6.5的ghc,否则默认会下载8.10版本,后续的package安装会有点问题。
2.1 getZonedTime[P37]
getZonedTime存在于多个time相关package中,按照上面的添加了time-lens后,需要在repl中先引入包 import Data.Time.Lens
然后才能使用zt <- getZonedTime
3.Regular Expression[P38]
3.1 首先安装pcre,这里没有采用brew进行安装,直接使用裸装。步骤如下
http://www.pcre.org
curl --rempote-name https://ftp.pcre.org/pub/pcre/pcre-8.44.tar.gz
tar -xzvf pcre-8.44.tar.gz
./configure --prefix=/Users/brant/program/libs/pcre-8.44-bin
make
make install
sudo ln -s /Users/brant/program/libs/pcre-8.44-bin /usr/local/pcre
echo 'export PATH=/usr/local/pcre/bin:$PATH' >> ~/.bash_profile
source ~/.bash_profile
pcre-config --version
3.2 安装pkg-config,步骤如下(这里注意需要安装0.29.2版本。如果安装0.29版本则会在高版本的mac上出现编译错误)
curl --remote-name https://pkgconfig.freedesktop.org/releases/pkg-config-0.29.2.tar.gz
tar -zxvf pkg-config-0.29.2.tar.gz
LDFLAGS="-framework CoreFoundation -framework Carbon"
./configure --with-internal-glib
make
sudo make install
3.3这里安装完毕后,按道理应该可以自动引入pcre.h,但是在我的环境中是找不到的,所以我采用了一个折衷的办法
编译
stack. build --extra-iunclude-dirs=/usr/local/pcre/include
执行repl
stack repl --extra-iunclude-dirs=/usr/local/pcre/include
如此便可以正确执行书中的regual相关代码
4.Json[44]
需要注意,因为我们上面已经新建了项目和main.hs,所以大部分同学应该在这里已经切换到非repl中执行了。
书中的代码‘$(deriveJSON defaultOptions "User)’ 在.hs文件中要修改为
instance ToJSON User where
toJSON (User uId name hobbies) = object [ "id" .= uId , "name" .= name,"hobbies" .= hobbies ]
instance FromJSON User where
parseJSON = withObject "User" $ \v -> User <$> v .: "id" <*> v .: "name" <*> v .: "hobbies"
-- 上面和下面等价。注意没有$()
deriveJSON defaultOptions ''User
4.Exception[P48]
书中说因为ClassyPrelude自动引入了safe-exceptions.所以就自动获得了throw.但是我实际执行下来是没有自动引入的。如果非手动导入会获得如下错误
<interactive>:1:7: error:
Variable not in scope: throw :: MyException -> IO ()
解决办法肯定是自己手动导入
import Control.Exception.Safe (throw)
至此,相关代码如下
package.yaml
dependencies:
- base >= 4.7 && < 5
- classy-prelude
- time
- time-lens
- pcre-heavy
- aeson
- template-haskell
- text
- safe-exceptions
default-extensions:
- NoImplicitPrelude
- OverloadedStrings
- QuasiQuotes
- TemplateHaskell
- DeriveGeneric
- DeriveAnyClass
stack.yaml
# resolver: lts-3.5
# resolver: nightly-2015-09-21
# resolver: ghc-7.10.2
resolver: lts-14.21
Main.hs
module Main where
import ClassyPrelude
import Lib
import GHC.Generics
import Data.Aeson
import Language.Haskell.TH.Syntax (nameBase)
import Data.Aeson.TH
import Data.Aeson.TH (deriveJSON, defaultOptions)
import Control.Exception.Safe (throw)
data User = User{ userId :: Int, userName :: Text, userHobbies :: [Text] } deriving (Show, Generic)
-- instance ToJSON User where
-- toJSON (User uId name hobbies) = object [ "id" .= uId , "name" .= name,"hobbies" .= hobbies ]
-- instance FromJSON User where
-- parseJSON = withObject "User" $ \v -> User <$> v .: "id" <*> v .: "name" <*> v .: "hobbies"
-- deriveJSON defaultOptions ''User
let structName = nameBase ''User
lowercaseFirst (x:xs) = toLower [x] <> xs
lowercaseFirst xs = xs
options = defaultOptions{ fieldLabelModifier = lowercaseFirst . drop (length structName)
}
in deriveJSON options ''User
--- 如果想要替换生成的key格式,可以使用 camelTo2 替换 lowercaseFirst
-- camelTo2 :: Char -> String -> String
-- Here’s a usage example:
-- camelTo2 '_' 'CamelAPICase' == "camel_api_case"
-- camelTo2 '-' 'userHobbies' == "user-hobbies"
-- isBelow10 :: Int -> Bool
-- isBelow10 n = if n < 10 then True else (error "above 10!")
isBelow10E :: Int -> Either Text ()
isBelow10E n = if n < 10 then Right() else Left (error "above 10!")
run :: Int -> IO ()
run n = case isBelow10E n of
Left e -> do
putStrLn "some went wrong!"
putStrLn e
Right _ ->
putStrLn "All good!"
main :: IO ()
main = someFunc
data ServerException = ServerOnFireException | ServerNotPluggedInException deriving(Show)
instance Exception ServerException
data MyException = ThisException | ThatException deriving(Show)
instance Exception MyException
run1 :: IO () -> IO ()
run1 action = action
`catch` (\e -> putStrLn $ tshow (e::ServerException) )
`catch` (\e -> putStrLn $ tshow (e::MyException))
`catchAny` (\e -> putStrLn $ tshow e)