clojure';通俗lisp中的'into'

clojure';通俗lisp中的'into',clojure,common-lisp,sequence,Clojure,Common Lisp,Sequence,clojure有一个方便的(into to coll from coll)功能,将from coll中的元素添加到to coll,保留to coll的类型 如何在CommonLisp中实现这一点? 第一次尝试是 (defun into (seq1 seq2) (concatenate (type-of seq1) seq1 seq2)) 但是这个方法显然失败了,因为类型的在结果中包含了向量的长度,不允许添加更多的元素(从sbcl开始),尽管它仍然作为第一个参数用于list (对于空列表仍然

clojure有一个方便的
(into to coll from coll)
功能,将
from coll
中的元素添加到
to coll
,保留
to coll
的类型

如何在CommonLisp中实现这一点? 第一次尝试是

(defun into (seq1 seq2)
  (concatenate (type-of seq1) seq1 seq2))
但是这个方法显然失败了,因为
类型的
在结果中包含了向量的长度,不允许添加更多的元素(从sbcl开始),尽管它仍然作为第一个参数用于list
(对于空列表仍然失败)

问题是:是否可以在不使用通用方法和/或复杂的
类型的
结果处理(例如,删除向量/数组的长度等)的情况下构造此类函数


我同意将
into
作为
append
(与clojure相比,
into
的结果取决于目标集合类型)让我们称之为
concat into
在clojure中,在大多数情况下,当您将
用于
时,您对第一个集合的类型有一个具体的想法,因为它改变了语义:如果它是一个列表,其他元素将
conj
ed放在前面,如果它是一个向量,它们将
conj
ed放在后面,如果它是一个地图,你需要提供地图条目指示符(即实际地图条目或两个元素向量),集合更灵活,但也有自己的语义。这就是为什么我认为直接使用
连接
,显式地提供类型,对于许多用例来说可能已经足够好了

除此之外,我认为扩展此功能可能很有用(Common Lisp只有一组封闭的序列类型),但对于这一点,使用泛型函数似乎太方便了,不能忽略。提供一个可扩展、通用和高性能的解决方案并非易事


编辑:总结一下:不,你不能通过巧妙地应用一两个“内置”来实现这种行为,但你肯定可以使用通用函数编写一个可扩展的通用解决方案。

好的,除了通用方法之外,我想到的唯一一件事就是这个非常简单的函数:

(卸载到(目标源)
(let((目标类型)(etypecase目标
(向量(列表数组(数组元素类型目标)(*))
(列表))
(连接目标类型目标源)))
CL-USER>(进入(列表1 2 4)“asd”)
;;=> (1 2 4#\a#\s#\d)
CL-USER>(进入#*0010(列表1-0))
;;=> #*00101100
CL-USER>(进入“asdasd”(列表#\a#\b))
;;=> “asdasdab”
还有简单的
empty
impl:

(defun empty (target)
  (etypecase target
    (vector (make-array 0
                        :element-type (array-element-type target)
                        :adjustable t :fill-pointer 0))
    (list)))
结果确实(如前所述)没有确切的类型,而是“元素类型与目标元素类型相同的集合”。它不符合clojure的协议(其中应在
list
target前面加上前缀)


我看不出它有什么缺陷(如果有),所以很高兴听到这个。。不管怎样,因为这只是为了教育,那就行了。

into
是否有功能合同?命名使我猜测它是第一个参数的变种。@Sylwester,因为clojure中的集合是不可变的(通常),所以它的语义是“使用所有arg1元素创建arg1类型的新集合,并将所有arg2元素添加到其中”。但在这个问题的范围内,变异变量也会起作用,因为它更多地是关于我将使用的通用结果类型“推断”,它定义了不可变函数以及转换函数;没有直接等效于
的into
,但是您可以使用一个知道如何组合不同类型集合的通用函数轻松实现您想要的行为。虽然您的答案相当合理,但问题的重点还是有点具体:在clojure
中,into
的类型大致相同
(数据:T1,其他:T2):T1
,在这个签名的概念中,它更多的是关于“返回作为arg传递的确切类型”。也许clojure的
empty
可以更好地说明这一点。此外:一般来说,我会将问题缩小为“返回作为参数传递的序列的相同类型的序列,并且具有所需的长度”它的行为实际上不是确切的类型,而是没有长度信息的类型,正如您所发现的。您可以将其描述为同一个类,但这太不精确了。例如,在通用Lisp中,字符串是字符向量,因此它是秩1和元素类型字符的数组。因此,虽然它的类是数组的子类(例如,
simple array
),您可以在Common Lisp中执行
(concatenate'string…
)。当然,Clojure通常不执行元素类型,因为(我猜)这与它的原理背道而驰,但也因为Java并不真正支持它(“泛型”不起作用)。