我可以使用clojure';对于';宏来反转字符串?
这是我问题的后续行动 是否可以使用Clojure“for”宏反转序列?我试图更好地理解这个宏的限制和用例 以下是我开始的代码:我可以使用clojure';对于';宏来反转字符串?,clojure,Clojure,这是我问题的后续行动 是否可以使用Clojure“for”宏反转序列?我试图更好地理解这个宏的限制和用例 以下是我开始的代码: ((defn reverse-with-for [s] (for [c s] c)) 可能吗 如果是这样,我假设解决方案可能需要将for宏包装在定义可变变量的某个表达式中,或者for宏的body expr将以某种方式将序列传递到下一次迭代(类似于map)。Clojurefor宏正在与任意Clojure序列一起使用 这些序列可能会也可能不会像向量那样公开随机访
((defn reverse-with-for [s]
(for [c s] c))
可能吗
如果是这样,我假设解决方案可能需要将
for
宏包装在定义可变变量的某个表达式中,或者for宏的body expr将以某种方式将序列传递到下一次迭代(类似于map
)。Clojurefor
宏正在与任意Clojure序列一起使用
这些序列可能会也可能不会像向量那样公开随机访问。因此,在一般情况下,如果不遍历Clojure序列的最后一个元素,就无法访问该序列的最后一个元素,这将使以相反顺序遍历它成为不可能
我想你一定有这样的想法(类似Java的伪代码):
首先,正如Goran所说,
for
不是一个语句,它是一个表达式,即序列理解。它通过迭代其他序列来构造序列。因此,在形式上,它是纯函数(没有副作用).for的可以看作是增强的映射
注入了过滤器
。因此,它不能像reduce
那样用于保持迭代状态
其次,您可以使用for
和可变状态来表示序列反转,例如使用atom,这大致相当于java变量(不考虑其并发属性)。但这样做会面临几个问题:
您正在打破主语言范式,因此您的代码外观和行为肯定会变得更差
由于所有clojure可变状态单元都设计为线程安全,因此它们都使用某种非法的并发修改保护,并且无法删除它。因此,您将获得较差的性能特征
在这种特殊情况下,正如Goran所说,序列是广泛使用的Clojure抽象之一。例如,有一些惰性序列,它们可能是无限的,所以你无法将它们走到最后。使用命令式技术处理这些序列肯定会有困难
所以不要这样做,至少在Clojure:)
编辑:我忘了提了for
返回惰性序列,因此您必须以某种方式对其求值,以便应用在其中执行的所有状态变化。不这样做的另一个原因是:)以下是使用for反转字符串的方法:
(defn reverse-with-for [s]
(apply str
(for [i (range (dec (count s)) -1 -1)]
(get s i))))
请注意,此代码是无变异的。这与:
(defn reverse-with-map [s]
(apply str
(map (partial get s) (range (dec (count s)) -1 -1))))
更简单的解决办法是:
(apply str (reverse s))
理解。但是我想你可能会做一些非常棘手的事情,比如变异之外为定义的var。但是,doseq
可能更合适。@noahz:我想你可以这样做。我的编辑是指那个部分。但接下来,您将在命令式算法中使用可变状态。按照这种思路,您还可以用实际的Java编写一个纯Java代码,并通过互操作调用它。我并不总是反对命令式变异代码。我只是觉得用原始Java更容易实现。特别是因为互操作非常有效。请查看Alexandre的解决方案。性能很差,但这正是我想要的。事实上,原子相当快,在无争用的代码中,它们只是一个比较和设置java调用。在我的测试中,它们比(inc1)慢20倍。map+过滤器实际上仍然没有
的
强大for
更像是mapcat
的一个(可能重复)应用程序,实际上它同样强大。考虑编写<代码>(对于[x(范围10)y[:xx] y)< /> >作为<代码> MAP>代码>操作:您不能这样做,因为您希望返回两倍于给定的元素。谢谢您的澄清。我不知道for
的这种拼接功能。我写了关于
和map+filter的等价性的文章,考虑到Scala中类似的构造,我读到它等价于map+filter。这就是我一直在寻找的东西。无突变的奖金。谢谢。如果字符串支持rseq
,那就太好了,这样您就可以在不需要遍历字符串进行反转的情况下完成此操作。@amalloy是的。我在写这个答案的时候发现了你的邮件列表,并在谷歌上搜索了clojure字符串rseq。不过,反转字符串并不是必须经常做的事情。
(apply str (reverse s))