全部switch
函数是改变信号函数使其行为类似于另一个信号函数的方法。我个人认为 Yampa 图有点难以解析,但是各种开关的类型签名很好地指示了如何理解它们。一旦理解了类型签名,图表就会变得更加清晰。switch
本身就是最基本的:
switch :: SF a (b, Event c) -> (c -> SF a b) -> SF a b
如果我们查看该类型,它会准确地告诉我们它的作用:它需要一个 SFsf
和 SF 发生器sfg
. sf
产生类型的值(b, Event c)
,信号函数发生器的输入也恰好是类型c
。所以,每当sf
的事件发生,SF将切换到SF生成器的结果。在事件发生之前,生成的 SF 将返回原始 SF 的值。
这个想法也被运用在rswitch
and kswitch
变体,但略有不同。
rswitch
:这称为“外部开关”,意味着 SF 将在不对其输入或输出进行任何分析的情况下进行切换。让我们看一下类型签名:
rswitch :: SF a b -> SF (a, Event (SF a b)) b
它需要一个 SF 作为类型的输入值a
并输出类型的值b
. rswitch
创建一个新的 SF 也产生输出b
,但需要额外的输入类型Event (SF a b)
。请注意,事件值的类型与输入类型匹配。这意味着每当事件发生时,该 SF 就会切换到该事件值。然而,SF 的类型仍然存在SF (a, Event (SF a b)) b
。这意味着 SF 可以自由地接收新 SF 的附加事件,这将影响整个 SF 的行为。其用途之一可能是游戏中的人工智能行为:
moveFollowTarget :: SF TargetPosition Velocity
moveShootTarget :: SF TargetPosition Velocity
moveIdle :: SF TargetPosition Velocity
aiMovement :: SF (TargetPosition, Event (SF TargetPosition Velocity)) Velocity
aiMovement = rswitch moveIdle -- Initially idle...
aiMovementManager :: SF a (Event (SF TargetPosition Velocity))
aiMovementManager = ... whatever ...
在这里,aiMovementManager
每当AI的运动行为需要改变时就会触发一个事件,该事件的值将是运动应该改变到的SF。
kswitch
: 这被称为intrinsic switch
,因为 SF 的内容经过分析以确定正确的开关应该是什么。让我们回顾一下类型签名
kswitch :: SF a b -> SF (a, b) (Event c) -> (SF a b -> c -> SF a b) -> SF a b
Here, kswitch
需要三个参数,sf
, analyzer
, and mapping
. sf
只是一个标准 SF,其输入类型为a
和类型的输出b
. sf
是信号最初的行为方式。analyzer
是一个 SF,其输入和输出为sf
并且可能会也可能不会触发某种其值具有类型的事件c
。如果它没有触发事件,那么什么也不会发生,并且 SF 继续表现得像sf
。如果它确实触发了一个事件,那么两者sf
并将事件值传递给mapping
它确定要切换到的新 SF。kswitch
当根据输出改变系统的行为方式时非常有用。
一个有用的例子是算法TCP 拥塞避免 http://en.wikipedia.org/wiki/Additive_increase/multiplicative_decrease。在这里,我们查看是否丢失网络数据包,以及提高或降低请求数据的速度。