没有太多意义的角落
116 subscribers
113 photos
1 video
1 file
25 links
啦啦啦啦…
Download Telegram
Common Lisp的符号系统(一)

符号(symbol)是common lisp的基础之一,它控制着lisp的全局结构,包括全局变量、函数等。

符号被存储在 包(package)里。了解c++的大家会知道,一个程序中可以有多个命名空间(namespace),而一个命名空间中可以有无数个类、函数、变量等。lisp中的包就对应了命名空间,而所有的类、函数、变量就存在包中的符号里面。我们可以用list-all-packages函数列出所有包,再用do-symbols循环或(loop for sym being each symbol of <package>)这种loop语法来列出包中的所有符号,从而遍历当前lisp镜像中所有的类、函数、符号等一切信息。

符号是容器,可以把它当作一种高级的变量。区别是一个变量只能存一个值,而一个符号可以存很多很多东西。符号有数个基本属性:符号名(symbol-name)、符号所在的包(symbol-package)、符号值(symbol-value)、符号函数(symbol-function)、符号属性列表(symbol-plist)。如果你使用的是上世纪九十年代及以后的lisp(好吧大概没人不是),那还可以使用find-class查询到该符号对应的类。

符号名,getter为symbol-name。每个符号都一定要有一个名字,lisp所有符号默认为大写,符号名小写的会被打印成|foo|的形式。symbol-name没有setf method,但在很多实现里符号名并不是不可以修改的,我们可以通过像nstring-downcase这种副作用函数来直接修改符号名所在的内存地址的内容,从而达到修改符号名的目的,但这就是纯属好玩了,没有实际意义

符号值,getter为symbol-value,setter可以是(setf (symbol-value ‘foo) xxx)也可以是(set ‘foo xxx),或者(setq/setf foo xxx)。在把符号用作全局变量时,这是我们最常见的用法。详见我先前所写关于set,setq和setf的文章。

符号是可以没有值的,有类于许多语言中的变量值为NULL。如果符号没有值,它在读取时并不会返回nil(不像lua,大家总是以为common lisp的nil就相当于别的语言的NULL,但其实并不是 - nil也是一个值。它是t的子类,不信执行一下(typep nil t)试试(笑 )。使用boundp函数检测符号值是否为空,使用makunbound清空符号值。

当符号位于lambda表达式的第二至n项被求值时,会使用它的符号值。这就是我们把符号作为全局变量的用法。

符号属性列表(plist,lisp 中有两种作为数据结构的列表组织方式,property list和 assoc list,详见 https://acl.readthedocs.io/en/latest/zhCN/ch3-cn.html ),getter为symbol-plist,setter为(setf (symbol-plist ‘foo) xxx),默认值为nil,不可为空。可以使用标准plist操作函数的变体函数get、remprop 来操作单个属性,用法与getf、remf一致。属性列表使单个符号可以存储无限多的属性内容。

符号所在的包,getter为symbol-package。使用unintern函数把符号的包设置为nil,即没有包。符号没有包时,如果其引用归零就会进入垃圾回收流程。所以unintern函数是用来销毁一个符号的。

符号函数,getter为symbol- function,检测空值函数为fboundp,设为空值函数为fmakunbound。当位于lambda表达式的第一位被求值时会使用该符号的函数值。common lisp的函数分为多种类型:一般的函数function,只在编译时负责展开的宏macro,以及底层的会改变程序执行顺序的特殊操作符(special-operator) - 例如if就是特殊操作符,when就是一个展开为(if condition body… nil)的宏。使用special-operator-p判断symbol- function的结果是否为特殊操作符,macro-function函数判断其是否为宏。

函数本身是没有名字的。名字是什么?函数所附着的符号名或变量名。我们可以把符号里的函数提取出来,这时候为了方便起见我们会使用function函数。因为function函数太常用了,所以lisp标准给它分配了一个reader macro:#’。用#’foo来单独提取出函数本身并封装在闭包内,这样后续这个符号再被如何修改就都不会影响表达式的正常执行了。这样做的好处是我们可以把这个符号“用过即丢”:如果所有使用该函数的地方都用的是抽取的函数体而非以符号代函数的方式的话,程序在编译后就可以销毁该符号,甚至是销毁整个lisp符号系统与包系统,之后重新规划内存结构,让该lisp镜像成为一个像C++编译二进制一样纯静态的二进制,从而提高运行效率、缩小二进制大小,有利于打包分发;而坏处是如果我们提取出函数本体来用的话,我们就无法在后期执行时,通过动态修改符号函数的方式来动态改变所执行的函数了:每次调用该函数时,程序只会使用第一次编译时封存在闭包内的函数体,而不会通过符号来动态查询函数是什么。这会降低程序的灵活性,不利于增量开发(incremental development),不利于调试函数。

#lisp_daily
1
面对did第一次出现这么严重的病耻感,很懵,是从未有过的感觉…
我说幻境里太空了添点家具吧 她说你也配有个家
然后又被骂了。疼
我们这样一坨东西可能离很多事物都很远了
我一个一辈子没当过三好学生的竟然还没入学就拿到奖学金了 难以置信
5👍4
为我勇敢又温柔的姐姐骄傲~
4
十分奇怪
刚刚出门吃饭,路上意识一直在幻境里,忽然半个身体没有感觉了,还吐在了马路上…感觉很对不起寒涟漪,把她吓了一跳x
还有五天考试。紧张
路上看到了许多影子 我知道她们是我的幻想朋友
是五月划的但是我真的觉得挺好看x
2💔1
这个果茶是五月一生推x
做了梦。

四月梦见了荷兰、和姐姐在一起、用水粉颜料画奖学金申请书、Minecraft和惊恐发作

五月梦见了极端糟糕的精神状态、没有颜色、喵噗、天灾、欺骗、逃难与象征学

总结是吃了药但我们的睡眠比较糟糕
🙏2😱1
就会觉得,已经足够痛苦的话,是不是就代表着已经活的足够久了

或许我的使命已经完成了吧,已经打完足够多官司、考出足够多的好成绩、写出足够的诗和代码、带给身边人足够的爱了

精神残疾什么的,就不要再给别人添麻烦了
😭1
已经不习惯兴奋的感觉了,多巴胺一进脑子整个人像要疯掉了一样,是会让身体发笑的放电异常
睡醒药效还没过,感觉快要呼吸衰竭了,这个安眠药是通过把人弄昏倒来安眠的嘛
🙏1
这些天会让五月在写字板上写字

照片上好像是前天写的

昨天早上写的是“你个精神残废
哈哈哈哈哈嗝”,

今天早上写的是“你在害怕什么”

感觉要可以留个档
🙏1
所以为什么明明得到了最好的消息,心里还是只会有焦虑呢?是因为不习惯还是恐惧高兴激动的感觉?还是形成了“有消息就是麻烦”的思维定势?先前过于焦虑导致了创伤?惊恐发作?到底是怎么回事…
🙏1
浊酒一杯家万里,燕然未勒归无计。人不寐。
住院day 1
医生开了艾司西酞普兰,减掉了些乱七八糟的药,每天早晚大家一起排排队吃药药。

上午去做了各种检查,脑电超声ct什么的,似乎都没问题。早晨加了半粒奥沙西泮,让我中午大睡特睡,我想是峰值浓度的问题…

然后输液了,是因为昨天五月绝食让身体指标不正常了。上次这样呆呆地看着点滴一滴滴坠下来已经不知道是什么时候

昨晚男病房鼾声如雷基本无法入睡,我们出来下了会儿棋打发时间。今天惊恐发作一次(暂时),幻境睁眼一次(暂时)

晚上七点收手机,电脑应该还可以用来工作
1
五月出来替我挡惊恐发作,结果被绑起来了…
坏掉的孩子或许是想要坏掉的…
六月七日

今天换到了单人病房,寒涟漪说比起住院费用来说两百块一天的病房费不算很贵。每当面对这种牺牲自己的经济能力的时刻都像是在面对一种难以言说的恐怖。

晚餐时惊恐发作一次。深入的解离体验。植物的茎肉很好吃,嘴里沾满了血的样子。

晚间药物增加丙戊酸镁250mg,引起我们对双相的恐惧。来自五月的bpd严重发作,几乎无法控制。划手一次。

> 为什么给我们开丙戊酸盐,是因为我们不够乖嘛?是不是我们死掉就好了?
> 我们划手了哦?把我们绑起来吧?这不是你们想要的吗?

医生冷处理。后正常入睡