我刚才读从以下typeclassopedia约之间的差异Monad和Applicative.我能理解,没有join在Applicative.但是下面的描述看起来含糊不清,我无法弄清楚monadic计算/动作的"结果"究竟是什么意思.所以,如果我把一个值放入Maybe,这使得一个monad,这个"计算"的结果是什么?
让我们更仔细地看一下(>> =)的类型.基本的直觉是它将两个计算组合成一个更大的计算.第一个参数ma是第一个计算.但是,如果第二个论点只是一个mb,那将是无聊的; 那么计算就无法相互交互(实际上,这正是Applicative的情况).因此,(>> =)的第二个参数具有类型a - > mb:这种类型的函数,给定第一次计算的结果,可以产生第二个要运行的计算....直观地说,正是这种能力使用先前计算的输出来决定接下来运行哪些计算使Monad比Applicative更强大.应用计算的结构是固定的,而Monad计算的结构可以基于中间结果而改变.
是否有一个具体的例子说明"能够使用先前计算的输出来决定接下来要运行的计算",Applicative没有?
我开始了我的Grand Haskell Crusade(GHC :)),我对monads和IO功能有点困惑.谁能解释一下这两个功能之间的区别是什么?
f1 = do x <- [1,2]
[x, x+1] -- this is monad, right?
f2 = do x <- [1,2]
return [x, x+1]
Run Code Online (Sandbox Code Playgroud)
结果是:
*Main> f1
[1,2,2,3]
*Main> f2
[[1,2],[2,3]]
Run Code Online (Sandbox Code Playgroud) 我已经阅读了这篇文章,但最后一节并未理解.
作者说Monad给了我们上下文敏感性,但是只使用Applicative实例就可以实现相同的结果:
let maybeAge = (\futureYear birthYear -> if futureYear < birthYear
then yearDiff birthYear futureYear
else yearDiff futureYear birthYear) <$> (readMay futureYearString) <*> (readMay birthYearString)
Run Code Online (Sandbox Code Playgroud)
没有do语法肯定会更加丑陋,但除此之外我不明白为什么我们需要Monad.任何人都可以为我清除这个吗?
一次又一次,我读了长期effectful,但我还是无法给予的是什么意思的明确定义.我认为正确的上下文是effectful 计算,但我也看到了长期effectful 值)
我曾经认为有效的手段有副作用.但在Haskell中没有副作用(除了某种程度上IO).整个地方仍然有效的计算.
然后我读到monad用于创建有效的计算.我可以在StateMonad 的背景下理解这一点.但我没有看到Maybemonad中有任何副作用.一般来说,在我看来,Monads包含一个类似函数的东西更容易看到产生副作用比Monads只包装一个值.
谈到Applicative仿函数,我更加迷失.我总是看到applicative functor作为一个map带有多个参数的函数的方法.我在这里看不到任何副作用.或者是有之间的差异effectful并用的效果?
我知道这个问题已被多次询问和回答,但我仍然不明白为什么对数据类型设置约束是一件坏事.
例如,我们来看看Data.Map k a.所有涉及Map需要Ord k约束的有用函数.所以对于定义有一个隐含的约束Data.Map.为什么更好地保持隐含而不是让编译器和程序员知道Data.Map需要可订购密钥.
此外,在类型声明中指定最终类型是常见的,可以将其视为"超级"约束数据类型的方式.
例如,我可以写
data User = User { name :: String }
Run Code Online (Sandbox Code Playgroud)
这是可以接受的.然而,这不是一个受限制的版本
data User' s = User' { name :: s }
Run Code Online (Sandbox Code Playgroud)
我会为写功能的所有99%后User类型并不需要String和这将很可能只需要少数s是IsString和Show.
那么,为什么松散的版本被User认为是坏的:
data (IsString s, Show s, ...) => User'' { name :: s }
Run Code Online (Sandbox Code Playgroud)
而这两个User和User'被认为是好?
我问这个,因为很多时候,我觉得我不必要地缩小我的数据(甚至函数)定义,只是为了不必传播约束.
据我所知,数据类型约束仅适用于构造函数,不会传播.那么我的问题是,为什么数据类型约束不能按预期工作(和传播)?无论如何,这是一个扩展,那么为什么没有一个新的扩展data正常,如果它被社区认为是有用的?
abc :: IO (Int)
abc = do
print "abc"
pure $ 10
xyz :: IO (Int)
xyz = undefined
main :: IO ()
main = do
x <- (((+) <$> abc <*> abc) <* xyz)
print x
Run Code Online (Sandbox Code Playgroud)
Why in the above is xyz being evaluated? I would assume due to Haskell's lazy nature it would not need to evaluate xyz (and hence not reach the undefined)?
My assumption is based on the type of <*:
Prelude> :t (<*) …Run Code Online (Sandbox Code Playgroud) 我对(>>=)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 …
这个问题与这篇文章有关:Understanding do notation for simple Reader monad: a <- (*2), b <- (+10), return (a+b)
我不在乎一种语言是否难以理解,如果它有望解决一些易于理解的语言给我们带来的问题。我被承诺在 Haskell(和其他函数式语言)中不可能改变状态是一个游戏规则改变者,我确实相信这一点。我的代码中有太多与状态相关的错误,我完全同意这篇文章,即在 OOP 语言中对对象的交互进行推理几乎是不可能的,因为它们可以改变状态,因此为了推理代码,我们应该考虑这些状态的所有可能排列。
但是,我发现对 Haskell monad 的推理也非常困难。正如您在我链接的问题的答案中所见,我们需要一个大图来理解 do 符号的 3 行。>>=为了理解代码,我总是打开stackit.io手动去糖化do符号并一步一步地编写do符号的应用程序。
这个问题或多或少是这样的:在大多数情况下,当我们有S a >>= f我们必须展开a从S并应用f它。然而,f实际上在形式中或多或少是另一回事S a >>= g,我们也必须解开等等。人脑不是那样工作的,我们不能轻易地把这些东西应用到头脑中然后停下来,把它们放在大脑的堆栈中,然后继续应用剩下的东西,>>=直到我们到达终点。当到达终点时,我们将所有这些东西存储在大脑的堆栈中并将它们粘合在一起。
因此,我一定是做错了什么。必须有一种简单的方法来理解>>=大脑中的“成分”。我知道 do 表示法非常简单,但我只能将其视为一种轻松编写>>=作文的方法。当我看到do符号时,我只是将它翻译成一堆 >>=. 我不认为它是理解代码的一种单独方式。如果有办法,我希望有人告诉我。
所以问题是:如何阅读do符号?