您好,我是 Haskell 新手,主要阅读 LYAH和 Hutton . 最近我遇到了这个片段,其中 Functor 实例 一个状态单子(monad),表示为:
instance Functor (State st) where
fmap f m = State $ \st -> let (a, s) = runState m st in (f a, s)
这可以简化为:
instance Functor (State st) where
fmap f m = State $ (\(a,s) -> (f a,s)) . runState m
谁能解释这种减少背后的工作流程?
关于如何学习这种减少技术,还有哪些好的资源/建议?
最佳答案
如果我提出的任何概念(例如 lambda 函数)不清楚,请在 LYAH 中阅读它们并在 ghci
中尝试一下。然后再回到这个回复,一切都应该清楚了!
如果您来自其他编程语言,可能会令人困惑的一件事是,在 Haskell 中,您可以使用如下函数
runState
并添加一个参数
runState m
它仍然是一个有效的函数。如果您随后添加第二个参数,如下所示:
runState m st
它最终会计算一个值。这意味着如果 runState
是一个有两个参数的函数,那么 runState m
就是一个有一个参数的函数,可以像对待任何其他一个有一个参数的函数一样对待。
您的示例中的重要一点是
\st -> let (a, s) = runState m st in (f a, s)
可以变成
(\(a,s) -> (f a,s)) . runState m
使用运算符进行函数组合,(.)
.
了解这如何可能的第一步是认识到 let...in
表达式可以重写为 lambda 形式。这意味着
let y = f x in expr
可以写成
(\y -> expr) (f x)
这两行都会将名称 y
绑定(bind)到 f x
的值,这就是我们真正需要的 let...in
表达。
如果你将这些知识应用到
\st -> let (a, s) = runState m st in (f a, s)
你会看到它可以重写为
\st -> (\(a, s) -> (f a, s)) (runState m st)
我们已经成功了一半!
函数组合的定义是这样的:
f . g = \x -> f (g x)
这意味着任何时候你有一些看起来像 \x -> f (g x)
的东西,你都可以用 f 替换它。 g
.
好吧,在这种情况下,我们确实有一些看起来像这样的东西!如果我们这么说
f = \(a, s) -> (f a, s)
g = runState m
x = st
我们看到了
\st -> (\(a, s) -> (f a, s)) (runState m st)
\x -> f (g x)
只不过是等待发生的函数组合。所以我们可以把它变成
f . g
根据我们对 f
和 g
的定义,
f . g
(\(a, s) -> (f a, s)) . (runState m)
并且您可以将括号放在 runState m
周围。
关于haskell - 减少 Haskell 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19766772/