UPD 我意识到这个问题并不完全正确,因为我试图从Erlang的经验中做一些对我来说很普遍的事情。如答案所解释,应缩小我的函数的类型,而不是采用“扩展”的类型来采用它们...
(这是尝试学习/评估Haskell时的测试项目)
这是预期的基本Web端点的一部分,返回单个实体(对于具有ID的请求)或全部列表(对于不具有ID的请求):
此天真代码有效:
doGet req resp =
let path = map T.unpack (pathInfo req)
in case path of
["molecule"] -> makeResponse resp doGetAllMolecules
["molecule", strId] -> makeResponse resp $ doGetMolecule strId
makeResponse resp f = do
res <- f
resp $ responseLBS status200 [] (LC8.pack $ (show res) ++ "\n")
doGetMolecule :: String -> IO (Maybe Db.Molecule)
doGetMolecule strId = Db.fetchMolecule (read strId :: Int)
doGetAllMolecules :: IO [Db.Molecule]
doGetAllMolecules = Db.fetchAllMolecules
现在,我希望它在找不到实体时返回status404
:
makeResponse resp f = do
res <- f
let s = case res of
Nothing -> status404
_ -> status200
resp $ responseLBS s [] (LC8.pack $ (show res) ++ "\n")
这会导致错误:
• Couldn't match type ‘[Db.Molecule]’ with ‘Maybe a0’
Expected type: IO (Maybe a0)
Actual type: IO [Db.Molecule]
• In the second argument of ‘makeResponse’, namely
‘doGetAllMolecules’
In the expression: makeResponse resp doGetAllMolecules
In a case alternative:
["molecule"] -> makeResponse resp doGetAllMolecules
那么如何“匹配类型”值,使它可以是Maybe或其他任何东西?
答案 0 :(得分:4)
我会这样:
doGetMolecule :: String -> IO (Maybe [Db.Molecule])
doGetMolecule strId = fmap (:[]) <$> Db.fetchMolecule (read strId :: Int)
doGetAllMolecules :: IO (Maybe [Db.Molecule])
doGetAllMolecules = Just <$> Db.fetchAllMolecules
现在它们具有相同的类型:两者都有机会返回分子列表,因此doGet
只需要处理一种类型。