如何跨函数调用链传递值

时间:2019-02-18 02:44:35

标签: haskell

假设我具有以下数据结构和功能:

data Settings = Settings { dbName :: String } deriving Show

-- username to user id lookup
getUserId :: Settings -> String -> Int
getUserId settings username = 1

-- checks permission for a given user id
hasPermission :: Settings -> Int -> Bool
hasPermission settings userId = True

我希望能够将getUserIdhasPermission与某些语法糖链接在一起,而不必在链接函数调用时携带Settings的实例。像这样:

main = do
  let _permission = Settings{dbName="prod"} >>= getUserId "bob" >> hasPermission
  print _permission

这(显然)不起作用。

对此有任何适合的模式吗?

2 个答案:

答案 0 :(得分:1)

我认为,解决此类问题的最简单方法是使用部分应用,如下所示:

main = do
  let settings = Settings { dbName="prod" }
  let getUserId' = getUserId settings
  let hasPermission' = hasPermission settings
  let _permission = hasPermission' $ getUserId' "bob"
  print _permission

但是,如果您将'common'参数放在最后,则还可以使用内置的 reader monad 实例:

main :: IO ()
main = do
  let getPermission = (flip getUserId) "bob" >>= (flip hasPermission)
  print $ getPermission $ Settings { dbName="prod" }

此处getPermission是类型为Settings -> Bool的局部函数。通常,我认为第一个选项(部分应用程序)更简单易懂。

答案 1 :(得分:0)

有一个名为implicit parameters的功能,最近有点过时了,但是我相信它仍然受支持,为此提供了一个很好的解决方案。

{-# LANGUAGE ImplicitParams #-}

data Settings = Settings { dbName :: String } deriving Show

getUserId :: (?settings :: Settings) => String -> Int
getUserId username = 1

hasPermission :: (?settings :: Settings) => Int -> Bool
hasPermission userId = True

main = do
    let ?settings = Settings { dbName = "prod" }
    print $ hasPermission (getUserId "bob")

另请参见implicit configurations论文,该论文对这个问题进行了相当深入的探讨,并提供了相应的库reflection