簡體   English   中英

Haskell - 混合有狀態計算

[英]Haskell - Mixed stateful computations

鑒於以下結構:

data Computation a = Pure (CState -> (a, CState))
                   | Action (CState -> IO (a, CState))

(CState是一種用於保持國家的結構,但現在並不是很感興趣。)
現在我想讓它成為Monad的一個實例,它基本上只是一個狀態monad,可以很容易地用StateT實現。 它唯一的補充是,我想跟蹤,無論結果Computation是Pure還是Action,我希望能夠在執行Action之前檢查Computation是否包含任何Action ,所以IO in Action沒有被執行)。

還應該指出, Computation有兩個構造函數並不重要。 我剛開始用這些構造函數實現它。

判斷a >> b是否為純的規則很簡單: a >> bPure如果ab都是Pure ,否則它就是一個動作。

現在我開始實現Monad實例:

instance Monad Computation where
    return x = Pure $ \s -> (x, s)
    (Action c) >>= f = Action . runStateT $
                         (StateT $ unpackAction oldComp) >>= (StateT . unpackAction . f)
    p@(Pure c) >>= f
      | givesPure f = Pure . runState $
                        state oldF >>= (state . unpackPure . f)
      | otherwise = liftComp p >>= f -- Just lift the first argument and recurse, to make an action

-- Helper functions used above:
unpackAction :: Computation a -> (CState -> IO (a, CState))
unpackAction (Pure c) = return . c 
unpackAction (Action c) = c

-- Make an Action out of a Pure
liftComp :: Computation a -> Computation a
liftComp (Pure c) = Action $ return . c
liftComp a@(Action _) = a

所以唯一缺少的部分是givesPure函數,我不確定它是否甚至可以實現它。 我曾經有過這樣的實現:

givesPure :: (a -> Computation b) -> Bool
givesPure f = isPure $ f undefined -- I actually used error with a custom message instead of undefined, but that shouldn't matter

isPure :: Computation a -> Bool
isPure (Pure _) = True
isPure (Action _) = False

這有效,但假設我綁定的函數總是返回具有相同純度的Computation,無論其輸入是什么。 這個假設合理地出現在我身上,因為計算的純度應該清楚地說明並且不依賴於某些計算,直到我注意到以下形式的函數不能用於這個假設:

baz :: Int -> Computation b
baz x = if x > 5 
        then foo
        else bar
-- foo and bar both have the type Computation b

所以在我看來,就像它不可能這樣做,因為我需要當前的狀態來應用第一個Computation,以獲得函數的正確輸入以獲得第二個Computation並測試它是否是純的。

有沒有人看到這個解決方案或有證據表明它是不可能的?

您遇到過monadic計算不適合靜態分析的事實,因為效果(在您的情況下,效果的存在)取決於計算本身期間獲得的值。 如果不運行計算,則無法預測它們。

當你從ApplicativeArrow再到Monad ,你獲得了“力量”(你可以表達更多的計算),但卻失去了靜態分析的能力。

對於Applicative ,有一個現成的Lift數據類型,它為現有的applicative添加了一個純計算。 但它沒有Monad實例。

您可以嘗試使用GADT:

data Pure
data Action

data Computation t a where
   Pure :: (CState -> (a, CState))      -> Computation t a
   Action :: (CState -> IO (a, CState)) -> Computation Action a

這個想法是值x :: Computation Action a可以做IO(但也可以是純粹的),而值y :: Computation Pure a不能做IO。

例如,

liftComp :: Computation t a -> Computation Action a
liftComp (Pure c) = Pure c
liftComp x@(Action c) = x

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM