Haskell 为什么我可以调用一元函数而不提供一元?
我认为我对Haskell Monads有很好的了解,直到我意识到这段非常简单的代码对我来说毫无意义(这是来自:Haskell 为什么我可以调用一元函数而不提供一元?,haskell,monads,state-monad,Haskell,Monads,State Monad,我认为我对Haskell Monads有很好的了解,直到我意识到这段非常简单的代码对我来说毫无意义(这是来自: playGame::String->State GameState GameValue 玩游戏 (u,score)>=和lambda代替do符号?我自己也弄不明白。将其分解为do符号 playGame [] = get >>= \ (_, score) -> return score 我们也可以用fmap playGame [] = fmap (\(
playGame::String->State GameState GameValue
玩游戏
(u,score)>=
和lambda代替do符号?我自己也弄不明白。将其分解为do
符号
playGame [] =
get >>= \ (_, score) ->
return score
我们也可以用fmap
playGame [] = fmap (\(_, score) -> score) get
playGame [] = fmap snd get
现在的诀窍是认识到,get
是一个与类型相同的值
State s s
在我们将计算结果输入到runState
或类似的程序中,并在其中为状态提供一个明确的起始值之前,get
将返回什么将无法确定
如果我们进一步简化它,去掉状态单子,我们就有了
playGame :: String -> (GameState -> (GameState, GameValue))
playGame [] = \gamestate -> (gamestate, snd gamestate)
状态monad只是围绕着所有手动传递的GameState
展开,但是你可以把get
看作是访问我们传递的“函数”的值。monad是一种“东西”,它接受一个上下文(我们称之为m)并“产生”一个值,同时仍然遵守monad法则。我们可以从单子的“内部”和“外部”两个方面来考虑这一点。单子定律告诉我们如何处理“往返”——出去然后再回来。特别是,这些定律告诉我们,m(MA)本质上是与(MA)相同的类型
关键是单子是这种往返的概括。join将(m(ma))压缩为(ma),并且(>>=)从monad中提取一个值,并将函数应用到monad中。换句话说,它将一个函数(f::a->mb)应用于(ma)中的a,从而生成一个(m(mb)),然后通过join将其压扁以获得我们的(mb)
那么这与“get”和对象有什么关系呢
好的,do符号将我们设置为计算结果在我们的单子中。(代码不是“调用”get。“get”不是一个函数,它是一个多态值:谢谢,这实际上是我的一个主要困惑点。对于来自OO世界的人来说,这几乎是一个不幸的名字,在OO世界中,类通常有“getThis”和“getthit”方法。我只是假设,因为“get”是一个动词,它必须是一个函数。即使在OO语言中也不是那么简单。特别是因为OO getter不是函数——它们实际上更接近多态值,就像Haskell的get一样。区别在于OO语言中的monad将值附加到一个对象,而我们将值附加到具有任意属性的任意monad语义学。我会给出一个答案来解释我的意思。因此,从某种意义上说,状态monad隐藏了状态的传递(正如您所提到的)。我可以欣赏这里的“魔力”。但在运行状态的本质中,“get”的值是“保持”的…对吗?@parker.sikand所以
State
只是一个文本函数上的包装器s->(s,a)
runState
是我们用来实际应用这个函数的。你可以把它看作是一种“增强的”$
。所以我想runState
与中的一样拥有get
的值(\x->…)$a
$
保存x
playGame :: String -> (GameState -> (GameState, GameValue))
playGame [] = \gamestate -> (gamestate, snd gamestate)
doStuff = do
a <- get
b <- get
return $ (a + b)
doStuff = do
a <- get
b <- get
(a + b) -> (\x -> return x)
x = foo.bar.baz.bin()