问题描述
我如何将一个常量应用形式变成,嗯,而不是一个常量应用形式,以阻止它在程序的生命周期内被保留?
How do I make a Constant Applicative Form into, well, not a Constant Applicative Form, to stop it being retained for the lifetime of the program?
我已经尝试过这种方法:
I've tried this approach:
-- | Dummy parameter to avoid creating a CAF
twoTrues :: () -> [[[Bool]]]
twoTrues _ = map (++ (True : repeat False)) . trueBlock <$> [1..]
但它似乎不起作用 - 配置文件显示它仍被保留并且仍将其标记为 CAF.
but it doesn't seem to work - the profile shows it as still being retained and still marks it as a CAF.
我找到了一个相关的谷歌搜索结果,Simon Peyton-Jones 对 Neil Mitchell 的回复,他正是问了这个问题 - 但不幸的是,那个答案指的是一个死链接.
I've found one relevant Google result on this, a reply by Simon Peyton-Jones to Neil Mitchell who asked precisely this question - but that answer refers to a dead link, unfortunately.
推荐答案
概括. 如果您有一个常数值,您能否将其概括为某个变量的函数?问题中我的函数的命名 twoTrues
立即表明该常量是序列中的第三个 zeroTrues
, oneTrue
, twoTrues
、threeTrues
等 - 确实如此.因此,将 twoTrues
概括为一个函数 nTrues
,它接受一个参数 n 并删除 twoTrues
,将从程序.
Generalise. If you have a constant value, can you generalise this to a function of some variable? The naming of my function in the question, twoTrues
, immediately suggests that this constant is the third in a sequence zeroTrues
, oneTrue
, twoTrues
, threeTrues
etc. - and indeed it is. So generalising twoTrues
into a function nTrues
which takes a parameter n and deleting twoTrues
, would eliminate one CAF from the program.
碰巧,在这种情况下,我只考虑了我的程序的情况 zeroTrues
、oneTrue
和 twoTrues
因为这就是全部我需要,但我的程序可以自然地扩展到处理 n
> 2 的 nTrues
- 所以推广到 nTrues
意味着它会有意义向zeroTrues
、oneTrue
等的用户全面推广".情况并非总是如此.
As it happens, in this case, I had only considered the cases zeroTrues
, oneTrue
and twoTrues
for my program because that was all I needed, but my program could naturally be extended to deal with nTrues
for n
> 2 - so generalising to nTrues
would mean it would make sense to "generalise all the way up" to the users of zeroTrues
, oneTrue
etc. That would not always be the case.
注意:可能还有其他 CAF 需要处理,无论是在代码中,还是由 GHC 的优化"生成(在这些病态情况下都不是真正的优化).
Note: there might still be other CAFs to deal with, either in the code, or produced by GHC's "optimisations" (which are not really optimisations in these pathological cases).
然而,这个答案可能涉及程序员的更多工作,而不是绝对必要的.正如唐的回答所示,实际上没有必要进行概括.
This answer may involve more work by the programmer than is strictly necessary, however. It isn't actually necessary to generalise, as Don's answer shows.
另一方面,在某些情况下,概括一个常量可以使您更清楚地了解您实际在做什么,并有助于可重用性.它甚至可以揭示以更好的系统方式和/或更高效的方式计算一系列值的方法.
On the other hand, in some cases, generalising a constant can make it more clear what you are actually doing, and aid reusability. It can even reveal ways to compute a series of values in a better systematic way, and/or more efficiently.
关于这种特殊情况的说明(可以忽略):在这种特殊情况下,我不想将 nTrues
本身 变成一个无限列表(这会再次成为 CAF,重新引入原始问题!)而不是函数.一个原因是,虽然 twoTrues
可能以无限列表的形式有用,但我看不出它对 nTrues
有何用处(无论如何在我的应用程序中)以无限列表的形式.
A note about this particular case (which can be ignored): In this particular case, I would not want to make nTrues
itself into an infinite list (which would be a CAF again, reintroducing the original problem!) rather than a function. One reason is that while twoTrues
could be useful in the form of an infinite list, I can't see how it would be useful (in my application, anyway) for nTrues
to be in the form of an infinite list.
这篇关于如何在 Haskell 中使 CAF 不是 CAF?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!