Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

There's also the ultra-minimalist part. Picolisp has like one data structure, it's two cells with pointers, and that's it. Maybe symbols are implemented in some other way, I'm not sure, but pretty much everything is based around that.

Portability is not a concern. Either you run something 64 bit POSIX or you aren't going to use Picolisp (except if you get your hands on an old 32 bit build). I think it's usually tested by a user on OpenBSD but outside of Debian you're basically on your own.

There are like three basic data types. Fixnums, symbols and the linked list. If you do something similar to what you're showing from SBCL (or LispWorks, didn't read closely enough at first) it'll look pretty much like it does in source.

     $ pil +
     : (de myfun ()(prinl "yo")(prinl "world"))
     : (cdr myfun)
     -> ((prinl "yo") (prinl "world"))
     : myfun
     -> (NIL ((prinl "hey")) (prinl "world"))
     : (myfun)
     yo
     world
     -> "world"
     : (set (cdr myfun) '(prinl "hey"))
     -> (prinl "hey")
     : myfun
     -> (NIL (prinl "hey") (prinl "world"))
     : (myfun)
     hey
     world
     -> "world"
Hijacking the 'de mechanism is not something you'll do often, but looking at definitions like this you'll do a lot, and from time to time navigate it with list browsing functions.

It boils down to some very simple interpreter behaviours, and after some time surprises become quite rare. I find it takes off quite a bit of cognitive load when solving non-trivial scripting tasks compared to e.g. bash or Python. Especially since 'fork and 'in/'out are so easy to work with, with the former you just pass in an executable list, '((V1 V2 Vn)(code 'here)(bye)), with the latter you get a direct no-hassle connection to POSIX pipes.



LispWorks, I change the interpreted code:

    CL-USER 63 > (defun foo (a) (print 'hey) (print a))
    FOO

    CL-USER 64 > (foo 'jack)

    HEY 
    JACK 
    JACK

    CL-USER 65 > (function-lambda-expression 'foo)
    (LAMBDA (A) (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 81D03EFF03>)) (DECLARE (LAMBDA-NAME FOO)) (PRINT (QUOTE HEY)) (PRINT A))
    NIL
    FOO

    CL-USER 66 > (fifth *)
    (PRINT (QUOTE HEY))

    CL-USER 67 > (setf (fifth (function-lambda-expression 'foo)) '(print 'hello))
    (PRINT (QUOTE HELLO))

    CL-USER 68 > (foo 'jack)

    HELLO 
    JACK 
    JACK


Is the first line in the body executable?

  (LAMBDA (A) 
    (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 81D03EFF03>)) 
    (DECLARE (LAMBDA-NAME FOO)) 
    (PRINT (QUOTE HEY)) 
    (PRINT A))
If not, one would probably need to do a bit of fiddling to tear away the function from the symbol if one should feel a sudden urge to do so.

Perhaps similar to this:

    : (de myfun (D)(prinl "heyo") (prinl D))
    -> myfun
    : myfun
    -> ((D) (prinl "heyo") (prinl D))
    : (mapcar '((D) (prinl "heyo") (prinl D)) '("world"))
    heyo
    world
    -> ("world")
    : (mapcar '(NIL (prinl "hey")) '(lel))
    hey
    -> ("hey")
    : (car myfun)
    -> (D)
    : (cdr myfun)
    -> ((prinl "heyo") (prinl D))
    : (cons (car myfun) (cdr myfun))
    -> ((D) (prinl "heyo") (prinl D))
    : (mapcar (cons (car myfun) (cdr myfun)) '("world"))
    heyo
    world
    -> ("world")
Mostly I use this to get at an implementation so I can test it or a portion of it against some particular value, or just to see how something works. Most builtins are implemented in assembler and their symbols only return a pointer, but for example 'doc is implemented in Picolisp:

    : doc
    -> ((Sym Browser) (raw T) (call (or Browser (sys "BROWSER") "w3m") (pack "file:" (and (= 47 (char (path "@"))) "//") (path (if (get Sym 'doc) (pack @ "#" Sym) "@doc/ref.html")))) (raw NIL))
    : de
    -> 270351
    : macro
    -> ("Prg" (run (fill "Prg")))
I really like the Picolisp 'match (https://software-lab.de/doc/refM.html#match ) function. What's the easiest way to do the same in Common Lisp? If it's not obvious from the examples there, it can also be used with character lists, i.e. transient symbols, i.e. strings, chopped up into a list of UTF-8 characters. It's similar to unification in logic programming, which is something Picolisp supports.


LispWorks:

    CL-USER 130 > (defun myfun (d) (print "heyo") (print d))
    MYFUN

    CL-USER 131 > (let ((source (function-lambda-expression #'myfun)))
                    (mapcar (eval (list* 'lambda
                                         (second source)
                                         (nthcdr 4 source)))
                            '("world")))

    "heyo" 
    "world" 
    ("world")
Above can in some ways done in many Lisp implementations. It's in this form simply not widely used. For most applications it's more interesting to use macros to manipulate code, which then can be compiled to efficient code.

Pattern matching is much implemented in Lisp.

I had adopted this code for a pattern matcher from a book (LISP, Winston/Horn), probably >30 years ago:

    CL-USER 115 > (pmatch:match '(#$a is #$b) '(this is a test))
    ((B (A TEST)) (A (THIS)))

    CL-USER 116 > (pmatch:match '(#$X (d #$Y) #$Z) '((a b c) (d (e f) g) h i))
    ((Z (H I)) (Y ((E F) G)) (X ((A B C))))
Not to say, that Picolisp isn't great for you, but it is not the only language where lists can be manipulated.


"Not to say, that Picolisp isn't great for you, but it is not the only language where lists can be manipulated."

Don't think I've made this claim.

Can the #$a &c. be used as variables?

    : (and (match '("h" "e" "l" "l" "o" @A ~(chop "ld")) (chop "helloworld")) @A) 
    -> ("w" "o" "r")


> Don't think I've made this claim.

That's true, but it sounds a bit as if Lisp interpreters are something very unusual. The syntax and other details may differ, but the general idea of executing source code via an interpreter is very old, often implemented - similar also the idea that the code can be mutable. It's just not very fashionable, since some Lisp dialects are designed such that one wants the compiler to be able to statically check the code for various things, before runtime.

In Common Lisp we would not want to introduce variables into an outer scope by enclosed functions. One would explicitly set up a scope.

Example: this is a macro example, which creates a scope, where the matching match-variables are also Lisp variables.

    CL-USER 165 > (pmatch:when-match (append (coerce "hello" 'list)
                                             '(#$a)
                                             (coerce "ld" 'list))
                      (coerce "helloworld" 'list)
                      (length a))

    3




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: