haskell – 在Monad链中重复应用的抽象

Haskell wikibook有一个示例,显示了在尝试在整个数据库中查找不同的连接信息时如何链接查找命令,如下所示:

getTaxOwed :: String       -- their name
       -> Maybe Double -- the amount of tax they owe
getTaxOwed name = 
  lookup name phonebook >>=
    (\number -> lookup number governmentDatabase) >>=
      (\registration -> lookup registration taxDatabase)

并用符号重写:

getTaxOwed name = do
  number       <- lookup name phonebook
  registration <- lookup number governmentDatabase
  lookup registration taxDatabase

现在,每当我看到一个函数重复不止一次时,我会立即想办法对其重复的应用程序进行抽象,但是因为我还没有在实践中使用Monads,并且因为它们似乎已经处于相当高的水平在这种情况下,我不知道如何处理抽象.

有什么方法,如果有的话,编码器可以抽象出上面的常见模式,即在每一行中调用查找?

(旁白:这是“抽象结束”一词的适当背景吗?我觉得它抓住了我的意思,但我不确定,而且我想确保我正确地使用术语作为一个相对较新的编码器;我查看了其他帖子,澄清了它的用法和含义,但我仍然无法弄清楚这个特定的例子)

最佳答案 非常感谢Carsten获得
foldM的链接!感谢他们对这个答案的见解.

因此,如果我们使用foldM,我们可以编写一个函数,该函数重复执行通过依赖于每个先前结果的多个目录链接的查找.如果,由于使用monads,在任何时候查找都找不到目录中的当前密钥,它将终止,并返回Nothing:

lookupALot :: Eq a => a -> [(a,b)] -> Maybe b
lookupALot key directories = foldM lookup key directories

这有表格的输出

  foldM f k1 [d1, d2, ..., dm] -- k == key, d == directory
  ==
  do
    k2 <- f k1 d1
    k3 <- f k2 d2
    ...
    f km dm

这与结构完全相同

  do
    number       <- lookup name phonebook
    registration <- lookup number governmentDatabase
    lookup registration taxDatabase

因此,更简洁的getTaxOwed编写方式是:

getTaxOwed :: String -> Maybe Double
getTaxOwed name = foldM lookup name [phonebook, governmentDatabase, taxDatabase]

哪种方式让我感到震惊!该行代码将找到与某人姓名相关联的电话号码,然后检查政府数据库及其注册号码,最后从该注册中查找税务信息.但请注意,这只适用于[(a,b)]形式的数据,如lookupalot的类型所示.

点赞