就在最近,我一直在玩lisp,我正在尝试创建一个通用的本地数据库,我正在按照另一个涵盖大部分此类项目的教程,但我决定我想加入一个简单的"特征。
我尝试以自定义格式生成时间戳,并将它们保存为字符串。我尝试将格式生成的字符串存储到使用 defvar 声明的变量中,方法是将变量作为第一个参数调用 format ,但不是保存完整的输出,我只是得到了一个月的那一天。这是我的代码:
(defun date ()
(setq *SUPPRESS-SIMILAR-CONSTANT-REDEFINITION-WARNING* 1)
(defconstant *day-names*
'("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"))
*DAY-NAMES*
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(defvar datetime)
(format datetime "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour
minute
second
(nth day-of-week *day-names*)
month
date
year
(- tz)
(return-from date datetime))))
(defun make-entry (category subject idea info researched)
(defvar date (date))
(list :category category :subject subject :date date :idea idea :info info :researched researched))
生成条目中日期的预期值应类似于 2014年7月30日星期三21:28:18(GMT-7)< / strong>,但我最终只有30,而不是剩下的。此外,我已经测试找到返回的30的类型,它确实是一个整数,而不是char-stream(字符串)应该是。因此,我确信这与格式中的&#34;〜d&#34;有关,但我可能错了。实际上,我只是试图将系统时间的格式化版本传递给make-entry。
答案 0 :(得分:5)
好的。 [Dons代码审查帽]
首先,让我们更加一致地缩进。你确实做了比典型的lisp-newbie在缩进时做得更好的事情,但是把大部分内容冲到了一列。缩进级别可以为您提供有关程序控制流程的大量提示。一旦你习惯了,我的意思是。
(defun date ()
(setq *SUPPRESS-SIMILAR-CONSTANT-REDEFINITION-WARNING* 1)
(defconstant *day-names*
'("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"))
*DAY-NAMES*
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(defvar datetime)
(format datetime "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week *day-names*)
month date year
(- tz)
(return-from date datetime))))
(defun make-entry (category subject idea info researched)
(defvar date (date))
(list :category category :subject subject :date date :idea idea :info info :researched researched))
您可以但不应在本地使用defconstant
和defvar
。您可以使用let
创建这些顶级表单,也可以使其成为本地定义。在您的情况下,constant
作为全局变得有意义,而var
应该是一个局部变量(稍后会更多)。此外,既然您没有在每个函数调用中重新定义常量,那么您就不需要压制该重定义警告。
(defconstant *day-names* '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"))
(defun date ()
*DAY-NAMES*
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(let ((datetime))
(format datetime "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week *day-names*)
month date year
(- tz)
(return-from date datetime)))))
Lisp表单自动返回它计算的最后一个值,但任何早期的表单只会产生副作用而不是值。具体来说,*DAY-NAMES*
在date
开头没有任何作用。此外,由于您似乎试图从datetime
返回date
,因此您无需致电return-from
。相反,只需评估datetime
。
(defun date ()
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(let ((datetime))
(format datetime "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week *day-names*)
month date year
(- tz))
datetime)))
format
将流作为其第一个参数。变量不是流(虽然它可能包含一个;你的不是)。你似乎想要做的是将当前时间作为字符串返回,根据你的format
指令进行格式化。要做到这一点,你根本不需要中间值。只需将NIL
作为第一个参数传递给format
,然后它会自动创建一个包含您内容的新字符串,然后将其返回。
(defun date ()
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(format nil "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week *day-names*)
month date year
(- tz))))
此时,date
似乎做了一些有意义的事情。
cl-user> (date)
"15:39:12 Thursday 7/31/2014 (GMT-5)"
cl-user>
由于您只是尝试将某些值放入列表中,因此您也不需要创建局部变量来将(date)
的结果保存在make-entry
中。< / p>
(defun make-entry (category subject idea info researched)
(list :category category :subject subject :date (date) :idea idea :info info :researched researched))
此时,make-entry
返回plist
,其:DATE
值是来自date
的相应格式化字符串。
cl-user> (make-entry "something" "something else" "blah" "bleeh" "stop using side effects")
(:CATEGORY "something" :SUBJECT "something else" :DATE
"15:41:57 Thursday 7/31/2014 (GMT-5)" :IDEA "blah" :INFO "bleeh" :RESEARCHED
"stop using side effects")
cl-user>
(defconstant *day-names* '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"))
(defun date ()
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(format nil "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week *day-names*)
month date year
(- tz))))
(defun make-entry (category subject idea info researched)
(list :category category :subject subject :date (date) :idea idea :info info :researched researched))
如果您跟随the PCL database chapter一起关注,请记住,当您阅读数据库时,需要再次解码以这种方式格式化的日期,假设您为&#39 ;重新计划做除字符串比较以外的任何事情。因此,根据您的具体用例,存储(get-universal-time)
的原始输出实际上更有意义。
答案 1 :(得分:1)
(defconstant *day-names*
'("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"))
(defun date ()
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(declare (ignore dst-p))
(format nil "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week *day-names*)
month date year (- tz))))
(defun make-entry (category subject idea info researched)
(list :category category
:subject subject
:date (date)
:idea idea
:info info
:researched researched))
然后
? (date)
"21:13:25 Thursday 7/31/2014 (GMT+1)"
? (make-entry "Lisp" "format" "read more" "CLHS" "not yet")
(:CATEGORY "Lisp" :SUBJECT "format" :DATE "21:19:42 Thursday 7/31/2014 (GMT+1)" :IDEA "read more" :INFO "CLHS" :RESEARCHED "not yet")
一些评论:
defvar
声明局部变量,这不符合您的想法 - 使用let
,甚至更好,避免它们return-from
;该函数返回最后评估的表单,在本例中为format
(declare (ignore ...))
以避免编译错误答案 2 :(得分:1)
此代码存在许多问题,但最大的问题是format
的一个参数是(return-from …)
:
(format datetime "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour
minute
second
(nth day-of-week *day-names*)
month
date
year
(- tz)
(return-from date datetime))
将其与:
进行比较CL-USER> (defun foo ()
(list 1 2 3 (return-from foo 4)))
FOO
CL-USER> (foo)
4
大多数情况下,您不需要做任何特殊操作来从函数返回值;最后一个表达式的值是函数的结果。这样的东西就足够了,因为当格式的第一个参数是 nil 时,你会得到一个字符串:
(defconstant +day-names+ ; Some people put + around constants
'("Monday" "Tuesday" "Wednesday" ; but it's not as a strong a convention
"Thursday" "Friday" "Saturday" "Sunday")) ; as * around dynamic variables.
(defun date ()
(multiple-value-bind (second minute hour date month year day-of-week dst-p tz)
(get-decoded-time)
(declare (ignore dst-p))
;; The value of (format ...) is returned from the date.
(format nil "~2,'0d:~2,'0d:~2,'0d ~a ~d/~2,'0d/~d (GMT~@d)"
hour minute second
(nth day-of-week +day-names+)
month date year (- tz))))
CL-USER> (date)
"15:36:40 Thursday 7/31/2014 (GMT-5)"
顺便说一句,虽然这有效,但从长远来看,使用某些外部标准格式的日期(例如,由XSD dateTimes指定)可能对您更有用。为此,您可能会找到外部库,例如those for time listed on CLiki中的一些有用。