tl;博士:
结论1:你不能
你最初要求的东西是不可能的,至少不是你想要的任何版本我都能想出。(见下文。)如果更改您的数据类型以允许我存储中间计算,我想我会没事的,但即使那样,该功能unFold
也会相当低效,这似乎与您聪明的优化技巧议程背道而驰!
结论 2:我认为它没有达到你想要的效果,即使你通过改变类型来解决它
列表算法的任何优化都会受到您使用原始未优化函数计算阶跃函数的问题的影响,而且很可能是以复杂的方式。
由于函数不相等,因此不可能将 step 优化为有效的东西。我认为你需要一个人来做unFold
,而不是一个编译器。
无论如何,回到最初的问题:
可以折叠。展开 = 身份证?
不。假设我们有
isSingleton :: [a] -> Bool
isSingleton [x] = True
isSingleton _ = False
then if we have unFold :: ([x] -> y) -> Fold x y
then if与需要foldSingleton
的相同unFold isSingleton
foldSingleton = Fold {start = False , step = ???}
其中 step 获取列表的一个元素并更新结果。现在isSingleton "a" == True
,我们需要
step False = True
因为isSingleton "ab" == False
,我们需要
step True = False
所以step = not
到目前为止,isSingleton "abc" == False
我们也需要
step False = False
因为有些函数([x] -> y)
不能用类型的值表示Fold x y
,所以不可能存在unFold :: ([x] -> y) -> Fold x y
这样的函数fold . unFold = id
,因为id
是一个全函数。
编辑:
事实证明您对此并不信服,因为您只期望unFold
处理具有折叠表示的函数,所以也许您的意思是unFold.fold = id
.
可以展开。折叠 = 身份证?
不
,即使您只想unFold
处理([x] -> y)
可以使用 获得的功能fold :: Fold x y -> ([x] -> y)
,我认为这是不可能的。让我们假设现在我们已经定义了这个问题
combine :: X -> Y -> Y
initial :: Y
folded :: [X] -> Y
folded = fold $ Fold initial combine
恢复价值initial
是微不足道的:initial = folded []
. 恢复原件combine
不是,因为没有办法从一个给你一些值的函数Y
到一个组合任意值的函数Y
。
例如,如果我们有X = Y = Int
并且我定义了
combine x y | y < 0 = -10
| otherwise = y + 1
initial = 0
然后,因为每次在 positive 上使用它时都combine
加一,并且初始值为 0,就其输出而言无法区分。请注意,由于永远不会是负数,因此也不可能定义一个可以恢复我们函数的函数。这归结为不是内射的事实。它携带不同的 type 值到相同的 type 值。y
y
folded
length
folded xs
unFold :: ([x] -> y) -> Fold x y
combine
fold
Fold x y
[x] -> y
因此,我证明了两件事:if unFold :: ([x] -> y) -> Fold x y
then bothfold.unFold /= id
和 now alsounFold.fold /= id
我打赌你也不相信这一点,因为你并不真正关心你是从 得到Fold 0 (\_ y -> y+1)
还是Fold 0 combine
从 回来unFold folded
,因为它们在重折叠时具有相同的价值!让我们再次缩小球门柱。也许你想unFold
在函数可以通过 获得的时候工作fold
,并且你很高兴它不会给你不一致的答案,只要你再次折叠结果,你会得到相同的函数。我可以用下一个问题来总结一下:
可以折叠。展开。折叠=折叠?
即,您能否定义unFold
这fold.unFold
是可通过 获得的函数集的标识fold
?
我真的相信这是不可能的,因为在step
不保留有关子列表中间值的额外信息的情况下计算函数不是一个容易处理的问题。
假设我们有
unFold f = Fold {start = f [], step = recoverstep f}
我们需要
recoverstep f x1 initial == f [x1]
因此,如果有 x 的 Eq 实例(敲响警钟!),那么 recoverstep 必须具有与
recoverstep f x1 y | y == initial = f [x1]
我们也需要
recoverstep f x2 (f [x1]) == f [x1,x2]
所以如果 x 有一个 Eq 实例,那么 recoverstep 必须具有与
recoverstep f x2 y | y == (f [x1]) = f [x1,x2]
但这里有一个大问题:x1
这个等式右边的变量是自由的。这意味着从逻辑上讲,除非我们已经知道在 x 上使用了什么值,否则我们无法判断阶跃函数在 x 上应该具有什么值。我们需要将 等的值存储f [x1]
在f [x1,x2]
Fold 数据类型中以使其工作,这就是为什么我们不能定义unFold
. 如果您更改数据类型 Fold 以允许我们存储有关中间列表的信息,我可以看到它会起作用,但就目前而言,恢复上下文是不可能的。