I am trying to perform a DB migration with pgloader and I would like to define a custom lisp transformation file for a datetime, but I don't know LISP (!)

So I have cut&paste one of the pgloader transform functions and I tried to invoke it with no luck after spending a bunch of hours (!) in studying LISP.

I have extracted and simplified the function

(defun date-with-no-separator
    (date-string
     &optional (formato '((:year     0  4)
                          (:month    4  6)
                          (:day      6  8)
                          (:hour     8 10)
                          (:minute  10 12)
                          (:seconds 12 14))))
  "Apply this function when input date in like '20041002152952'"

  (let ((str-length      (length date-string))
        (expected-length (reduce #'max (mapcar #'third formato))))
    (print str-length)
    (print expected-length)))

I have changed format to formato in order to be sure that it is a variable and not the format LISP function. It seems to me that I have been right at least in this assumption. Am I?

I have tried:

(setq my-date "20041002152952")
(date-with-no-separator my-date)

and by running clisp test.lisp I got the output

14
14

and then I have done some failing attempts that you can see below with ANY LUCK:

(setq my-date "2004")
; (setf (get 'formato 'year) '(0 4))
(setq formato (#':year 0 4))

(date-with-no-separator my-date formato) ;(formato (:year 0 4))) ; '((12 16) (6 8) (1 3)) ))

At this time I just expect to get

4
4

when I set my-date to "2004" and my format to (:year 0 4) but also

10
10

when I set my-date to "01/01/1970" and my format to (:year 6 10) (:month 3 5) (:day 0 2)

I am a pythonist if it could be useful to make me understanding the topic with pythonic examples.

2

There are 2 answers

3
Martin Půda On BEST ANSWER

You're right, format is a variable here, but Common Lisp is Lisp2, so variables can have the same name as functions and you don't overwrite core function.

Optional argument formato is a list, containing triplets (keyword number number)- so if you want to provide your own format, it has to have exactly this form.

And you probably don't need setq here- you can write the values of arguments into a function call or use let.

Here are some examples:

> (date-with-no-separator "2004" '((:year 0 4)))

4 
4 
4

> (date-with-no-separator "01/01/1970" '((:year 6 10) (:month 3 5) (:day 0 2)))

10 
10 
10

> (let ((date "01/01/1970")
        (format '((:year 6 10) (:month 3 5) (:day 0 2))))
   (date-with-no-separator date format))

10 
10 
10
1
Rainer Joswig On

(setq formato (#':year 0 4))

Above makes no sense.

#':year is nothing useful:

  • #'foo denotes a function foo
  • :year denotes a keyword symbol.

( .... ) denotes a form to be evaluated, for example a function call.

(#':year 0 4) thus tries to call the function object :year, which does not exist and if it would exist, then it can't be called like this.

Remember: when you want to pass lists as data you have to quote them:

(:year 0 4) this is a list of three items: a keyword symbol and two integer numbers.

If you want to pass that as data you have to quote it:

(list '(:year 0 4)) -> ((:year 0 4))

If you want to have a list of lists you have either compute it or quote a list of lists:

computed:

(list '(:year 0 4)) -> ((:year 0 4))

or

(list (list :year 0 4)) -> ((:year 0 4))

quote it:

'((:year 0 4)) -> ((:year 0 4))

summary

this (setq formato (#':year 0 4)) should be:

(setq formato '((:year 0 4)))