您好我是Haskell的新手,主要是从LYAH和Hutton阅读。 最近我遇到了这个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
有人能解释这种减少背后的工作流程吗?
关于如何学习这种减少技术,还有哪些好的资源/建议?
答案 0 :(得分:9)
如果我提出的任何概念(例如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
,我们对f
和g
的定义,
f . g
(\(a, s) -> (f a, s)) . (runState m)
并且您可以将括号放在runState m
附近。