这个宏的递归定义做了它应该做的事情(从1到n的总和):
(defmacro sum-int-seq (n)
`(cond
((equal 0 ,n) 0)
(t (+ ,n (sum-int-seq (- ,n 1))))))
Run Code Online (Sandbox Code Playgroud)
例如(sum-int-seq 5)给出15.
但为什么它有效呢?当宏扩展时,我得到这个:
(macroexpand '(sum-int-seq 5))
(IF (EQUAL 0 5) 0 (+ 5 (SUM-INT-SEQ (- 5 1))))
Run Code Online (Sandbox Code Playgroud)
但是因为sum-int-seq是一个宏,所以宏评估应该变成一个无限循环.编译器是否创建了递归函数?如果这个定义创建了一个递归函数,有没有办法以递归方式定义宏?
(为简洁起见,这是一个愚蠢的例子,一个函数当然会更好地工作)
以下示例在Paul Grahams ANSI Common Lisp中给出,作为封装的示例:
(defpackage "CTR"
(:use "COMMON-LISP")
(:export "COUNTER" "INCREMENT" "CLEAR"))
(in-package ctr)
;function definitions here
Run Code Online (Sandbox Code Playgroud)
然而,在Peter Seibels Practical Common Lisp中,链接到这里,他说:
由于读取器使用了包,因此必须先定义包,然后才能对包含切换到该包的IN-PACKAGE表达式的文件进行LOAD或COMPILE-FILE操作.在其他DEFPACKAGE表单可以引用它们之前还必须定义包...在需要时确保包存在的最好的第一步是将所有DEFPACKAGE文件与需要在这些包中读取的代码分开放置
所以他建议为每个包创建两个文件,一个用于defpackage,一个用于代码.包含defpackages的文件应该以(包内"COMMON-LISP-USER")开头.
对我来说,似乎在包内和代码之前将defpackage放在同一个文件中是确保在使用之前定义包的好方法.所以第一种方法,将所有内容收集到一个文件中似乎更容易 使用此方法创建包时是否有任何问题?
我有这个(not (some #(= (:length %1) 0) %))作为后置条件.写得这样很清楚,但是如果不满足这个条件,我得到这个:
Assert failed: (not (some (fn* [p1__17852#] (= (:length p1__17852#) 0)) %))
Run Code Online (Sandbox Code Playgroud)
哪个不太可读.有没有办法为后置条件或前置条件定义消息?
编辑1:
遵循noahlz和noisesmiths建议,(但使用外部命名函数):
(defn not-zero-length
[evseq]
(not (some (fn [item] (= (:length item) 0)) evseq)))
(defn my-func
[evseq]
{:post [(not-zero-length %)]}
evseq)
(my-func '({:length 3}{:length 0}))
Run Code Online (Sandbox Code Playgroud)
得到:
AssertionError Assert failed: (not-zero-length %)
Run Code Online (Sandbox Code Playgroud)
哪个更清楚.
我正在尝试在 React 中设置一个控件contentEditable。每次我在 div 中写入内容时,组件都会重新渲染,并且光标/插入符会跳回开头。我试图通过将光标保存在onInput回调中来处理这个问题:
import { useState, useEffect, useRef, useLayoutEffect } from 'react'
function App() {
const [HTML, setHTML] = useState()
const [selectionRange, setSelectionRange] = useState()
console.log('on rerender:', selectionRange)
useLayoutEffect(() => {
console.log('in layout effect', selectionRange)
const selection = document.getSelection()
if (selectionRange !== undefined) {
selection.removeAllRanges()
selection.addRange(selectionRange)
}
})
function inputHandler(ev) {
console.log('on input', document.getSelection().getRangeAt(0))
setSelectionRange(document.getSelection().getRangeAt(0).cloneRange())
setHTML(ev.target.innerHTML)
}
return (
<>
<div
contentEditable
suppressContentEditableWarning
onInput={inputHandler}
dangerouslySetInnerHTML={{ __html: HTML }}
>
</div>
<div>html:{HTML}</div>
</>
)
} …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种方法来提取常见的lisp中列表的所有元素.像这样
[194]> (break-out-of-list '(a b c d))
A
B
C
D
Run Code Online (Sandbox Code Playgroud)
编辑:我给出的用法示例并没有很好地考虑,但我仍然很好奇是否有可能突破列表,如上例所示.
我正在尝试使用paredit中的一些函数,而不加载所有的键绑定.看看paredit.el,我找到的唯一键盘映射是paredit-mode-map,所以我尝试了这个.
(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-M-left>") 'paredit-backward)
Run Code Online (Sandbox Code Playgroud)
它没有改变键绑定(用Ch k检查),但变量paredit-mode-map被改变了.
我也试过了
(eval-after-load "paredit"
'(progn
(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-M-left>") 'paredit-backward)))
Run Code Online (Sandbox Code Playgroud)
然后打开和关闭paredit,结果相同.
以前,直接对键映射进行更改一直对我有用.这里发生了什么?
编辑:
我通过这样做成功地更改了键盘映射:
; Remove old paredit bindings
(defun take-from-list (condp list)
"Returns elements in list satisfying condp"
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) list)))
(setq minor-mode-map-alist
(take-from-list
(lambda (x) (not (eq (car x) 'paredit-mode)))
minor-mode-map-alist))
; Create new paredit-mode-map
(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-kp-enter>") 'paredit-backward)
; Add the new …Run Code Online (Sandbox Code Playgroud) 我想获取我在 lisp 会话中创建的所有变量的列表。我认为这应该可以通过查看 common-lisp-user 中的所有符号来实现。但是我怎样才能得到这样的清单呢?
运行此按预期工作:
(defn long-seq [n]
(lazy-seq (cons
(list n {:somekey (* n 2)})
(long-seq (+ n 1)))))
(take 3 (long-seq 3))
; => ((3 {:somekey 6}) (4 {:somekey 8}) (5 {:somekey 10}))
Run Code Online (Sandbox Code Playgroud)
但是我想用矢量做同样的事情:
(defn long-seq-vec [n]
(lazy-seq (into
(vector (list n {:somekey (* n 2)}))
(long-seq-vec (+ n 1)))))
(take 3 (long-seq-vec 3))
Run Code Online (Sandbox Code Playgroud)
这给了我一个堆栈溢出.为什么?
在Clojure Programming(OReilly)中,有一个示例,其中java.io.BufferedWriter和java.io.Printwriter都放在代理中(每个代理一个代理).然后将这些内容写入代理操作中.该书说,在代理行动中执行io是安全的.据我所知,在代理行动中所有副作用操作都可以.这是因为提交内的代理操作仅在提交成功时才会运行.其他代理操作中的代理操作仅在外部代理操作成功完成后运行.一般来说,代理操作可以保证连续应用.
Clojure 文档说:"代理的状态本身应该是不可变的......".
据我所知,原子和引用必须保持不可变值的原因是clojure可以回滚并重试多次提交.
我不明白的是:
1:如果Clojure确保代理操作只运行一次,为什么代理值必须是不可变的.(例如,如果我在代理中持有一个java数组,并在代理操作中添加它,这应该没问题,因为该操作只会运行一次.这与向BufferedWriter添加行非常相似)
2:java.io.BufferedWriter被认为是不可变的吗?我知道你可以有一个稳定的引用,但如果代理操作在它上面执行io,它是否仍然被认为是不可变的?
3:如果BufferedWriter被认为是不可变的,我如何判断其他类似的java类是否是不可变的?
我想将Cx-insert绑定到命令.这有效:
(global-set-key [\C-insert] 'my-func)
Run Code Online (Sandbox Code Playgroud)
但这不是:
(global-set-key [\C-x-insert] 'my-func)
Run Code Online (Sandbox Code Playgroud) common-lisp ×4
lisp ×4
clojure ×3
elisp ×2
emacs ×2
caret ×1
concurrency ×1
javascript ×1
list ×1
macros ×1
package ×1
paredit ×1
reactjs ×1
recursion ×1