2017-07-31 51 views
0

所以我是Haskell的新手,可能會問一個非常愚蠢的問題。 我試圖讓下面的代碼運行:返回case in do塊

asdf :: Maybe a -> Maybe a 
asdf k = do 
    return $ case k of 
       Nothing -> Nothing 
       Just x -> Just x 

我知道,這基本上是fmap,只有與回報是不義的事。我真正想要做的是以下

vote :: PostId -> Bool -> Maybe (Int, Int) 
vote id v = do 
    p <- runSQL $ P.get id 
    return $ case p of 
    Nothing -> Nothing 
    Just p -> do 
       let uv = postUpvotes p 
       let dv = postDownvotes p 
       let nuv = if v then uv + 1 else uv 
       let ndv = if not v then dv + 1 else dv 
       runSQL $ update id [PostUpvotes =. nuv, PostDownvotes =. ndv] 
       (nuv, ndv) 

我想這有多個問題。我的第一個例子究竟出了什麼問題?對第二個問題的處理方式是完全錯誤的還是有什麼問題?你會如何寫它?

+2

'runSQL'的類型是什麼?我認爲它不是純粹的,所以你不能在返回'Maybe(Int,Int)'的函數中運行它。 – Lee

+0

它來自本教程:https://www.spock.li/tutorials/rest-api – lbrndnr

+1

除非您在'IO' monad中返回一個值,否則不能執行IO,可能類似於IO(Maybe(Int(Int,智力))'。 – chi

回答

2

您的第一個代碼示例不需要return

你知道return在Haskell中的含義嗎?它不像其他任何編程語言中的return。在大多數語言中,它是一個控制語句流程,它將控制權返回給調用函數並附帶一個值。在Haskell中,它只是一個具有誤導性名稱的函數。

在這種情況下,你應該說:

asdf k = 
    case k of 
      Nothing -> Nothing 
      Just x -> Just x 

在Haskell do符號用於與單子,像IO。令人困惑的事實是,Maybe實際上也是一個monad。事實上,它是最簡單的monad。當你需要在某種上下文中運行的函數的菊花鏈時,你只需要使用單子,這在這裏不是這種情況。

回到第二個例子,問題是runSQL必須與外部世界進行交互,所以對於某些類型a,它幾乎肯定會返回IO a類型的內容。在這種情況下,在外部環境中執行菊花鏈功能,因此使用monads是必要的。

return是一個函數,在這種情況下,有

return :: a -> IO a 

這真的應該被稱爲pure,因爲它需要一個純粹的價值,並在一元範圍內包裝起來的類型。 (當你到達Applicative Functors時,你會發現一個名爲pure的版本return)。

關於monad的一條規則是,一旦你處於monadic環境中,你就無法離開;您可以對上下文中的值執行純計算,但結果會保留在monadic上下文中。該上下文用「IO」等類型表示。所以在這種情況下,你的功能類型應該是

vote :: PostId -> Bool -> IO (Maybe (Int, Int)) 

但是,如果你嘗試,你會發現它仍然不起作用。 case的第一個分支是好的,因爲它返回Nothing。但是第二個分支有一個類型錯誤,因爲它在IO操作之後試圖返回(nuv, nvd)。您試圖分解return,但實際上您需要在第一個分支中輸入return Nothing,然後在第二個分支末尾輸入return $ Just (nuv, nvd)

順便說一句,你不需要爲每個值新的let。你可以說

let 
    foo = 1 
    bar = 2 
return (foo, bar) 
+0

我不買那也許是最簡單的monad。可以說,Reader是一樣簡單,但即使你不同意,Identity也顯得更簡單。 – amalloy

+2

另外''投票'功能需要更多的修復比你建議,因爲它試圖在第二個分支做一些IO。而不是'return $ case ...',它必須看起來更像'case p of {Nothing - > return Nothing;只要p - > do ... return(nuv,ndv)}'。 – amalloy

+0

@amalloy:你是對的。發佈更新。 –