繁体   English   中英

当非 monadic 值变成 monadic 值时,正确重构 Haskell 代码

[英]Proper refactor of a Haskell code when a non-monadic value becomes a monadic value

假设我有这个示例代码:

h = 2
add = \x y -> (x + y)
addH = add h

main = return (fmap addH [1,2])

运行它评估为 [3,4]


现在,假设 h 没有设置为“2”,而是“Just 2”。

问题,第 1 部分:

那么,最终仍然返回 [3,4] 的正确重构是什么?

问题,第 2 部分:

熟练的 Haskell 开发人员是否更愿意将返回值更改为 [Just 3, Just 4]

例如使用这样的重构:

h = Just 2
add = \x y -> (x + y)
addH = liftM2(add) h . pure         --isn't there a better syntax for that?

main = return (fmap addH [1,2])

更一般地说,在现有的代码库中,当曾经返回 'Num t => [t]' 的函数现在必须返回 'Num t => [Maybe t]' 时,如何最大限度地减少重构影响?

我想指出,在你的原始代码中, []Maybe是多余的,仔细检查这两个函子的含义会导致一个有趣的讨论。 [] (list) 表示成功或失败,与Maybe意义相同,主要区别在于[]可以表示 0 个或多个值,而Maybe仅限于 0 或 1 个值。

这导致了关于Just in Just 2含义的另一个考虑。 2包裹在JustNothing意思,而NothingNothing意思? 为了更进一步,您可以选择以下五种不同的结果,每种结果都有不同的含义:

  1. Just [3, 4] :有一个处理多个值的整体计算,并且成功了。
  2. Nothing :可能有一个整体的价值,但没有。
  3. [3, 4] :有一批计算,这些是出来的值。
  4. [] :可能有多个值,但没有。
  5. [Just 3, Just 4] :有一批计算,每个计算都可能失败,但都成功了。

情况 1 :如果h代表一个整体值,并且是此计算链中唯一的故障点,则选项 1 和选项 2 似乎是一个合理的选择。 以下代码实现了这一点:

import Control.Applicative (LiftA2)
h = Just 2
add = (+)
addH = LiftA2 add h . pure
-- Returns Just [3,4] or Nothing
mainFunc = traverse addH [1,2]

情况 2 :如果add表示的函数可能会根据其参数而失败(例如,考虑函数hDivBy ,它会在每个 0 处失败),那么选项 3 和 4 似乎是一个不错的选择。

import Data.Maybe (mapMaybe)
hDivBy = \x -> (`div` x) <$> h
--Returns [1]
mainFunc = mapMaybe hDivBy [0, 2]

案例 3 :如果您想跟踪元素索引,那么选项 5 将为您提供:

--Returns [Nothing, Just 2]
mainFunc = fmap hDivBy [0,2]

请注意,此代码将所有内容保留在Applicative领域,使其更通用, 以及其他优点

要获得Fyodor Soikin结果,您可以尝试以下方法。

h = Just 2
add = \x y -> x + y
addH arr = pure fmap <*> (add <$> h) <*> pure arr

main = return $ addH [1, 2]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM