Isn't this very confusing in almost all instances?
It's really not useful for variables, but can be very useful for functions, and since they're pretty much the same thing, you get the behavior for free. Although I haven't touched Lisp, my understanding is that Forth and Lisp have some conceptual similarities, but Forth is written by an engineer and Lisp by a computer scientist. Limit you for your own safety? Not a thing in Forth.
How is this less confusing? := vs = will either push a new variable on top of a stack of identically named variables, or change the content of the top element on that stack? Why would anyone want any of that? Shadow variables are usually associated with hard-to-find-bugs, (i.e. forgetting that there is already a variable named 'xyz' in the current scope) not some great feature we want more of..
Anyway again very inspiring :)
People who use lisp like the parentheses.
I don't, though they're no more objectionable than all the {}; languages. I just don't like unnecessary punctuation.
I coded in scheme for years using a preprocessor that understood
define-syntax opt
syntax-rules |
$ _ (x v) b ...
let || x | if (null? x) v | car x
b ...
which is line for line equivalent to (define-syntax opt
(syntax-rules ()
((_ (x v) b ...)
(let ((x (if (null? x) v (car x))))
b ...) )))
It's a matter of taste, but I'd rather read the former. The key ideas, other than using indentation to carry parenthesis level, are to use $ to hang double indents, and | to open a parenthesis that auto-closes.I gave this up learning Clojure so I could use other people's tools. Instead I prefer lighter parentheses, and I use this script to tailor fonts for coding lisp:
https://gist.github.com/Syzygies/226253bc38743ef474ee67cbf58...
I have the most trouble with comment characters, in any language. In various languages I used a preprocessor that implemented a practical version of "comments are flush, code is indented" (hey, it cost me one level) and relied on syntax coloring to mute the comments. Again, I gave this up to use other people's tools.
[0]: https://dwheeler.com/readable/readable-s-expressions.html
Another technical reason is that we work with text based version control tools, under which we use whitespace-insensitive diff as a hack to hide some differences that don't make a difference. That tool becomes unreliable over indentation-only languages; you can make a semantic change whose whitespace-insensitive diff is empty.
Another technical reason not to go indentation-only is that you don't know whether a partially obscured block of code is complete or just a prefix:
|defun foo():
| bar()
| xyzzy()
+---------- < window border
am I looking at all of foo, or do I have to scroll down to see more?Here you know it's the whole thing:
|(defun foo():
| (bar)
| (xyzzy))
+---------- < window border struct KaNode *ka_add(struct KaNode *node, struct KaNode **env) {
if (node->type == KA_STR && node->next->type == KA_STR) {
struct KaNode *output = ka_str(node->str);
strcat(output->str, node->next->str);
return output;
}
return ka_num(node->num + node->next->num);
}
Is this legal? If so, I'm going to use the heck out of it for my version of STOIC.[Edit] Ok.. thanks for the help.. I'm used to seeing function types declared AFTER the parameters because pascal habits die hard. It looked like a run of the mill structure declaration to me.
planet = [ name := 'World' nick := 'Earth' ]
'Hello, ' + (planet :: {WAT})
Output: 10585168
$ txr -i kamby.tl
Syntactic toffee recipe: melt butter over low heat, stir in Lisp macros.
1> (kamby-repl)
kmb> (let dz (/ 10 0))
** error: /: division by zero
kmb> (let a 1)
a
kmb> a
1
kmb> (let foo [(let bar1 42) (let bar2 73)])
foo
kmb> foo
#<kamby-env:(bar2 bar1)>
kmb> foo.bar1
42
kmb> foo.bar2
73
kmb> (set a 4)
4
kmb> a
4
kmb> (set a (* 2 a))
** warning: unbound variable a
** error: unbound variable a
Errors out at the end because unknown forms are evaled as Lisp, and Kamby variables are not Lisp variables.Mostly this was to play with the "construct environment tree as-you-go, with qualified pathname access" idea.
Code:
(defstruct kamby-env ()
bindings ;; assoc list
next-env ;; kamby-env object or nil
(:method extend (me sym value)
(upd me.bindings (acons sym value)))
(:method lookup (me sym)
(assoc sym me.bindings))
(:method delete (me sym)
(let ((binding (assoc sym me.bindings)))
(upd me.bindings (remq binding))))
(:method print (me stream pretty-p)
(format stream "#<~s:~s>" 'kamby-env [mapcar car me.bindings])))
(defvar *kamby-env* (new kamby-env))
(defun kamby-error (form fmt . args)
(error `~s: ~s: @fmt` 'kamby-eval (if (atom form) form (car form)) . args))
(defun kamby-eval (form)
(let ((e *kamby-env*))
(match-case form
((let @var @expr) e.(extend var (kamby-eval expr))
var)
((set @var @expr) (let ((binding e.(lookup var)))
(if binding
(rplacd binding (kamby-eval expr))
(kamby-error form "no such variable: ~s" var))
(cdr binding)))
((del @var) (unless e.(delete var)
(kamby-error form "no such variable")))
(@(symbolp @var) (let ((binding e.(lookup var)))
(if binding
(cdr binding)
(kamby-error form "no such variable: ~s" var))))
;; TXR Lisp qref syntax a.b.c.d <--> (qref a b c d)
((qref . @vars) (let (value)
(while vars
(let* ((var (pop vars))
(binding e.(lookup var)))
(unless binding
(kamby-error form "no such variable: ~s (when resolving ~s)" var form))
(set value (cdr binding))
(if (and vars (not (typep value 'kamby-env)))
(kamby-error form "~s isn't an environment object; cannot lookup ~s"
value (car vars)))
(set e value)))
value))
;; TXR Lisp dwim brackets syntax [a b c] <--> (dwim a b c)
((dwim . @forms) (let ((*kamby-env* (new kamby-env next-env e)))
[mapdo kamby-eval forms]
*kamby-env*))
(@else (eval else)))))
(defun kamby-repl ()
(whilet ((line (progn (put-string "kmb> ") (get-line))))
(catch
(prinl (kamby-eval (read line)))
(error (x)
(put-line `** error: @x`)))))https://github.com/henriquegogo/kamby
Still looks awesome; 400LOC is an incredible achievement for grok-ability c:
But there's always Forth for the the lighter taste in delimiters: https://github.com/TexTerry/forth-examples/blob/master/pasca...
But as Lisp was my first real language, I might be a bit biased. And besides Lisp I like languages like Forth or Postscript, and even Perl ;-)
There’s a point in using different signs that mean different things.