我最近看到的是帶來了一個簡單的例子,<*和*>光。
validate :: String -> Maybe String
validate s = if s=="" then Nothing else Just s
>validate "a" *> validate "b"
Just "b"
>validate "" *> validate "b"
Nothing
>validate "a" <* validate "b"
Just "a"
>validate "a" <* validate ""
Nothing
>validate "a" <* validate "b" <* validate "c"
Just "a"
>validate "a" *> validate "b" <* validate "c"
Just "b"
這表明效果很重要,即使它們產生的值并不重要。
我的問題是關于型別簽名。
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
- 這些型別簽名實際上暗示了上面顯示的行為嗎?
我可以看到人們如何推理“顯然我們有一個 Applicative - 所以這說明了一般的行為。對于 operator *>,因為我們扔掉了左值,這個函式可能具有的唯一可能的含義是左側會影響整個手術。”
在Maybe- 那么似乎是 -的情況下,行為是隱含的。對于Either,同樣的含義成立并且錯誤將在效果“失敗”上傳播。
注意我只能說上述內容,因為我現在知道實作是如何作業的,我的問題與第一次看到這樣的簽名的經驗豐富的函式式程式員有關。
我讀過一個型別簽名[a] -> b :: Int(可能不是真正的代碼),但暗示實作是串列的長度。
我還搜索了“從型別簽名中暗示實作”,發現人們已經/正在做這樣的事情 - 但一般來說是做不到的(呃 - 沒有那個新的 GitHub 東西:--)
所以也許我已經回答了我自己的問題,但希望得到任何其他答案或評論。我對 Haskell 還是個新手,經過多年來的一些錯誤開始,它終于開始陷入困境。我只是觸及了表面......
謝謝
uj5u.com熱心網友回復:
(*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a這些型別簽名實際上暗示了上面顯示的行為嗎?
當然不是。這兩個操作可以簡單地實作為
apR :: (Applicative f) => f a -> f b -> f b
apR a b = b
apL :: (Applicative f) => f a -> f b -> f a
apL a b = a
只是忽略對 的Applicative約束f。
并且以同樣的方式[a] -> Int并不意味著實作是length。也可以
foo :: [a] -> Int
foo _ = 42
但是在這兩種情況下,從推斷的型別與給定的簽名不同的意義上說,這些都不是“正確”的實作。
那么您的問題可能有點不同,例如,假設有一個具有匹配推斷型別的實作。它是否遵循我們的意圖?
答案似乎仍然是否定的。一方面,我們可以定義
apR2 :: (Applicative f) => f a -> f b -> f b
apR2 a b = pure (\a _ b -> b) <*> a <*> b <*> b
對于某些型別,例如您的示例,它不會產生任何影響。但總的來說,做兩次效果和只做一次是不同的。
另一個更有意義的“錯誤”實作(感謝Daniel Wagner的評論)是
apR2b :: (Applicative f) => f a -> f b -> f b
apR2b a b = pure (\b a -> b) <*> b <*> a
現在,即使您的示例也不總是有效,因為效果的順序是不同的——它b在a's之前“先做”。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/379194.html
上一篇:如何在具有IndependantScreens布局的所有顯示幕上切換作業區
下一篇:從資料型別列印串列
