簡體   English   中英

Haskell 做符號邊緣情況無法類型檢查

[英]Haskell do notation edge case fails to typecheck

我試圖理解do符號的規則。

這是一些類型檢查的代碼:

fff :: Maybe Int
fff = do
    _ <- pure $ Just 100
    (+10)
    <$> Just 50

這基本上是fff = (+10) <$> Just 50 我認為上面的內容不會進行類型檢查 - 因為肯定每一行都應該在Maybe的上下文中,而(+10)不是。

為什么要進行上述類型檢查? 下面是上面的一個更簡單的例子:

fff :: Int -> Maybe Int
fff i = do
    (+10)
    <$> Just i

為什么以上被認為是有效的語法? 這不是“脫糖”到:

fff i = ((+10) >>= (\i -> fmap (Just i))) i

這確實在 ghci 中給出了類型檢查錯誤。


下面是一個按照與上面類似的縮進進行類型檢查的示例:

x :: Maybe Int
x = do
  _ <- Just 1
  undefined
  <$> Just 5

(感謝@cvlad 來自 FP slack chat 上面的例子)

fff :: Int -> Maybe Int
fff i = do
    (+10)
    <$> Just i

為什么以上被認為是有效的語法?

因為它被解析為

fff i = do {        -- do { A } is just
    (+10) }         --      A
    <$> Just i

這相當於

fff i =
    (+10) 
    <$> Just i

因為<$> Just i本身是一個無效的表達式(所以fff i = ((+10) >>= (\\i -> fmap (Just i))) i是不正確的翻譯),並且這界定了根據@chi 的回答中引用的規則, do塊。

事實上,它的類型被推斷為

fff :: Num b => b -> Maybe b

如果在最后一行的<$>之前添加一個空格,則第二個示例有效。 沒有空格,它再次被解析為

inputTest :: FormInput -> IO (Either [String] (Int, Int))
inputTest fi = do {
    allErrors' <- undefined :: IO [String]
    undefined }
    <$> ((liftM2 ) (,) <$> undefined <*> undefined) fi

因為<$> ...本身就是無效的表達式。 事實上,當我添加顯式分隔符時,

inputTest2 :: String -> IO (Either [String] (Int, Int))
inputTest2 fi = do {
    allErrors2 <- undefined :: IO [String] ;
    undefined  }
    <$> ((liftM2 ) (,) <$> undefined <*> undefined) fi

我在 TIO 上收到完全相同的錯誤消息(必須在那里使用String而不是您的類型)。

由於第一個undefined :: IO [String] ,整個 do 塊都有一些IO t類型,我們不能將它映射任何東西上。

始終添加所有顯式分隔符(除了練習良好的縮進風格),以避免這種奇怪的語法脆弱性。


你的新例子是

x :: Maybe Int
x = do          -- {     this is
  _ <- Just 1   -- ;       how it is
  undefined     -- }         parsed
  <$> Just 5

代碼改變了,但答案是一樣的。 <$>之前do塊是Maybe t (因為Just 1 ),我們不能 fmap that

同樣,將最后一行縮進一些,它會編譯,因為undefined <$> Just 5現在undefined <$> Just 5將被解析為一個表達式。

這是一種奇怪的互動。

我開始將測試用例簡化為這個,它運行良好。

> x = do succ ; <$> Just 1
> x
Just 2

相比之下,這不會解析:

> y = do { succ ; <$> Just 1 }      
error: parse error

但是,這解析:

> z = do { succ } <$> Just 1      
> z
Just 2

所以,這就是我認為正在發生的事情。 由於標記<$>永遠無法啟動表達式,因此 parse 暫時失敗。 do解析器規則本質上是一個最大咀嚼規則:在失敗時,添加一個隱含的}並重試。

因此,上面的x被解析為z 由於succ是一元值(OP問題中的第(+10)(+10) ,因此它可以出現在do 這使得類型檢查成功。

引用Haskell 報告 2.7

每當包含布局列表的語法類別結束時,也會插入一個右括號; 也就是說,如果在右大括號合法的位置遇到非法詞素,則插入右大括號。

暫無
暫無

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

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