libera/#lisp - IRC Chatlog
Search
8:09:40
rendar
reading the book Structure and Interpretation of Computer Programs says that the language it convers is Scheme and not Lisp, is this normal?
8:14:39
jackdaniel
I've noticed a glitch in the matrix, it may be that they do something to the r eality ,)
8:15:36
jackdaniel
Lisp is often used in a sense "languages that descend from LISP 1.5", in this sense scheme does not qualify. that said scheme is considered a lisp dialect regardless by many (if not most) people
8:31:23
wasamasa
there is this weird split between people who believe lisp means a family of lisp languages and that lisp means CL and CL-like languages
8:52:45
pjb
rendar: that's correct. scheme is more pedagogical a programming language than Common Lisp. That's why it's often used in books and lectures.
8:53:13
pjb
rendar: but as a programmer you must be used to switching to different languages, and even to write programs that work as-is in several languages!!!
8:54:37
jackdaniel
sicp is a book about writing programs, scheme is used as a language to illustrate various concepts
8:54:51
pjb
rendar: see for example: https://github.com/informatimago/happy/blob/master/happy.source or Have a look at (intersection common-lisp emacs-lisp scheme) http://www.informatimago.com/develop/lisp/com/informatimago/small-cl-pgms/intersection-r5rs-common-lisp-emacs-lisp/
8:55:11
pjb
rendar: it's a common misconception. sicp is not a book about lisp or scheme. It's a book about programming!
8:55:34
pjb
rendar: people have been doing the exercises in sicp in all kinds of languages, from CL to C++.
9:04:11
rendar
can we say that a symbol is a string, and that the environment is an hash table mapping that string, to that internal structure?
9:06:24
rendar
well, that every Lisp have an internal representation of a symbol is a no brainer thing, its obvious, what i want to get is that internal structure is the 'value' whose symbol name (the 'key') points to, with an hash table
9:07:49
pjb
rendar: but quite often the name doesn't matter at all. You can (make-symbol "") #| --> #:|| |# and this can be useful (eg. in macros).
9:08:03
jackdaniel
yes, the symbol name is a string, and you may use hash tables to implement most mappings if you assume that there are no packages (i.e symbol names are unique)
9:08:22
pjb
rendar: we often use gensym in macros, to get different symbol names, but this is only useful when you debug the macro, to not be confused by different symbols having the same name.
9:09:19
pjb
rendar: note that usually you don't want the value stored in the symbol whose name is given.
9:10:31
pjb
rendar: basically, the system could throw away all the symbol names at runtime, and keep working.
9:10:55
pjb
(unless, of course, you do some reading at run-time, which often occurs of course; but it's independent).
9:13:51
rendar
as i am writing a little lisp interp, i had these doubts because i'm implementing the parser which will return a tree of nested python tuples, .e.g `('+', 2, ('+', 4, 5))` then the evaluator will evaluate that tree.. as you can see symbols are strings here, which the Env mapper will map to something valuable, e.g. '+' will be mapped to op.add()
9:13:53
pjb
rendar: but the name could very well not be stored directly. Instead of a hash-table, you could use a tree, so you could still map names to symbols, but to find out the name of a symbol, it would be a more complicated procedure. This would save a lot of memory (reduce '+ (list-external-symbols "CL") :key (compose length symbol-name)) #| --> 11271 |#
9:14:41
rendar
now, instead of plain strings, i have used an object Symbol, just to differentiate it better, so i had this python tuple: `(Symbol('+'), 2, 3)` for `(+ 2 3)`
9:15:13
rendar
but Symbol('+') is just a "typedef" for string, it is NOT the internal representation of a symbol
9:15:59
rendar
because Symbol('+') will be the *key* for an hashtable, and the value will be something like SymbolInternal() object which will contain function, values and so on
9:16:10
jackdaniel
mind that even if a symbol is defined as a structure with pointers, it does not mean that you are operating on these values; i.e you may have bindings in your lexical or dynamic environment for both variables and functions
9:17:24
pjb
rendar: yes. symbols, characters, strings, integers, floats, conses, vectors, arrays, structures, etc.
9:25:55
rendar
now, how in lisp is called the structured POINTED by symbol name? e.g. .. in `(setf x 2)` somewhere internally there will be an hash table pointing str->something, e.g. 'x' (key) -> something (value)
9:26:56
pjb
packages are more than just a hash-table, since they manages the use of other packages, the shadowing of symbols, and an export list.
9:27:46
pjb
The s-expression is read with *package* bound to the current package. By default, it's the package named "COMMON-LISP-USER".
9:30:01
pjb
rendar: now, other lisps may have no package. eg. emacs lisp instead only uses obarray. They're like the underlying structure of a hash-table.
9:31:34
pjb
here is an implementation of a package system and a lisp reader: https://gitlab.com/com-informatimago/com-informatimago/-/tree/master/common-lisp/lisp-reader
9:32:13
rendar
what i mean is that with `(setf x 2)` there will be a struct somewhere where that 2 is stored.. how we can call that structure? SymbolInternal..?
9:34:08
pjb
For example, (let (x) (setf x 2)) here x names a local lexical variable. When evaluating that, you wil create a frame with space for the local variable x, and a mapping from x to that space. Then setf will findout where that space is, and put a reference to 2 into that space.
9:34:41
pjb
rendar: no, symbols name variables, not values! It's the variables that refer to values.
9:36:13
pjb
rendar: but if you write: (defun foo (n) (let (x) (if (zerop n) (setf x 2) (setf x (foo (- n 1)))) (g n x)))
9:37:03
pjb
rendar: then you will have several frames each with a variable named x (and a parameter named n). And then in (setf x 2) the place named by x will depend on the current frame.
9:38:07
pjb
rendar: and then they are closures: (let (x) (mapcar (lambda (e) (if (zerop e) (setf x 2))) '(1 2 3 0 5)))
9:38:54
pjb
here the x in (setf x 2) names the variable x that is outside the function (lambda …). When the function (lambda …) is passed to the function mapcar, this is still this x in the outer let that needs to be set!
9:40:01
rendar
but i think that different scopes don't change how the internal mapping between 'x' and some structure will happen, right?
9:40:02
pjb
So you need to deal with environments (where the link between names and variables is stored) and frames (where the variable space is allocated).
10:21:55
aeth
Common Lisp is very explicit about its scope. Most Lisps are, but Scheme kind of relaxes that a bit with its internal (define)s
10:23:04
aeth
In a language like C, you can't "foo = 42;" without something like "int foo;" or "int foo = 41;" first
10:24:05
aeth
And you can't do that because C doesn't know the type, just like you can't SETF or SETQ something that has no binding because CL doesn't know where its scope is.
10:24:28
aeth
(Well, some implementations let you, and guess what the scope ought to be, but give you a warning because it's probably not where you think it is and it's not fully portable.)
10:27:04
aeth
on the first run of a variable, you want to use defparameter or defvar. defparameter has fewer surprises because it is always evaluated, while defvar only evaluates itself once (probably so it can be in a source file and get recompiled without wiping out your modified variable)
10:27:10
aeth
globally and portably, anyway. http://www.lispworks.com/documentation/HyperSpec/Body/m_defpar.htm
10:29:53
aeth
if you set something that's not defined, it can only guess what you mean to set because there's a lot of different things (lexical, dynamic; global (but probably thread-local), local)
10:30:13
aeth
(lexical globals aren't portable, but they do exist in some implementations including SBCL)
10:30:18
jackdaniel
technically speaking scope is not explicit in CL; you can't tell by the body alone whether the binding is dynamic or lexical
10:32:06
aeth
rendar: It's a useful warning. If you get the SETF warning in actual code instead of at the REPL, you've probably just experienced a bug (and probably typoed the name of the variable that you were trying to set)
10:32:33
aeth
In a lot of languages, it will helpfully create a brand new variable instead of modifying the one you want to modify, which will create a fun bug that can be hard to track
10:34:02
aeth
(Won't protect you in every situation, of course, since the typoed variable name might still exist, e.g. foo and fo might both exist)
10:35:48
aeth
(But it's more useful than you think because you still get protected if LET is supposed to rebind something and you typo the name because the typoed name of the LET variable will show up as an unused variable)
10:37:11
aeth
In general it's more idiomatic to rebind what a variable means inside of a LET than to SETF it, where SETF is more useful setting the slots of mutable data bstructures. So e.g. (let ((x 42)) ... (let ((x (1+ x))) ...
10:41:26
aeth
and it naturally creates points where you can refactor by moving that into its own function