[英]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
。 這使得類型檢查成功。
每當包含布局列表的語法類別結束時,也會插入一個右括號; 也就是說,如果在右大括號合法的位置遇到非法詞素,則插入右大括號。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.