Haskell wikibook有一个例子展示了如何链接 lookup
尝试在整个数据库中查找不同连接信息时的命令,请参见此处:
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)
并改写为
do
符号:getTaxOwed name = do
number <- lookup name phonebook
registration <- lookup number governmentDatabase
lookup registration taxDatabase
现在,每当我看到一个函数重复不止一次时,我会立即尝试想办法抽象它的重复应用程序,但因为我还没有使用
Monads
在实践中还有很多,因为它们似乎已经处于相当高的抽象级别,我不知道在这种情况下如何处理。如果有的话,编码人员可以通过哪些方式抽象上述常见模式,即调用
lookup
在每一行?(顺便说一句:这是“抽象结束”一词的合适上下文吗?我觉得它捕获了我的意思,但我不确定,我想确保我作为一个相对较新的编码员适本地使用术语; 我查看了其他帖子,这些帖子阐明了它的用法和含义,但我仍然无法弄清楚这个特定的例子)
最佳答案
非常感谢 Carsten 提供的链接 foldM
!感谢他们对这个答案的洞察力。
所以,如果我们使用 foldM
,我们可以编写一个重复执行 lookup
的函数链接到依赖于每个先前结果的多个目录。如果,感谢使用 monads
, 在任何时候 lookup
找不到当前 key
在目录中,它将终止,并返回 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]
哪一种让我大吃一惊!该行代码将找到与某人的
name
相关联的电话号码。 ,然后检查 governmentDatabase
与他们的号码 registration
,最后从registration
中找到他们的税务信息.但请注意,这仅适用于 [(a,b)]
形式的数据。 ,如 lookupALot
的类型所示.
关于haskell - 在 Monad 链中对重复应用进行抽象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32163806/