让我们来看一下给出的例子 hackage documentation for stateful
do
smp <- start (stateful "" (:))
res <- forM "olleh~" smp
print res
输出是:
["","o","lo","llo","ello","hello"]
它的作用是将一个字符推到下一个字符后进入信号网络,首先是&#39; o&#39;然后&#39; l&#39;,&#39; l&#39;再一次,等等。
给有状态((:)
,又名cons
)的状态转换函数接受一个元素和一个元素列表,并返回带有前置单个元素的列表。 (在Haskell中,String
是Char
s)的列表
这是怎么回事?
(:) 'o' "" -- gives "o", then
(:) 'l' "o" -- gives "lo", etc
这一切都很简单,但你注意到有一个&#39;〜&#39;在输入字符串的末尾?那么为什么不给出
["","o","lo","llo","ello","hello", "~hello"]
^^^^^^
可能是因为它首先给出了初始值,然后是第一次调用(:)
second 等的结果,等等。所以如果我们输入六个字符(包括&#39;〜 &#39;)我们离开&#34;&#34;在五个字符之后。字符串"~hello"
实际上在那里,但在对信号进行采样时,我们得到旧状态(在它被丢弃之前)。
我期望以下两个(人为的)示例产生相同的输出,但它们不会:
-- 1
do
smp <- start $ do
n <- input
return (n*2)
res <- forM [1,2,3] smp
print res -- prints [2,4,6]
-- 2
do
smp <- start $ stateful 0 (\n _ -> n*2) -- ignore state
res <- forM [1,2,3] smp
print res -- prints [0,2,4]
-- edit: 3
-- to make the trio complete, you can use transfer to do the same
-- thing as 1 above
-- there is of course no reason to actually do it this way
do
smp <- start $ transfer undefined (\n _ _ -> n*2) (pure undefined)
res <- forM [1,2,3] smp
print res
所以我的问题是:
编辑: 在亚历山大指出我transfer后,我想出了这个:
do
smp <- start (stateful' "" (:))
res <- forM "olleh" smp -- no '~'!
print res -- prints ["o","lo","llo","ello","hello"]
stateful' :: a -> (p -> a -> a) -> SignalGen p (Signal a)
stateful' s f = transfer s (\p _ a -> f p a) (pure undefined)
状态&#39;在我的机器上似乎比有状态慢大约25%。
答案 0 :(得分:1)
可能是因为它首先给出了初始值,然后是第一次调用(:)秒的结果等等。所以如果我们输入六个字符(包括'〜'),我们会在五个字符后输出“”前缀。字符串“~hello”实际上在那里,但在对信号进行采样时,我们得到旧状态(在它被丢弃之前)。
这正是stateful
的工作原理。引用the documentation:
初始状态是第一个输出,并且每个后续输出都是从前一个输出和全局参数的值计算的
这回答了你的第一个问题。
至于第二个,是的,替代函数可以立即返回新状态。事实上,有such a function already,称为transfer
:
当前输入影响当前输出,即第一个参数中给出的初始状态被认为出现在第一个输出之前,并且永远不会被观察到。
(它也带有状态,你的例子中你应该忽略它。)
使用此功能,可以像这样重写“hello”示例:
do
smp <- start (transfer
""
(\character _ state -> character:state)
(pure undefined))
res <- forM "olleh" smp
print res