当我正在学习Haskell时,我意识到do
符号只是合成糖:
a = do x <- [3..4]
[1..2]
return (x, 42)
Run Code Online (Sandbox Code Playgroud)
翻译成
a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))
Run Code Online (Sandbox Code Playgroud)
我意识到我可能会使用do-notation,但我想了解翻译中发生的事情.纯粹出于教学原因,ghc/ghci有没有办法给我一个用do-notation编写的相当复杂的monad的相应绑定语句?
编辑.事实证明#haskell上的lambdabot可以做到这一点:
<Guest61347> @undo do x <- [3..4] ; [1..2] ; return (x, 42)
<lambdabot> [3 .. 4] >>= \ x -> [1 .. 2] >> return (x, 42)
Run Code Online (Sandbox Code Playgroud)
这是Undo插件的源代码.
为什么允许使用此功能:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
Run Code Online (Sandbox Code Playgroud)
这不是:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
Run Code Online (Sandbox Code Playgroud)
编译错误:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
Run Code Online (Sandbox Code Playgroud)
我明白为什么功能 2 不应该工作,但为什么功能 1 工作呢?
为什么这会起作用:
-- function 3
myfunc = do
x <- getLine
return (show x)
Run Code Online (Sandbox Code Playgroud)
我知道它IO String
然后返回,但是为什么函数 1 也没有被迫这样做?
我对(>>=)
Haskell中绑定函数的定义有一些疑问.
因为Haskell是一种纯语言,所以我们可以使用Monad来处理带副作用的操作.我认为这个策略是有点像把所有的动作可能会引起副作用另一个世界,我们可以从"纯"哈斯克尔世界虽然控制它们do
或>>=
.
所以当我看一下>>=
函数的 定义时
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)
它需要一个(a -> m b)
函数,因此m a
前一个动作的结果可以"解包"到非monadic a
中>>=
.然后,该功能(a -> m b)
需要a
作为其输入和返回另一个单子m b
作为其结果.通过绑定功能,我可以对monadic进行操作,而不会给纯haskell代码带来任何副作用.
我的问题是为什么我们使用一个(a -> m b)
函数?在我看来,一个m a -> m b
函数也可以做到这一点.有什么理由,还是因为它的设计是这样的?
编辑
从意见,我知道这是很难提取a
的m a
.但是,我认为我可以将monadic m a
视为a
副作用.
是否有可能假设函数m a -> m b …
阅读这篇博文 – https://www.haskellforall.com/2021/05/the-trick-to-avoid-deeply-nested-error.html – 我意识到我不明白为什么“技巧”实际上有效这个情况:
{-# LANGUAGE NamedFieldPuns #-}
import Text.Read (readMaybe)
data Person = Person { age :: Int, alive :: Bool } deriving (Show)
example :: String -> String -> Either String Person
example ageString aliveString = do
age <- case readMaybe ageString of
Nothing -> Left "Invalid age string"
Just age -> pure age
if age < 0
then Left "Negative age"
else pure ()
alive <- case readMaybe aliveString of
Nothing -> Left "Invalid alive string" …
Run Code Online (Sandbox Code Playgroud)