簡體   English   中英

單聲道和不記數法

[英]Monads and do notation

如果我們有以下代碼:

import Control.Monad.State  

type Stack = [Int]

pop :: State Stack Int  
pop = state $ \(x:xs) -> (x,xs)  

push :: Int -> State Stack ()  
push a = state $ \xs -> ((),a:xs)  

stackManip :: State Stack Int  
stackManip = do  
    push 3  
    x <- pop  
    pop

與我們一起運行:

command: runState stackManip [1]  
result: (1,[])

“ Haskell”如何知道將“ x”的值賦予3? 那么,他怎么知道從州單子中取出3個而不是州(在這種情況下為堆棧)?

Maybe monad的相同問題:

do
 x <- Just 5 

這里只有一個值,但是Haskell如何知道將'5'取為'x'?

這歸結為>>=的定義。 你應該注意到, do ---這里使用的功能---只是薄語法糖調用>>=

do
   x <- pop
   pop
= pop >>= \ x -> pop

並且(忽略新類型包裝器) >>=State定義為:

a >>= f = \ s -> case a s of
    (x, s') -> f x s'

因此, f將結果作為第一個參數(名為x參數)並將狀態作為其(靜默)第二個參數( pop定義內的參數)獲取結果。

請注意,您無法以其他方式定義>>=

a >>= f = \ s -> case a s of
    (x, s') -> f s' x

因為那樣它就會有類型

State s a -> (s -> State a b) -> State a b

這通過類型分配了錯誤的類型變量。 (這就是Haskell偏愛單字母類型變量的原因:相同的類型變量比其實際含義要重要得多)。

x <- pop大致從pop獲取x pop操作返回3 ,而不是整個堆棧。 您還可以從以下類型中看到:

pop :: State Stack Int   -- returns Int, keeps Stack as state

相比之下, get具有以下類型:

get :: State Stack Stack  -- returns Stack, keeps Stack as state

因此, x <- get將獲得整個狀態堆棧。

如果您需要更詳細的說明,建議您查看如何為State Stack monad定義(>>=) 然后,將其刪除后,將其應用於您的代碼

push 3  >>= ( \ _ ->
pop     >>= ( \ x ->
pop ))

經過許多簡化之后,您應該達到類似以下的目的:

State (\stack0 ->  let (_, stack1) = unState (push 3) stack0
                       (x, stack2) = unState pop      stack1
                       (_, stack3) = unState pop      stack2
                       in stack3 )

然后,您可以根據需要內聯pushpop並繼續進行簡化。 但是您已經在上面看到了x的來源。

暫無
暫無

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

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