3

嗨,我是 Haskell 新手,主要从LYAHHutton阅读。最近我遇到了这个片段,其中状态单子的 Functor 实例表示为:

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

谁能解释这种减少背后的工作流程?

还有什么关于如何学习这种减少技术的好的资源/建议?

4

1 回答 1

9

如果我提出的任何概念(例如 lambda 函数)不清楚,请在 LYAH 中阅读它们并在ghci. 然后再次回到这个回复,一切都应该清楚一点!

如果您来自其他编程语言,可能会令人困惑的一件事是,在 Haskell 中,您可以使用诸如

runState

并添加一个参数

runState m

它仍然是一个有效的功能。如果您随后添加第二个参数,如下所示:

runState m st

它最终会计算一个值。这意味着 ifrunState是两个参数的函数,thenrunState 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到 的值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)你可以用 just 替换它的东西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.

于 2013-11-04T11:57:30.020 回答