将函数的第一个参数旋转为第 n 个
给定一个至少具有 n 个参数的函数,我想旋转第一个参数,使其成为第 n 个参数。例如(在无类型 lambda 演算中):
r(λa. a) = λa. a
r(λa. λb. a b) = λb. λa. a b
r(λa. λb. λc. a b c) = λb. λc. λa. a b c
r(λa. λb. λc. λd. a b c d) = λb. λc. λd. λa. a b c d
等等。
你能用通用的方式写r
吗?如果您知道 n >= 2
怎么办?
这是 Scala 中提出的问题:
trait E
case class Lam(i: E => E) extends E
case class Lit(i: Int) extends E
case class Ap(e: E, e: E) extends E
旋转应该采用 Lam(a => Lam(b => Lam(c => Ap(Ap(a, b), c))))例如,返回 Lam(b => Lam(c => Lam(a => Ap(Ap(a, b), c))))。
Given a function with at least n
arguments, I want to rotate the first argument so that it becomes the n
th argument. For example (in untyped lambda calculus):
r(λa. a) = λa. a
r(λa. λb. a b) = λb. λa. a b
r(λa. λb. λc. a b c) = λb. λc. λa. a b c
r(λa. λb. λc. λd. a b c d) = λb. λc. λd. λa. a b c d
And so on.
Can you write r
in a generic way? What if you know that n >= 2
?
Here's the problem stated in Scala:
trait E
case class Lam(i: E => E) extends E
case class Lit(i: Int) extends E
case class Ap(e: E, e: E) extends E
The rotation should take Lam(a => Lam(b => Lam(c => Ap(Ap(a, b), c))))
and return Lam(b => Lam(c => Lam(a => Ap(Ap(a, b), c))))
, for example.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
诀窍是标记所涉及函数的“最终”值,因为对于正常的 haskell,
a -> 都可以。 b
和a -> (b->c)
只是单个变量的函数。但是,如果我们这样做,我们就可以做到这一点。
然后,看看它的实际效果:
The trick is to tag the "final" value of the functions involved, since to normal haskell, both
a -> b
anda -> (b->c)
are just functions of a single variable.If we do that, though, we can do this.
Then, to see it in action:
如果不违反 HOAS 的“合法性”,这可能是不可能的,因为
E => E
不仅必须用于对象语言中的绑定,还必须用于元语言中的计算。也就是说,这是 Haskell 中的一个解决方案。它滥用Literal
节点来放入唯一 ID 以供以后替换。享受!得到以下结果:(
不要被看起来相似的变量名称所迷惑。这是您寻求的旋转,模 alpha 转换。)
It's probably impossible without violating the ‘legitimacy’ of HOAS, in the sense that the
E => E
must be used not just for binding in the object language, but for computation in the meta language. That said, here's a solution in Haskell. It abuses aLiteral
node to drop in a unique ID for later substitution. Enjoy!with the following result:
(Don't be fooled by the similar-looking variable names. This is the rotation you seek, modulo alpha-conversion.)
是的,我正在发布另一个答案。而且它可能仍然不完全是您正在寻找的东西。但我认为它仍然可能有用。这是在哈斯克尔。
所以在这里我编写了一个基本的代数数据类型来表达 lambda 演算。我添加了一个简单但有效的自定义 Show 实例。
为了好玩,我引入了一个简单的
reduce
方法,以及帮助器replace
。警告:未经仔细考虑或测试。请勿用于工业用途。无法处理某些令人讨厌的表情。 :P它似乎有效,尽管这实际上只是我偏离了方向。 (ghci 中的
it
指的是在提示符下计算的最后一个值)现在轮到有趣的部分了,
旋转
。所以我想我可以剥离第一层,如果它是 Lambda,那就太好了,我将保存标识符并继续向下钻取,直到找到非 Lambda。然后我将 Lambda 和标识符放回“最后”位置。如果它一开始就不是 Lambda,那么什么也不做。请原谅缺乏想象力的变量名称。通过 ghci 发送此信息显示出良好的迹象:
Yes, I'm posting another answer. And it still might not be exactly what you're looking for. But I think it might be of use nonetheless. It's in Haskell.
So here I cooked up a basic algebraic data type for expressing lambda calculus. I added a simple, but effective, custom Show instance.
For fun, I threw in a simple
reduce
method, with helperreplace
. Warning: not carefully thought out or tested. Do not use for industrial purposes. Cannot handle certain nasty expressions. :PIt seems to work, though that's really just me getting sidetracked. (
it
in ghci refers to the last value evaluated at the prompt)So now for the fun part,
rotate
. So I figure I can just peel off the first layer, and if it's a Lambda, great, I'll save the identifier and keep drilling down until I hit a non-Lambda. Then I'll just put the Lambda and identifier right back in at the "last" spot. If it wasn't a Lambda in the first place, then do nothing.Forgive the unimaginative variable names. Sending this through ghci shows good signs:
使用模板 haskell 执行此操作的一种方法如下:
使用这两个函数:
然后对于具有可变数量参数的函数
myF
,您可以通过这种方式旋转它们:肯定有更简洁的方法与 TH 一起做这件事,我对此很陌生。
One way to do it with template haskell would be like this:
With these two functions:
Then for a function
myF
with a variable number of parameters you could rotate them this way:There most certainly are neater ways of doing this with TH, I am very new to it.
好的,感谢所有提供答案的人。这是我最终采用的解决方案。利用我知道
n
的事实:我认为如果不给出
n
就无法解决这个问题,因为在 lambda 演算中,项的元数可以取决于它的争论。即没有明确的“最后”论点。相应地改变了问题。OK, thanks to everyone who provided an answer. Here is the solution I ended up going with. Taking advantage of the fact that I know
n
:I don't think this can be solved without giving
n
, since in the lambda calculus, a term's arity can depend on its argument. I.e. there is no definite "last" argument. Changed the question accordingly.我认为您可以使用论文 Haskell 中的 n 元 zipWith 用于此目的。
I think you could use the techniques described int the paper An n-ary zipWith in Haskell for this.
Haskell
不是普通的 Haskell。您必须使用其他人(比我聪明得多)可能会发布的一些深层模板魔法。
在普通的 Haskell 中,让我们尝试编写一个类。
旋转的类型到底是什么?如果您无法编写其类型签名,那么您可能需要模板来按照您正在寻找的通用性级别进行编程(无论如何,在 Haskell 中)。
不过,将这个想法转化为 Haskell 函数很容易。
某些
Lisp(s)
Lispy 语言具有
apply
函数(链接:r5rs),它接受一个函数和一个列表,并将列表的元素作为参数应用于函数。我想在这种情况下,取消列表的旋转并继续发送它并不那么困难。我再次向专家们寻求更深入的答案。Haskell
Not in plain vanilla Haskell. You'd have to use some deep templating magic that someone else (much wiser than I) will probably post.
In plain Haskell, let's try writing a class.
What on earth is the type for rotate? If you can't write its type signature, then you probably need templates to program at the level of generality you are looking for (in Haskell, anyways).
It's easy enough to translate the idea into Haskell functions, though.
etc.
Lisp(s)
Some Lispy languages have the
apply
function (linked: r5rs), which takes a function and a list, and applies the elements of the list as arguments to the function. I imagine in that case it wouldn't be so hard to just un-rotate the list and send it on its way. I again defer to the gurus for deeper answers.