Haskell 为什么我可以调用一元函数而不提供一元?

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 (\(

我认为我对Haskell Monads有很好的了解,直到我意识到这段非常简单的代码对我来说毫无意义(这是来自:

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()