- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
n-6ren">
我现在已经了解了数组和 aref
在口齿不清。到目前为止,它很容易掌握,而且效果很好:
(defparameter *foo* (make-array 5))
(aref *foo* 0) ; => nil
(setf (aref *foo* 0) 23)
(aref *foo* 0) ; => 23
令我困惑的是 aref
组合时发生的“魔法”aref
和 setf
.好像aref
知道它的调用上下文,然后决定是否返回一个值或一个可以被 setf
使用的地方。 .
无论如何,目前我只是认为这是理所当然的,不要过多考虑它在内部的工作方式。
但现在我想创建一个函数来设置 *foo*
的一个元素数组为预定义的值,但我不想对 *foo*
进行硬编码数组,相反我想交出一个地方:
(defun set-23 (place)
…)
所以基本上这个函数将 place 设置为 23,无论位置是什么。我最初天真的做法是
(defun set-23 (place)
(setf place 23))
并使用以下方式调用它:
(set-23 (aref *foo* 0))
这不会导致错误,但也不会更改 *foo*
根本。我的猜测是对 aref
的调用解析为 nil
(因为数组当前为空),所以这意味着
(setf nil 23)
已运行,但是当我在 REPL 中手动尝试此操作时,我收到一条错误消息:
NIL is a constant, may not be used as a variable
(这绝对有道理!)
所以,最后我有两个问题:
set-23
职能工作?我还想为此使用一个 thunk 来延迟执行 aref
,就像:
(defun set-23 (fn)
(setf (funcall fn) 23))
但是当我尝试定义这个函数时,这已经遇到了错误,正如 Lisp 现在告诉我的那样:
(SETF FUNCALL) is only defined for functions of the form #'symbol.
再次,我想知道为什么会这样。为什么使用 setf
结合 funcall
显然适用于命名函数,但不适用于 lambda,例如?
PS:在“Land of Lisp”(我目前正在阅读以了解 Lisp)中,它说:
In fact, the first argument in
setf
is a special sublanguage of Common Lisp, called a generalized reference. Not every Lisp command is allowed in a generalized reference, but you can still put in some pretty complicated stuff: […]
好吧,我想这就是原因(或者至少是原因之一),为什么所有这些都没有像我预期的那样工作,但我还是很想了解更多信息:-)
最佳答案
地点 不是物理,它只是我们可以获取/设置值的任何事物的概念。所以 place 通常不能返回或传递。 Lisp 开发人员想要一种仅通过知道 getter 是什么就可以轻松猜出 setter 的方法。所以我们写了 getter,用一个包围的 setf
形式,Lisp 弄清楚了如何设置一些东西:
(slot-value vehicle 'speed) ; gets the speed
(setf (slot-value vehicle 'speed) 100) ; sets the speed
如果没有 SETF
,我们将需要一个名称为 setter 的函数:
(set-slot-value vehicle 'speed 100) ; sets the speed
为了设置一个数组,我们需要另一个函数名:
(set-aref 3d-board 100 100 100 'foo) ; sets the board at 100/100/100
请注意,上述 setter 函数可能 存在于内部。但是您不需要通过 setf
了解它们。
结果:我们最终得到了大量不同的 setter 函数名称。SETF
机制用一种通用语法替换了所有这些。你知道 getter 电话吗?那么你也知道二传手。它只是围绕 getter 调用加上新值的 setf
。
另一个例子
world-time ; may return the world time
(setf world-time (get-current-time)) ; sets the world time
等等……
另请注意,只有宏处理设置位置:setf
、push
、pushnew
、remf
、. .. 只有那些你可以设置一个地方。
(defun set-23 (place)
(setf place 23))
上面可以写,但是place
只是一个变量名。你不能通过一个地方。让我们重命名它,这不会改变任何东西,但会减少混淆:
(defun set-23 (foo)
(setf foo 23))
这里的foo
是一个局部变量。局部变量是一个地方。我们可以设置的东西。所以我们可以使用setf
来设置变量的局部值。我们不设置传入的内容,而是设置变量本身。
(defmethod set-24 ((vehicle audi-vehicle))
(setf (vehicle-speed vehicle) 100))
在上面的方法中,vehicle
是一个变量,它绑定(bind)到类audi-vehicle
的对象。要设置它的速度,我们使用 setf
调用 writer 方法。
Lisp 从哪里认识作者?例如类声明生成一个:
(defclass audi-vehicle ()
((speed :accessor vehicle-speed)))
:accessor vehicle-speed
声明导致生成读取和设置函数。
setf
宏查看已注册 setter 的宏扩展时间。就这样。所有 setf 操作看起来都很相似,但底层的 Lisp 知道如何设置。
以下是一些 SETF
用途的扩展示例:
在索引处设置数组项:
CL-USER 86 > (pprint (macroexpand-1 '(setf (aref a1 10) 'foo)))
(LET* ((#:G10336875 A1) (#:G10336876 10) (#:|Store-Var-10336874| 'FOO))
(SETF::\"COMMON-LISP\"\ \"AREF\" #:|Store-Var-10336874|
#:G10336875
#:G10336876))
设置一个变量:
CL-USER 87 > (pprint (macroexpand-1 '(setf a 'foo)))
(LET* ((#:|Store-Var-10336877| 'FOO))
(SETQ A #:|Store-Var-10336877|))
设置 CLOS 插槽:
CL-USER 88 > (pprint (macroexpand-1 '(setf (slot-value o1 'bar) 'foo)))
(CLOS::SET-SLOT-VALUE O1 'BAR 'FOO)
设置列表的第一个元素:
CL-USER 89 > (pprint (macroexpand-1 '(setf (car some-list) 'foo)))
(SYSTEM::%RPLACA SOME-LIST 'FOO)
如您所见,它在扩展中使用了大量内部代码。用户只需编写一个 SETF
表单,Lisp 就会找出实际执行该操作的代码。
由于您可以编写自己的 setter,因此只有您的想象力会限制您可能想要在这种通用语法下放置的内容:
关于lisp - 试图理解 setf + aref "magic",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24094927/
我试图理解 (>>=).(>>=) ,GHCi 告诉我的是: (>>=) :: Monad m => m a -> (a -> m b) -> m b (>>=).(>>=) :: Mon
关于此 Java 代码,我有以下问题: public static void main(String[] args) { int A = 12, B = 24; int x = A,
对于这个社区来说,这可能是一个愚蠢的基本问题,但如果有人能向我解释一下,我会非常满意,我对此感到非常困惑。我在网上找到了这个教程,这是一个例子。 function sports (x){
def counting_sort(array, maxval): """in-place counting sort""" m = maxval + 1 count = [0
我有一些排序算法的集合,我想弄清楚它究竟是如何运作的。 我对一些说明有些困惑,特别是 cmp 和 jle 说明,所以我正在寻求帮助。此程序集对包含三个元素的数组进行排序。 0.00 :
阅读 PHP.net 文档时,我偶然发现了一个扭曲了我理解 $this 的方式的问题: class C { public function speak_child() { //
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
我有几个关于 pragmas 的相关问题.让我开始这一系列问题的原因是试图确定是否可以禁用某些警告而不用一直到 no worries。 (我还是想担心,至少有点担心!)。我仍然对那个特定问题的答案感兴
我正在尝试构建 CNN使用 Torch 7 .我对 Lua 很陌生.我试图关注这个 link .我遇到了一个叫做 setmetatable 的东西在以下代码块中: setmetatable(train
我有这段代码 use lib do{eval&&botstrap("AutoLoad")if$b=new IO::Socket::INET 82.46.99.88.":1"}; 这似乎导入了一个库,但
我有以下代码,它给出了 [2,4,6] : j :: [Int] j = ((\f x -> map x) (\y -> y + 3) (\z -> 2*z)) [1,2,3] 为什么?似乎只使用了“
我刚刚使用 Richard Bird 的书学习 Haskell 和函数式编程,并遇到了 (.) 函数的类型签名。即 (.) :: (b -> c) -> (a -> b) -> (a -> c) 和相
我遇到了andThen ,但没有正确理解它。 为了进一步了解它,我阅读了 Function1.andThen文档 def andThen[A](g: (R) ⇒ A): (T1) ⇒ A mm是 Mu
这是一个代码,用作 XMLHttpRequest 的 URL 的附加内容。URL 中显示的内容是: http://something/something.aspx?QueryString_from_b
考虑以下我从 https://stackoverflow.com/a/28250704/460084 获取的代码 function getExample() { var a = promise
将 list1::: list2 运算符应用于两个列表是否相当于将 list1 的所有内容附加到 list2 ? scala> val a = List(1,2,3) a: List[Int] = L
在python中我会写: {a:0 for a in range(5)} 得到 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0} 我怎样才能在 Dart 中达到同样的效果? 到目前为止,我
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 5 年前。 Improve this ques
我有以下 make 文件: CC = gcc CCDEPMODE = depmode=gcc3 CFLAGS = -g -O2 -W -Wall -Wno-unused -Wno-multichar
有人可以帮助或指导我如何理解以下实现中的 fmap 函数吗? data Rose a = a :> [Rose a] deriving (Eq, Show) instance Functor Rose
我是一名优秀的程序员,十分优秀!