【问题标题】:Reducing Haskell expressions减少 Haskell 表达式
【发布时间】:2013-11-04 11:28:13
【问题描述】:

嗨,我是 Haskell 新手,主要阅读 LYAHHutton。 最近我遇到了这个sn-p,其中 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

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

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

【问题讨论】:

  • 第一个版本实际上是不完整的,它应该是let (a, s) = runState m st(或者,在模式中,fmap f (State m)。这是否澄清了一些事情?- 请注意,这在最近的 GHC 中都不起作用,因为State 不再是简单的newtype,而是根据单子转换器定义。(这很容易解释:只需将State 替换为state。)
  • 您好,我在编写 sn-p 时出错。感谢您的回复。你能解释一下你在模式 fmap (State m) 中的意思吗?也只是单纯的好奇。
  • 好吧,在使用 fmapped 值构建“新状态对象”之前,您先解构原始对象。同样,这在标准库中现在不起作用。

标签: haskell functional-programming monads reduction


【解决方案1】:

如果我提出的任何概念(例如 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 绑定到 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

根据我们对fg 的定义,

f                     . g
(\(a, s) -> (f a, s)) . (runState m)

您可以在runState m 周围去掉括号。

【讨论】:

    猜你喜欢
    • 2012-03-17
    • 2022-01-21
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    相关资源
    最近更新 更多