簡體   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