允许函数接受Haskell中的各种类型

时间:2018-08-31 06:59:23

标签: haskell

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或其他任何东西?

1 个答案:

答案 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只需要处理一种类型。