在Elerea,为什么stateful return不是最后一次状态转换后的状态?
In Elerea, why doesn't stateful return the state after the last state transformation?
让我们看一下
hackage documentation for stateful
do
smp <- start (stateful "" (:))
res <- forM "olleh~" smp
print res
输出是:
["","o","lo","llo","ello","hello"]
它所做的是将一个字符一个接一个地推入信号网络,首先是 'o',然后是 'l',然后是 'l',依此类推。
给有状态((:)
,又名 cons
)的状态转换函数接受一个元素和一个元素列表,return 是带有单个元素的列表。 (在 Haskell 中,一个 String
是 Char
的列表)
这是怎么回事
(:) 'o' "" -- gives "o", then
(:) 'l' "o" -- gives "lo", etc
这一切都非常简单,但您是否注意到输入字符串末尾有一个“~”?那为什么不给
["","o","lo","llo","ello","hello", "~hello"]
^^^^^^
?
可能是因为它先给出初始值,然后是(:)
第一次调用的结果第二次,等等。所以如果我们压入六个字符(包括'~') 我们在 5 个字符被前置后得到 ""。字符串 "~hello"
实际上在那里,但是在对信号进行采样时我们得到 old 状态(就在它被丢弃之前)。
我希望以下两个(人为的)示例产生相同的输出,但它们没有:
-- 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
所以我的问题是:
- 为什么要这样做?获得初始值是否足够重要,我们只需要接受这个延迟?
- 是否可以使用替代函数 return 下一个值? (换句话说,这个替代函数 return "hello" 是否可以在 'h' 被发送后立即被发送,所以 '~' 可以被删除?)结果信号将永远不会产生初始信号值。
编辑:
在 Alexander 向我指出 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)
stateful' 在我的机器上似乎比 stateful 慢了大约 25%。
Probably because it gives the initial value first, then the result of the first invocation of (:) second, etc. So if we push in six characters (including '~') we get out "" after five characters have been prepended. The string "~hello" is actually in there, but on sampling the signal we get the old state (right before it is discarded).
这正是 stateful
的工作原理。引用 the documentation:
The initial state is the first output, and every following output is calculated from the previous one and the value of the global parameter
这回答了您的第一个问题。
至于第二个,是的,替代函数可以 return 立即进入新状态。其实还有such a function already,叫做transfer
:
The current input affects the current output, i.e. the initial state given in the first argument is considered to appear before the first output, and can never be observed.
(它还带有状态,您在示例中应该忽略它。)
有了这个函数,"hello"例子可以改写成这样:
do
smp <- start (transfer
""
(\character _ state -> character:state)
(pure undefined))
res <- forM "olleh" smp
print res
让我们看一下 hackage documentation for stateful
do
smp <- start (stateful "" (:))
res <- forM "olleh~" smp
print res
输出是:
["","o","lo","llo","ello","hello"]
它所做的是将一个字符一个接一个地推入信号网络,首先是 'o',然后是 'l',然后是 'l',依此类推。
给有状态((:)
,又名 cons
)的状态转换函数接受一个元素和一个元素列表,return 是带有单个元素的列表。 (在 Haskell 中,一个 String
是 Char
的列表)
这是怎么回事
(:) 'o' "" -- gives "o", then
(:) 'l' "o" -- gives "lo", etc
这一切都非常简单,但您是否注意到输入字符串末尾有一个“~”?那为什么不给
["","o","lo","llo","ello","hello", "~hello"]
^^^^^^
?
可能是因为它先给出初始值,然后是(:)
第一次调用的结果第二次,等等。所以如果我们压入六个字符(包括'~') 我们在 5 个字符被前置后得到 ""。字符串 "~hello"
实际上在那里,但是在对信号进行采样时我们得到 old 状态(就在它被丢弃之前)。
我希望以下两个(人为的)示例产生相同的输出,但它们没有:
-- 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
所以我的问题是:
- 为什么要这样做?获得初始值是否足够重要,我们只需要接受这个延迟?
- 是否可以使用替代函数 return 下一个值? (换句话说,这个替代函数 return "hello" 是否可以在 'h' 被发送后立即被发送,所以 '~' 可以被删除?)结果信号将永远不会产生初始信号值。
编辑: 在 Alexander 向我指出 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)
stateful' 在我的机器上似乎比 stateful 慢了大约 25%。
Probably because it gives the initial value first, then the result of the first invocation of (:) second, etc. So if we push in six characters (including '~') we get out "" after five characters have been prepended. The string "~hello" is actually in there, but on sampling the signal we get the old state (right before it is discarded).
这正是 stateful
的工作原理。引用 the documentation:
The initial state is the first output, and every following output is calculated from the previous one and the value of the global parameter
这回答了您的第一个问题。
至于第二个,是的,替代函数可以 return 立即进入新状态。其实还有such a function already,叫做transfer
:
The current input affects the current output, i.e. the initial state given in the first argument is considered to appear before the first output, and can never be observed.
(它还带有状态,您在示例中应该忽略它。)
有了这个函数,"hello"例子可以改写成这样:
do
smp <- start (transfer
""
(\character _ state -> character:state)
(pure undefined))
res <- forM "olleh" smp
print res