在 Haskell 中,如何将嵌套上下文中的 "apply" 函数转换为上下文中的值?
In Haskell how to "apply" functions in nested context to a value in context?
nestedApply :: (Applicative f, Applicative g) => g (f (a -> b)) -> f a -> g (f b)
如类型所示,如何在上下文 f
中将 (a->b)
应用于 a
?
感谢您的帮助。
这是关注类型很有帮助的案例之一。我会尽量保持简单并解释原因。
让我们从描述任务开始。我们有 gfab :: g(f(a->b))
和 fa :: f a
,我们想要有 g(f b)
.
gfab :: g (f (a -> b))
fa :: f a
??1 :: g (f b)
由于 g
是一个函子,要获得类型 g T
我们可以从 g U
类型的值 ??2
开始并将 fmap
应用于 ??3 :: U -> T
。在我们的例子中,我们有 T = f b
,所以我们正在寻找:
gfab :: g (f (a -> b))
fa :: f a
??2 :: g U
??3 :: U -> f b
??1 = fmap ??3 ??2 :: g (f b)
现在,看来我们应该选择 ??2 = gfab
。毕竟,这是我们拥有的类型 g Something
的唯一值。我们得到U = f (a -> b)
.
gfab :: g (f (a -> b))
fa :: f a
??3 :: f (a -> b) -> f b
??1 = fmap ??3 gfab :: g (f b)
让我们把 ??3
变成一个 lambda,\ (x :: f (a->b)) -> ??4
和 ??4 :: f b
。 (x
的类型可以省略,但我决定加上它来说明是怎么回事)
gfab :: g (f (a -> b))
fa :: f a
??4 :: f b
??1 = fmap (\ (x :: f (a->b)) -> ??4) gfab :: g (f b)
如何制作??4
。好吧,我们有 f (a->b)
和 f a
类型的值,所以我们可以 <*>
得到 f b
。我们最终得到:
gfab :: g (f (a -> b))
fa :: f a
??1 = fmap (\ (x :: f (a->b)) -> x <*> fa) gfab :: g (f b)
我们可以将其简化为:
nestedApply gfab fa = fmap (<*> fa) gfab
现在,这不是最优雅的方法,但理解这个过程很重要。
有
nestedApply :: (Applicative f, Applicative g)
=> g (f (a -> b))
-> f a
-> g (f b )
要在上下文 f
中将 (a->b)
应用于 a
,我们需要在上下文 中操作 g
.
那只是 fmap
。
翻转签名更清晰,重点看最后部分
flip nestedApply :: (Applicative f, Applicative g)
=> f a
-> g (f (a -> b)) --- from here
-> g (f b ) --- to here
所以我们这里有
nestedApply gffun fx = fmap (bar fx) gffun
在 下应用 bar fx
g
由 fmap
为我们包装。这是
bar fx :: f (a -> b)
-> f b
即
bar :: f a
-> f (a -> b)
-> f b
这只是 <*>
不是吗,又翻转了。这样我们就得到了答案,
nestedApply gffun fx = fmap (<*> fx) gffun
我们可以看到只使用了g
的fmap
个功能,所以我们只需要
nestedApply :: (Applicative f, Functor g) => ...
在类型签名中。
写在sheet纸上容易,二维.我们在这里用狂野的缩进来模仿,以获得垂直对齐。
是的,我们人类首先学会了书写,在纸上,然后在打字机上打字,时间要晚得多。上一代或两代人从小就被迫使用现代设备进行线性打字,但 现在 涂鸦和说话(以及手势和指点)有望再次流行起来。创造性的输入模式最终将包括 3D 工作流程, 将是一个明确的进步。 1D 不好,2D 好,3D 更好。例如,许多类别理论图在以 3D 形式绘制时更容易理解(至少可以想象)。经验法则是,它应该简单,而不是困难。如果太忙,可能需要另一个维度。
只是玩连接电线。几张不言而喻的图,就大功告成了。
这里有一些类型的曼荼罗(再次翻转):
-- <$> -- <*> -- =<<
f a f a f a
(a -> b) f (a -> b) (a -> f b)
f b f b f ( f b) -- fmapped, and
f b -- joined
当然还有所有应用程序之母,
-- $
a
a -> b
b
a.k.a。 Modus Ponens (是的,也翻转了).
nestedApply :: (Applicative f, Applicative g) => g (f (a -> b)) -> f a -> g (f b)
如类型所示,如何在上下文 f
中将 (a->b)
应用于 a
?
感谢您的帮助。
这是关注类型很有帮助的案例之一。我会尽量保持简单并解释原因。
让我们从描述任务开始。我们有 gfab :: g(f(a->b))
和 fa :: f a
,我们想要有 g(f b)
.
gfab :: g (f (a -> b))
fa :: f a
??1 :: g (f b)
由于 g
是一个函子,要获得类型 g T
我们可以从 g U
类型的值 ??2
开始并将 fmap
应用于 ??3 :: U -> T
。在我们的例子中,我们有 T = f b
,所以我们正在寻找:
gfab :: g (f (a -> b))
fa :: f a
??2 :: g U
??3 :: U -> f b
??1 = fmap ??3 ??2 :: g (f b)
现在,看来我们应该选择 ??2 = gfab
。毕竟,这是我们拥有的类型 g Something
的唯一值。我们得到U = f (a -> b)
.
gfab :: g (f (a -> b))
fa :: f a
??3 :: f (a -> b) -> f b
??1 = fmap ??3 gfab :: g (f b)
让我们把 ??3
变成一个 lambda,\ (x :: f (a->b)) -> ??4
和 ??4 :: f b
。 (x
的类型可以省略,但我决定加上它来说明是怎么回事)
gfab :: g (f (a -> b))
fa :: f a
??4 :: f b
??1 = fmap (\ (x :: f (a->b)) -> ??4) gfab :: g (f b)
如何制作??4
。好吧,我们有 f (a->b)
和 f a
类型的值,所以我们可以 <*>
得到 f b
。我们最终得到:
gfab :: g (f (a -> b))
fa :: f a
??1 = fmap (\ (x :: f (a->b)) -> x <*> fa) gfab :: g (f b)
我们可以将其简化为:
nestedApply gfab fa = fmap (<*> fa) gfab
现在,这不是最优雅的方法,但理解这个过程很重要。
有
nestedApply :: (Applicative f, Applicative g)
=> g (f (a -> b))
-> f a
-> g (f b )
要在上下文 f
中将 (a->b)
应用于 a
,我们需要在上下文 中操作 g
.
那只是 fmap
。
翻转签名更清晰,重点看最后部分
flip nestedApply :: (Applicative f, Applicative g)
=> f a
-> g (f (a -> b)) --- from here
-> g (f b ) --- to here
所以我们这里有
nestedApply gffun fx = fmap (bar fx) gffun
在 下应用 bar fx
g
由 fmap
为我们包装。这是
bar fx :: f (a -> b)
-> f b
即
bar :: f a
-> f (a -> b)
-> f b
这只是 <*>
不是吗,又翻转了。这样我们就得到了答案,
nestedApply gffun fx = fmap (<*> fx) gffun
我们可以看到只使用了g
的fmap
个功能,所以我们只需要
nestedApply :: (Applicative f, Functor g) => ...
在类型签名中。
写在sheet纸上容易,二维.我们在这里用狂野的缩进来模仿,以获得垂直对齐。
是的,我们人类首先学会了书写,在纸上,然后在打字机上打字,时间要晚得多。上一代或两代人从小就被迫使用现代设备进行线性打字,但 现在 涂鸦和说话(以及手势和指点)有望再次流行起来。创造性的输入模式最终将包括 3D 工作流程, 将是一个明确的进步。 1D 不好,2D 好,3D 更好。例如,许多类别理论图在以 3D 形式绘制时更容易理解(至少可以想象)。经验法则是,它应该简单,而不是困难。如果太忙,可能需要另一个维度。
只是玩连接电线。几张不言而喻的图,就大功告成了。
这里有一些类型的曼荼罗(再次翻转):
-- <$> -- <*> -- =<<
f a f a f a
(a -> b) f (a -> b) (a -> f b)
f b f b f ( f b) -- fmapped, and
f b -- joined
当然还有所有应用程序之母,
-- $
a
a -> b
b
a.k.a。 Modus Ponens (是的,也翻转了).