减少Haskell表达式

Pau*_*l K 3 monads haskell functional-programming reduction

嗨,我是Haskell的新手,主要是从LYAHHutton读书.最近我遇到了这个状态monad的Functor实例的片段,表示为:

instance Functor (State st) where
    fmap f m = State $ \st -> let (a, s) = runState m st in (f a, s)
Run Code Online (Sandbox Code Playgroud)

这可以简化为:

instance Functor (State st) where 
    fmap f m = State $ (\(a,s) -> (f a,s)) . runState m
Run Code Online (Sandbox Code Playgroud)

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

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

kqr*_*kqr 9

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

如果你来自其他编程语言,可能会让人感到困惑的一件事是,在Haskell中,你可以使用像

runState
Run Code Online (Sandbox Code Playgroud)

并添加一个参数

runState m
Run Code Online (Sandbox Code Playgroud)

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

runState m st
Run Code Online (Sandbox Code Playgroud)

它最终将计算一个值.这意味着if runState是两个参数的函数,那么它runState m是一个参数的函数,可以像对应一个参数的任何其他函数一样对待.


你的例子中重要的一点是

\st -> let (a, s) = runState m st in (f a, s)
Run Code Online (Sandbox Code Playgroud)

哪个可以变成

(\(a,s) -> (f a,s)) . runState m
Run Code Online (Sandbox Code Playgroud)

使用运算符进行函数组合(.).


理解如何实现的第一步是认识到let…in表达式可以用lambda形式重写.这意味着

let y = f x in expr
Run Code Online (Sandbox Code Playgroud)

可写成

(\y -> expr) (f x)
Run Code Online (Sandbox Code Playgroud)

这两行都将名称绑定y到值f x,这实际上是我们需要的let…in表达式.

如果你将这些知识应用于

\st -> let (a, s) = runState m st in (f a, s)
Run Code Online (Sandbox Code Playgroud)

你会看到它可以被重写为

\st -> (\(a, s) -> (f a, s)) (runState m st)
Run Code Online (Sandbox Code Playgroud)

我们就在那里!


功能组成的定义是这样的:

f . g = \x -> f (g x)
Run Code Online (Sandbox Code Playgroud)

这意味着每当你有一些看起来像\x -> f (g x)你可以用它替换它的东西f . g.

那么,在这种情况下,我们确实有类似的东西!如果我们这样说

f = \(a, s) -> (f a, s)
g = runState m
x = st
Run Code Online (Sandbox Code Playgroud)

我们看到了

\st -> (\(a, s) -> (f a, s)) (runState m st)
\x  -> f                     (g          x)
Run Code Online (Sandbox Code Playgroud)

只不过是等待发生的功能组合.所以我们可以把它变成

f . g
Run Code Online (Sandbox Code Playgroud)

这是我们对f和的定义g,

f                     . g
(\(a, s) -> (f a, s)) . (runState m)
Run Code Online (Sandbox Code Playgroud)

你可以放下括号runState m.