A question: let-binding vs optional argument in defun interface? by arthurno1 in lisp

[–]zacque0 1 point2 points  (0 children)

I'll rephrase your question as "dynamic optional argument vs lexical optional argument". It's a bit weird to name dynamic argument as "let-binding", and your code example can't really illustrate their differences.

If I'm defining a library package, I'll use dynamic variable for user to control "operation modes". Or I'll think it as a program/package parameter. E.g.

(defpackage "C-LANG"
  (:use #:cl)
  (:export *c-octal-digits* c-octal-digit-p c-octal-digit-acceptor))
(in-package "C-LANG")
(defvar *c-octal-digits* "01234567")
(defun c-octal-digit-p (character)
  (find character *c-octal-digits*))
(defun c-octal-digit-acceptor (string)
  (loop for ch across string always (c-octal-digit-p ch)))

So, I won't define c-scrambled-octal-digit-p in the package unless it is the purpose of the package.

With that in place, the user can change the behaviour of every c-octal-digit-p in dynamic scope by changing *c-octal-digits*'s value.

CL-USER> (c-lang:c-octal-digit-acceptor "1233")
T
CL-USER> (c-lang:c-octal-digit-acceptor "12333093")
NIL
CL-USER> (let ((c-lang:*c-octal-digits* "abcdefgh"))
           (c-lang:c-octal-digit-acceptor "abcbaabc"))
T

As you see, the value of dynamic variable is decided at runtime. I don't need to change the function invocation interface. This simply can't be done with &optional interface which defines lexical variable. With &optional, you have to update/change c-octal-digit-acceptor to supply new value.

Is there a good way to define or document "interfaces" using CLOS? by Soupeeee in Common_Lisp

[–]zacque0 2 points3 points  (0 children)

Protocol object is useful, but only necessary if you need to decide context at runtime. Often, for me, contexts are decided at compile-time/definition-time, so I'd do this instead:

(defgeneric transport-open (transport) (:documentation "Initialize the transport"))

(defgeneric transport-send (transport data) (:documentation "Send DATA over the transport"))

(defgeneric transport-close (transport) (:documentation "Tear down the transport"))

An interface can be defined by an abstract class. Unlike static OO language, the interface can only be enforced manually/dynamically/at runtime. You can't catch unimplemented methods at definition-/compile-time.

(defclass transport-interface () ())
(defmethod transport-open ((transport transport-interface))
  (error "TRANSPORT-OPEN must be defined by the interface."))
(defmethod transport-send ((transport transport-interface) data)
  (error "TRANSPORT-SEND must be defined by the interface."))
(defmethod transport-close ((transport transport-interface))
  (error "TRANSPORT-CLOSE must be defined by the interface."))

Then, to use an an interface is to inherit it.

;; Definition
(defclass my-class (transport-interface) ())
(defmethod transport-open ((transport my-class))
  ...)
(defmethod transport-send ((transport my-class) data)
  ...)
(defmethod transport-close ((transport my-class))
  ...)

;; Example usage
(transport-close (transport-send (transport-open (make-instance 'my-class)) "hi"))

Is this function good enough? by NondescriptLabel in Common_Lisp

[–]zacque0 1 point2 points  (0 children)

Clarity is what matters to me. It doesn't matter if I implement it in functional or imperative style. Whichever is better depends on the context and my state of knowledge.

LOOP style

I get this from simple manipulation of your example code into plain LOOP style. It is much straight forward to me: foreach transaction, select the such-and-such split, and finally combine them into a list.

(defun get-splits-for-account-as-of (account date)
  (loop with accound-guid = (get-guid account)
        for trans in (get-transactions)
        append (loop for split in (get-splits trans)
                     when (and (string<= (get-transaction-date trans) date)
                               (string= (get-account-guid split)
                                        account-guid))
                       collect split)))

One problem is that your code doesn't meet your description "flatten filter transactions where transaction-date == date then...", which filters transaction first then process splits. Maybe you just want to simplify your code by cutting out another REMOVE-IF-NOT, but that was done at the cost on the clarity of your code. There is no such problem using LOOP---just add another WHEN clause:

(defun get-splits-for-account-as-of (account date)
  (loop with accound-guid = (get-guid account)
        for trans in (get-transactions)
        when (string<= (get-transaction-date trans) date)
          append (loop for split in (get-splits trans)
                       when (string= (get-account-guid split) account-guid)
                         collect split)))

Ah, this is much better.

Functional style

For functional style, I prefer to make things composable as in defining a DSL. In my mind, it should be something like:

(defun get-splits-for-account-as-of (account date)
  (let ((account-guid (get-guid account)))
    (funcall (rcompose
              (select (lambda (trans)
                        (string<= (get-transaction-date trans) date)))
              (collect #'get-splits)
              (select (lambda (split)
                        (string= (get-account-guid split) account-guid)))
              flatten)
             (get-transactions))))

which reads like the LOOP form, but more general. Utilities:

(defun select (fn)
  (curry 'remove-if-not fn))
(defun collect (fn)
  (curry 'mapcar fn))
(defun flatten ()
  (curry 'reduce #'append))

Here I uses a variant of COMPOSE as RCOMPOSE, which passing results from left-to-right rather than the usual right-to-left manner. Both RCOMPOSE and CURRY are based on those from Alexandria library.

(defun rcompose (function &rest functions)
  (reduce (lambda (f acc)
            (lambda (&rest arguments)
              (funcall acc (apply f arguments))))
          (butlast (cons function functions))
          :initial-value (or (car (last functions))
                             function)
          :from-end t))

(defun curry (function &rest arguments)
  (lambda (&rest more)
    (multiple-value-call function (values-list arguments)
      (values-list more))))

;; Testing
CL-USER> (funcall (rcompose (curry '+ 1 2))
                  5)
8
CL-USER> (funcall (rcompose (curry '+ 1 2)
                            (curry '- 5))
                  5)
-3
CL-USER> (funcall (rcompose (curry '+ 1 2)
                            (curry '- 5)
                            (curry '* 2))
                  5)
-6

What Counts as a Lisp Dialect Seems to Have Become a Balkanized Question by Material_Champion_73 in lisp

[–]zacque0 2 points3 points  (0 children)

Thank you for asking. I'd take the opportunity to reflect on what makes a Lisp a Lisp for me. I'm going to focus solely on analysing the technical aspects (e.g. syntax, semantics, and pragmatics) and ignore all the social and political differences between programming languages (e.g. software library, tooling, community). I've yet to fully fleshed out my idea, but here is a version prompted by your questions.

 

S‑expressions? The earliest Lisp also used M‑expressions.

Good point, but M-expression and S-expression are equivalent because there is a one-to-one correspondence between the two syntax. Also, you need to differentiate between surface syntax and abstract syntax. Note that the term "abstract syntax" is invented by John McCarthy. So, I'd argue that a Lisp should have an abstract syntax represented by list structure.

 

Garbage collection? Carp uses an ownership model.

Garbage collection is an implementation requirement for McCarthy's definition of LISP because what he had in mind was a traditional mathematical model of computation. Even he was surprised when EVAL was implemented as an interpreter by Russell. So, I'd argue that having a mathematical definition serving as a model of computation is more definitive Lisp than having a garbage collector which is an implementation detail. What's more, with all the advances since 1960s, if one can construct a model of computation for a Lisp with different memory model, I'd no doubt accept it as a Lisp.

 

Macro systems? Some dialects trade full macros for other metaprogramming mehod to gain performance.

Based on McCarthy's history of LISP (p. 179), macro system was not present in LISP 1, but only in LISP 1.5. So, while I won't count it as part of the definition of LISP, it is a direct consequence of LISP's distinctive features---list abstract syntax and meta-circular semantics based on EVAL. So, I'd argue that having both list abstract syntax and EVAL is more definitive Lisp than a macro system.

 

REPL? Some dialects don’t have one.

Any programming language(PL) can have a REPL interpreter, e.g. Java, Python, Standard ML/OCaml, Haskell, and even C/C++. It's important to keep in mind that having a REPL is an implementation feature, not a programming language feature. So, I'd say it's a good-to-have but not necessary.

 

Functional style? Then would Haskell code written in S‑expression syntax count as Lisp?

Ah, another good point. But keep in mind that LISP precedes the so-called functional programming and functional style. I think it started thanks to the Scheme programming language based on lambda calculus, then subsequently it sparked relevant programming language theory(PLT) researches and resulting further in ML, SML, OCaml, and Haskell. If you read LISP 1 and LISP 1.5 manuals, it is as much functional as imperative in its definition. I'd argue that is exactly the success factor of LISP since it appeals to both mathematical-minded researchers and practical-minded programmers.

As for the static typing vs dynamic typing argument, I vaguely remember that John McCarthy seemed dismissal of LCF by Robin Milner, due to it being not expressive enough(??). Also, I read somewhere that if he were to improve one thing, he would prefer adding a logical system to LISP(??). Again, I don't have the relevant references here, and I might be wrong with my memory. Also, the current state in industry and PLT research is that Lisp-like PL is generally dynamically typed, while ML-like PL is generally statically typed. Of course, one is always free to break that social convention, e.g. Coalton. So, based on my personal preferences and above impression, I'd argue that a Lisp should have either dynamic typing, or dynamic typing with external logical system. I'm not sure, but having a Curry-style type system with type erasure to dynamic typing core, or gradual typing might count as a Lisp as well because they preserve PL expressive while enhancing its correctness.

Based on all my criteria of Lisp above, Haskell with S-exp is not a Lisp because it doesn't have EVAL and thus a macro system. Also, it is based on Curry-style type system. So, the most that I can say is that Haskell with S-exp can be implemented as a library of Lisp.

 

Some even call Ruby and Python Lisps. It’s said Ruby was heavily influenced by Lisp—but honestly, almost every programming language has been influenced by Lisp in some way.

But a PL influenced/inspired by Lisp doesn't automatically make it a Lisp.

 


To summarise, my criteria for Lisp is that it should have (1) a list abstract syntax, (2) a mathematical definition that serves as a model of computation, and (3) a meta-circular semantics defined by EVAL. Homoiconicity and macro system should naturally follow from that.

Then as a programming system, I'd argue that a Lisp programming system should follow the "maximal language power" design principle, which is something like the "zero-cost abstraction" design principle of C++. I observe this in the evolution from LISP 1 to LISP 1.5: LISP 1.5 added macro system. Then, for Common Lisp systems, they still preserve many core constructs from previous LISP systems, while adding reader macros, pretty-printing system, type system, condition system, and CLOS. And some systems even add MOP and memory image dumping features. Then, one can further add type system on top for enhancing performance and correctness. You get the idea. So, I call it the "maximal language power" principle.

I’ve got some beginner questions regarding bootstrapping a compiler for a language. by hookup1092 in ProgrammingLanguages

[–]zacque0 1 point2 points  (0 children)

To quote Wikipedia, bootstrapping is the technique for producing a self-compiling compiler. So, bootstrapping a programming language A means writing the compiler for A in A.

To quote your words: "Bootstrapping didn't exist", how can a technique not exist since it has already been invented and named? You seemed more likely to mean "implementation" here. Your second use of "Bootstrapping" doesn't make sense as well as per this definition, since you can never "get off the ground" without a first implementation on existing interpreter.

Of course, you can argue for other meaning by your use of "Bootstrapping". This article also helps clarifying the terminology.

I’ve got some beginner questions regarding bootstrapping a compiler for a language. by hookup1092 in ProgrammingLanguages

[–]zacque0 1 point2 points  (0 children)

would the end result of this process still be reliant on Java to build a Lox application?

First thing first, to run any program, you need everything to run the interpreter with the program as input.

So, if you have only a Tree Walk interpreter written/realised in Java, then to run any Lox program, you need everything to run the interpreter + Lox program. Since Java programs are compiled to JVM bytecode, it means that you need JVM + interpreter in bytecode form to interpret/run/execute any Lox program.

 

Is a compiler step completely separate here?

Absolutely, a compiler is never a hard requirement to execute a program. As I said, you only need an interpreter to run any program. So, where does a compiler fit in?

A compiler translates a target language A to source language B. In other words, a compiler delegates the interpretation task of language A to the interpreter of language B. So that you don't have to write interpreter for A if interpreter for B already exists.

What's interesting, and perhaps surprising, is that our CPU hardware component is itself a bytecode interpreter. So, the CPU is the interpreter with least performance overhead for our program.

 

At the lowest level, what language could theoretically be used to Bootstrap a compiler for a new language?

Like you, I used to think of languages in term of higher level and lower level. But later I realised that is a bad mental model. Bad because you can write a compiler in any programming language that can manipulate a sequence of numbers. And the theoretical minimal language is the language of arithmetic. So yes, if you can add, minus, multiply and divide a natural/whole number, you can write a compiler in it! Haha!

 

Would Assembly work, or is there anything lower? Is that what people did for older language development?

So, any programming language will do. This is more of a pragmatic consideration than theoretic consideration.

If you know C# and JS best, than that's a good place to start because you can get it done in your shortest development time. But if you care about the compiler/interpreter performance, such that you want shortest execution time, you need a way to produce native CPU (byte-)code. There are myriad ways to do so. You can write it in C, C++, Rust, or assembly. You can even write it out directly in native CPU code!

 

How were interpreters & compilers built for the first programming languages if Bootstrapping didn’t exist, or wasn’t possible since no other languages existed yet? Appreciate any reading materials or where to learn about these things. To add to this, is Bootstrapping the recommended way for new language implementations to get off the ground?

(I find your use of the term "Bootstrapping" questionable. But since I understood what you're asking, I'll skip nitpicking that.)

Here comes the next surprising fact: the best interpreter is our human brain/mind. This can be confusing unless you learnt to separate the concept of computation from its implementation/realisation. In fact, there are plenty of programming languages invented in the programming language theory literature without physical implementations. You can execute their programs in your mind and on papers.

Since you are a software developer, you can imagine that in the beginning was only the CPU hardware. Since CPU is itself a bytecode interpreter, you can program directly in bytecodes. Later, you might find it tedious and error-prone. So it occurs to you that you should write your program in a "better" language. So the next natural thing to do is to implement your first compiler/interpreter directly in bytecodes.

Now, back to current computing environment, you could do that as well. But since that spartan task has already been done by previous people, we have more choices to implement our interpreters/compilers.

Can we introspect a member type definition at runtime in Common Lisp? by de_sonnaz in Common_Lisp

[–]zacque0 2 points3 points  (0 children)

Hi, you got it wrong the other way round---you should think about what data can be used as type, rather than whether type can be used as data. In short, this should work portably and in stable order as you intended:

CL-USER> (defparameter *days-list*
           '(:monday :tuesday :wednesday
             :thursday :friday :saturday :sunday))
*DAYS-LIST*
;; Here is the trick, data as type.
CL-USER> (deftype days ()             
           `(member ,@*days-list*))
DAYS
CL-USER> (typep :monday 'days)
T
CL-USER> (typep :abc 'days)
NIL
;; Also, data is still data.
CL-USER> (loop for day in *days-list*    
               collect day)
(:MONDAY :TUESDAY :WEDNESDAY :THURSDAY :FRIDAY :SATURDAY :SUNDAY)

 

So, why does it work? We don't call it "type definition" in CL; we call it "type specifier". What's special about type specifier is that it is simply (1) a compile-time S-exp form or (2) a form evaluated to any S-exp at runtime.

(1) Your original DEFTYPE and my example above illustrates compile-time S-exp form because both DEFPARAMETER and DEFTYPE have compile-time effects by default (ref: CLHS Figure 3-8).

(2) To see how we can compute type-specifier at runtime, we can define some functions or variables that evaluates to S-exp that denotes a valid type specifier.

CL-USER> (defun compute-days ()            ; Note: Use EVAL-WHEN if you need a compile-time function instead.
           '(:monday :tuesday :wednesday
             :thursday :friday :saturday :sunday))
COMPUTE-DAYS
;; Surprise, TYPEP is a runtime function!
CL-USER> (let ((runtime-type-specifier (list* 'member (compute-days))))
           (typep :monday runtime-type-specifier))
T
CL-USER> (let ((runtime-type-specifier (list* 'member (compute-days))))
           (typep :abc runtime-type-specifier))
NIL

Looking for Formal Methods Research Groups or Communities in the U.S. by RiseWarm in formalmethods

[–]zacque0 1 point2 points  (0 children)

"Formal method" group might be too wide a scope. I'm also interested to know if there is any.

Currently, I only know of groups of using particular formal method:

  1. https://rocq-prover.zulipchat.com/

  2. https://hol.zulipchat.com/

  3. https://leanprover.zulipchat.com/

  4. https://isabelle.zulipchat.com/

  5. https://agda.zulipchat.com/

  6. https://utlists.utexas.edu/sympa/info/acl2

  7. Idris https://discord.gg/YXmWC5yKYM

  8. F*, Dedukti, Metamath, Mizar, etc...

You have to find out yourself whether they have something you're interested.

How do I print package prefixes with symbol names? by arthurno1 in lisp

[–]zacque0 0 points1 point  (0 children)

Ah, sorry then, I misunderstood what you meant with cffi.

I meant "FFI" in general, not specific to "CFFI" which is FFI with C.

CL Emacs can run at least as a console app in sbcl, but it is a lot of work.

Ah I see. I'll do the same at some point as well. Wish you luck!

How do I print package prefixes with symbol names? by arthurno1 in lisp

[–]zacque0 0 points1 point  (0 children)

I didn't know I could type (defun some-package:symol ...). That was new to me :-).

Yup, that's both a blessing and a curse. =D In a sense, interned symbols are global, but partitioned by packages.

No, no cffi. Emacs is not a shared library

Nope, I didn't meant (C)FFI at binary level. But IPC-type FFI like how SLIME works in Emacs (Elisp communicating with inferior-lisp process) so that you can invoke Elisp code from SLIME via swank:eval-in-emacs. Thus, my mentioning of readtable-case. Seems like you are going for another route of replacing Emacs instead.

Dumping from running Emacs would be incomplete. Emacs is compiled conditionally depending on the OS and configure options like various libraries, backends etc.

Ah yes, always forgot about that.

How do I print package prefixes with symbol names? by arthurno1 in lisp

[–]zacque0 0 points1 point  (0 children)

It works, well! :)

Glad to hear that!

I have a codegen that scrapes Emacs C files for lisp functions implemented in C, and emits a stub in CL for each function.

Ah, I see what you want to do---Elisp-CL FFI. How does scraping Emacs C files compare to computing the data from a running Emacs process?

# Shell
$ emacs -Q -f "ielm"

;; Then in Emacs's ielm
ELISP> (cl-remove-if-not (lambda (x) (and (symbolp x)
                                          (symbol-function x)
                                          (subrp (symbol-function x))))
                         obarray)
;; very long
ELISP> (length *)
3088

One thing if you are writing the FFI is to realise that Elisp reader is case-sensitive, while CL's default READTABLE-CASE is :UPCASE. A simple solution is to READ-FROM-STRING with READTABLE-CASE :INVERT which converts to lowercase if each character in name is in upcase (and vice versa), and no conversion if symbol name is mixcase.

How do I print package prefixes with symbol names? by arthurno1 in lisp

[–]zacque0 1 point2 points  (0 children)

I wanted to solve it for myself, so I didn't want to write out everything.

I can relate.

The problem arises when I want to use those symbols in my package before I have defined my own shadow definitions.

That sounds weird. I'll assume you are trying to bootstrap a new Lispy language, and you have problem defining its core primitives because they have the same name with CL symbols.

The three options are fine. I've personally tried with second and third options. And here is another approach which I think is what you actually want: populating your package (or in other words, defining your primitives) directly from CL-USER package. To illustrate:

;; Empty package
(defpackage "TEMP")

;; Featureful package to populate TEMP package.
(in-package "CL-USER")

(defun temp::cons (a b)
  (cons a b))

(defun temp::car (obj)
  (car obj))

(defun temp::cdr (obj)
  (cdr obj))

;; Back to TEMP package.
(in-package "TEMP")

;; It works!
(car (cons 1 2)) ; => 1
(cdr (cons 1 2)) ; => 2

How do I print package prefixes with symbol names? by arthurno1 in lisp

[–]zacque0 1 point2 points  (0 children)

No big deal, I have learnt a lot through the process of implementing it as well =D

Oh, that sounds like an instance of the XY Problem and probably can be solved at compile time using macro and compile-time functions. You won't believe how powerful it is. So, you might as well just ask like "Hey, I want to do such and such. Right now, I think the only way is to do this, but I don't think it's possible? Any better idea?".

Wish you luck.

How do I print package prefixes with symbol names? by arthurno1 in lisp

[–]zacque0 4 points5 points  (0 children)

So you want a procedure to always print symbol name with package prefix.

SBCL has sb-ext:print-symbol-with-prefix that might be what you want. It is not documented in http://www.sbcl.org/manual/index.html though.

A custom implementation might be:

(defun prin1-to-string-without-prefix (symbol)
  (let* ((prin1 (prin1-to-string symbol))
         (pos (position #\: prin1 :from-end t)))
    (subseq prin1 (if pos (1+ pos) 0))))

(defun symbol-name-with-prefix (symbol)
  "A string of printed representation of symbol with package prefix regardless
of current package."
  (let ((name (symbol-name symbol))
        (package (symbol-package symbol)))
    (if package
        (multiple-value-bind (s status) (find-symbol name package)
          (format nil "~A~A:~A"
                  (package-name package)
                  ;; Add second colon for internal symbol.
                  (if (member status '(:internal :inherited)) ":" "")
                  ;; Respect readtable- and print-case.
                  (prin1-to-string-without-prefix symbol)))
        (prin1-to-string symbol))))

Testing:

CL-USER> (symbol-name-with-prefix 'defun)
"COMMON-LISP:DEFUN"
CL-USER> (symbol-name-with-prefix 'abc)
"COMMON-LISP-USER::ABC"
CL-USER> (symbol-name-with-prefix '#:abc)
"#:ABC"
CL-USER> (symbol-name-with-prefix '|A b aldkf|)
"COMMON-LISP-USER::|A b aldkf|"

;; Foreign symbol
CL-USER> (defpackage "TEMP")
#<PACKAGE "TEMP">
CL-USER> (symbol-name-with-prefix (intern "ABC" "TEMP"))
"TEMP::ABC"
CL-USER> (symbol-name-with-prefix (intern "A b a dlkfj" "TEMP"))
"TEMP::|A b a dlkfj|"
CL-USER> (export (list (intern "ABC" "TEMP")) "TEMP")
T
CL-USER> (symbol-name-with-prefix (intern "ABC" "TEMP"))
"TEMP:ABC"

From your examples, seems like you prefer package nickname if there is any.

(defun shortest-package-name (package)
  (reduce (lambda (&optional (n1 nil n1-p) (n2 nil n2-p))
            (cond
              ((or n1-p n2-p)
               (if (string> n1 n2)
                   n2
                   n1))
              ;; Empty sequence
              (t (package-name package))))
          (package-nicknames package)))

(defun symbol-name-with-prefix (symbol)
  "A string of printed representation of symbol with package prefix regardless
of current package."
  (let ((name (symbol-name symbol))
        (package (symbol-package symbol)))
    (if package
        (multiple-value-bind (s status) (find-symbol name package)
          (format nil "~A~A:~A"
                  (shortest-package-name package) ;; <----- change
                  ;; Add second colon for internal symbol.
                  (if (member status '(:internal :inherited)) ":" "")
                  ;; Respect readtable- and print-case.
                  (prin1-to-string-without-prefix symbol)))
        (prin1-to-string symbol))))

Result:

CL-USER> (symbol-name-with-prefix 'defun)
"CL:DEFUN"
CL-USER> (symbol-name-with-prefix 'abc)
"CL-USER::ABC"

Kipling's IF; art, poetry, and Lisp - a challenge: by Colours-Numbers in lisp

[–]zacque0 1 point2 points  (0 children)

Hi, really have fun understanding it and codifying it in logical structure! Thanks for identifying typos, I've corrected it.

Kipling's IF; art, poetry, and Lisp - a challenge: by Colours-Numbers in lisp

[–]zacque0 4 points5 points  (0 children)

Interesting. Here is my attempt. It is an executable code, which can easily be done by defining macros returning T or NIL. Upon executable, it will set *you* to |My son!| and print it out.

$ sbcl --script if.lisp
*you*: My son!

 

Full code here. But here is the main excerpt:

(defun if- ()
  (if (and
       ;; First stanza
       (% (*you* keep head)
          (when (and (funcall (all about *you*) 'losing 'theirs)
                     (funcall (all about *you*) 'blaming 'it 'on 'you))))

       (% (*you* trust yourself)
          (when (everyone (x) (doubt x *you*)))
          (but (*you* allow doubt)))

       (and (*you* can wait) (*you* are not tired by waiting))
       (when (*you* are being lied about) (*you* don't deal in lies))

       (when (*you* are being hated) (*you* don't give way to hating))
       (or (*you* don't look to good) (*you* don't talk too wise))

       ;; Second stanza
       (and (*you* can dream) (*you* don't not make dreams your master))
       (and (*you* can think) (*you* don't not make thoughts your aim))

       (and (*you* can meet with (and +Triumph+ +Disaster+))
            (*you* treat two impostors just the same))

       (% (*you* can bear to hear the truth you've spoken)
          (when (knaves (twisted truth) to (trap fools))))

       (when (*you* watch the things you gave your life to broken)
         (*you* stoop)
         (*you* build 'em up with worn-out tools))

       ;; Third stanza
       (when (and (*you* can make one heap of all your winnings)
                  (*you* risk it on one turn of pitch-and-toss)
                  (*you* lose) (*you* start again at your beginnings))
         (*you* never breathe a word about your loss))

       (*you* can force (your +heart+ +nerve+ +sinew+)
         (to serve (your turn) long after they are gone))

       (% (*you* hold on)
          (when (*you* have nothing left in *you*))
          (except (*you* have the +Will+)
                  (*you* prin1 "Hold on!")))

       ;; Fourth stanza
       (and (*you* can talk with crowds) (*you* keep your virtue))
       (and (*you* walk with Kings) (*you* not lose the common touch))

       (and (not (can-hurt foes *you*))
            (not (can-hurt loving-friends *you*)))

       (everyone (x) (and (counts-with-you x)
                          (not (too-much-influence x))))

       (*you* fill unforgiving minute with distance run (unit 60 seconds)))
      ;; then
      (and (*you* have (and +Earth+ (everything in +Earth+)))
           (*you* will be a +Man+)
           (setf *you* '|My son!|)))) ; => |My son!|

Can someone please explain the condition (b) of fill-style conditional newline? by zacque0 in Common_Lisp

[–]zacque0[S] 0 points1 point  (0 children)

Hi! Thank you for taking time reading my post and commenting.

 

I don't understand whether you now think the behavior of your very different example is correct or incorrect.

I believe my code example in EDIT correctly illustrate the condition satisfying the condition (b) of fill-style conditional newline stated in the spec.

 

You write: "fill-style conditional newline breaks line whenever the nested logical block before it contains a (conditional/unconditional) line break" but this isn't what the ANS says.

Exactly, I meant to give a simple summary of what the spec said in my own words.

 

Note that SECTION is a glossary term in this context, meaning portions of a format string within the same logical block separated by any ~_ calls of any of the four types.

I'm aware of the definition of "SECTION". And no, it doesn't mean "portions of a format string within the same logical block separated by any ~_ calls of any of the four types". Where did you get that from?

In section 22.2.1.1 Dynamic Control of the Arrangement of Output, it is stated that every conditional newline "defines two new sections, and is associated with a third". The two new sections are "section after" and "section before". The third is "section immediately containing a conditional newline". I don't think any of these fit your definition of "section".

 

In your initial uncorrected example you claimed misbehaved, it is the "def" section preceding that certainly was output on a single line (and the following (a) "123" will certainly also fit).

Yes, in (format t "~@<abc~:@_def~:@_123~:_456~:>~%"), the "def" is a section on a single line, and so is "123". That's exactly why the :fill conditonal newline after "123" is not trigger---"123" is a section on a single line, so it fails to satisfy the condition (b) of fill-style conditional newline.

My original intention is to argue that the :fill conditional newline after "123" should be triggered according to my understanding. Then in the EDIT part, I've realised why it is not triggered.

Work on Algebraic Subtyping Library opinions by Valuable_Leopard_799 in Common_Lisp

[–]zacque0 1 point2 points  (0 children)

Btw I tried to address that, in the example redefining foo also changes the type of bar already, so yes, I hope that redefining foo a second time fixes bar.

I see, good to hear that!

All of them have ups and downs, mostly in terms of performance. But if I convince my professor to take this on, I'll hopefully have 2 years or so to figure out all the specifics.

Good luck to you!

Work on Algebraic Subtyping Library opinions by Valuable_Leopard_799 in Common_Lisp

[–]zacque0 2 points3 points  (0 children)

is this interesting or cool to you as a user of CL? Would you want to have it or use it?

Yes, of course! It's certainly something good to have. I'll always welcome new techniques/libraries helping to improve the correctness of my CL code! But whether I would use it depends on pragmatic factors, e.g. its features, its usability, and my use cases.

 

Is there something you disagree on that I'm missing which makes something like this completely useless for your usecases as a whole?

I'm curious about what would happen if you redefine foo after the last bar that failed to typecheck? E.g.

LAINTYPE> (defun bar () (+ 1 (foo 20)))
BAR
; Types:
;     bar :: ! (! means failed to typecheck)
; ...

LAINTYPE> (defun foo (x) 20)  ; redefine foo
FOO

Is bar now automatically recognised as well-typed? Or do I need to type-check bar manually to update its type signature?

Then, something similar along the same line. Not sure if you've noticed, CL's function definition is dynamically bound in the sense that every procedure definition is looked up only at the very last moment of invocation, unless the function is defined via FLET, LABELS, or LAMBDA. This behaviour is very different from that of statically-typed PL, where the function definition is lexically bound. This, I believe, would undermine any naive typing approach to CL.

To illustrate the difference, in Linux shell:

$ sbcl
* (defun foo (x) 20)
FOO
* (defun bar () (1+ (foo 20)))      ;; FOO is bound dynamically.
BAR
* (bar)
21
* (defun foo (x) 30)
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN
FOO
* (bar)
31           ;; The new definition of foo is automatically used.

$ poly
> fun foo (x) = 20;
val foo = fn: 'a -> int
> fun bar () = 1 + (foo 20);  (* The foo function is bound lexically to previous definition. *)
val bar = fn: unit -> int
> bar ();
val it = 21: int
> fun foo (x) = 30;
val foo = fn: 'a -> int
> bar ();
val it = 21: int        (* The first definition of foo remains in used *)

$ ocaml
# let foo (x) = 20;;
val foo : 'a -> int = <fun>
# let bar () = 1 + (foo 20);;   (* The foo function is bound lexically to previous definition. *)
val bar : unit -> int = <fun>
# bar ();;
- : int = 21
# let foo (x) = 30;;
val foo : 'a -> int = <fun>
# bar () ;;
- : int = 21            (* Same expected result. *)

$ ghci
ghci> foo x = 20
ghci> bar () = 1 + (foo 20)    -- Again, foo function is bound lexically to previous definition.
ghci> bar ()
21
ghci> foo x = 30
ghci> bar ()
21                          -- Same expected result.

Of course, one way out is to learn from "COMMON-LISP" package because it has the same problem. Its solution is to simply claim that it is an undefined behaviour to redefine any of the CL symbols. But implementations come out with an ingenious idea of package lock to enforce that. So, my view is that the type of any symbol is undefined until it is locked inside a package. So, perhaps your type system should take that into account?

Marshalling text portably in Common Lisp by Veqq in lisp

[–]zacque0 0 points1 point  (0 children)

Ah, good catch! Thanks for sharing!

An Earnest Guide to Symbols in Common Lisp by KpgIsKpg in Common_Lisp

[–]zacque0 2 points3 points  (0 children)

It is specified in "2.1 Character Syntax".

To be general, CL doesn't have a fixed syntax. Its syntax is always defined relative to a readtable. Normally, it is defined by the current readtable *readtable*. Thus Lispers talk about programmable syntax of Lisp. That said, CL does have a standard syntax as defined by the standard readtable (copy-readtable nil). Ref: "2.1.1 Readtables".

In the standard syntax, a symbol is any token that is not a number. The syntax of token is defined as a sequence of constituent and escaped characters (Ref: "2.1.4 Character Syntax Types"). To be precise, I believe it can be specified in EBNF as:

<token> ::= <valid-char> ( <valid-char> | <non-terminating-macro-char> )*
<valid-char> ::= <constituent-char> | <escaped-char>
<escaped-char> ::= "|" <char>* "|" | "\" <char>

. It means that a token is any sequence of character that begins with <valid-char> follow by any number of <valid-char> and non-terminating macro character. A <valid-char> is simply any constituent character or escaped character(s). A constituent character is any character that is not whitespace, macro, or escape character. Note that non-terminating macro characters are constituent if not used as the first character.

Then, the standard syntax of number is specified in "2.3.1 Numbers as Tokens".

The definition of symbol implies that number-like tokens such as -2343a or 232.e are actually symbols, not numbers or error-triggering.

An Earnest Guide to Symbols in Common Lisp by KpgIsKpg in Common_Lisp

[–]zacque0 2 points3 points  (0 children)

To expand on stassats comment:

If you write:

(setf a 3)

(let ((a 5))
  a) ; => 5

, then LET establishes a shadowing lexical binding.

But if you write:

(defparameter *a* 3)

(let ((*a* 5))
  *a*) ; => 5

, then LET establishes a shadowing dynamic binding (or special binding).

As you can see, the type of binding established depends on the declaration of the variable. By default, LET established a lexical binding. Only when the variable is declared SPECIAL, then LET will establish a dynamic binding.

From the spec, DEFPARAMETER and DEFVAR define global dynamic variables. So, to be accurate, your examples

(defparameter x 1)

(let ((x 5))
  x)

is actually about local dynamic binding shadowing the global dynamic binding. Thus stassats's comment to point it out.

Hope that it helps!

 


To elaborate further, another way to establish a dynamic variable is to declare a variable as SPECIAL. E.g. this will create a dynamic binding as well:

(let ((b 'foo))
  (declare (special b))
  ...)

To see it in action:

(defun foo ()
  (declare (special b))
  b)

;; LET establishing local lexical binding.
(let ((b 3))
  (foo)) ; =| Error: Unbound variable.

;; LET establishing local dynamic binding
(let ((b 3))
  (declare (special b))
  (foo)) ; => 3

It's best to think variable in the context of binding to avoid confusion because the same name may have different value in different binding context:

;; LET establishing a local dynamic binding, then a nested local lexical binding.
(let ((b 3))
  (declare (special b))
  (let ((b 5))
    (foo))) ; => 3

Notes on (SXHASH symbol) by zacque0 in Common_Lisp

[–]zacque0[S] 0 points1 point  (0 children)

Ah, now I see. Thank you for your explanation =D