
Klisp – An implementation of the Kernel programming language - ycmbntrthrwaway
http://klisp.org/
======
def-
> Try that in your programming language ;)

Short circuiting in Nim, seems simple enough:

    
    
        template myAnd(a, b: bool): bool =
          if a: b
          else: false

~~~
boken
This doesn't quite hit the mark. The example given in Klisp will work with an
arbitrary number of arguments. What looks to be the second of two named
arguments, _e,_ is actually the dynamic environment from which _$and?_ is
called.

~~~
kazinator
> _e, is actually the dynamic environment from which $and? is called._

I.e. this and operator is an anti-deluvial beast once known in the Lisp word
as a FEXPR.

If a compiler is developed, every such operator will have to be reimplemented
as a macro.

~~~
junke
Context:

Special Forms in Lisp [0] by Kent Pitman (1980) is about FEXRs vs. MACRO:

> It is widely held among members of the MIT Lisp community that FEXPR,
> NLAMBDA, and related concepts could be omitted from the Lisp language with
> no loss of generality and little loss of expressive power, and that doing so
> would make a general improvement in the quality and reliability of program-
> manipulating programs.

> There are those who advocate the use of FEXPR's, in the interpreter for
> implementing control structure because they interface better with certain
> kinds of debugging packages such as TRACE and single-stepping packages. Many
> of these people, however, will admit that calls to FEXPR's used as control
> structure are bound to confuse compilers and macro packages, and that it is
> probably a good idea, given that FEXPR's do exist, to require compatible
> MACRO definitions be provided by the user in any environment in which
> FEXPR's will be used. This would mean that a person could create a FEXPR
> named IF, provided he also created an IF MACRO which described its behavior;
> the FEXPR definition could shadow [12] the MACRO definition in the
> interpreter, but programs other than the interpreter could appeal to the
> MACRO definition for a description of the FEXPR's functionality.

[0] [http://www.nhplace.com/kent/Papers/Special-
Forms.html](http://www.nhplace.com/kent/Papers/Special-Forms.html)

~~~
kazinator
But, of course, if you just write the macro IF, it's pointless to then write a
FEXPR. This is because the interpreter can use the IF macro just fine. Nobody
is going to write every operator twice in a large code base, first as a FEXPR
operator and then a macro operator. It's extra development work, plus extra
work to validate that the two behave the same way and are maintained in sync.

Kent is writing very theoretically there and being very generous to the idea.

Single stepping through macro-expanded code is perfectly possible. There is no
debugging disadvantage between stepping through a macro-expanded control flow
operator, versus one which is interpreted. In both cases, the single-stepping
interpreter can know the source code location where the argument expressions
came from and jump the cursor there, providing visual stepping.

Not to mention that compiled code can be stepped through a source code view;
countless programmers have been doing this in C for decades, and similar
languages. Given that we can write an if statement in C, compile it and step
through it in gdb, the position that we benefit from an FEXPR to do the same
thing in a Lisp interpreter is rather untenable.

------
klibertp
IO:

    
    
        myand := method(
            if(call evalArgAt(0), call evalArgAt(1), false)
        )
    
        myand(true, 3 println)  # prints 3 to stdout
        myand(false, 3 println) # nothing happens
    

This should also be possible in TCL. Scala has some kind of lazily eval'ed
arguments, too. And, of course, Haskell has this built-in.

EDIT: better example code.

~~~
klibertp
(forgot to mention, this IO code generalizes to any number of arguments)

------
gliese1337
Cool! I read Shutt's thesis on Kernel years ago, but I didn't know there was
an implementation available yet.

Vau interpreters can actually be simpler than lambda interpreters, and make a
great playground for language design. I wrote a blog post back in 2012 about
converting a simple Python Lisp interpreter into a vau interpreter
([http://gliese1337.blogspot.com/2012/04/schrodingers-
equation...](http://gliese1337.blogspot.com/2012/04/schrodingers-equation-of-
software.html)), and that eventually grew into an undergraduate capstone paper
on designing the denotational semantics of and implementing another vau-based
language called Vernal
([https://github.com/gliese1337/CS598R](https://github.com/gliese1337/CS598R)).

I don't expect any of these will ever become mainstream industry languages,
but they have a theoretical elegance and simplicity that makes them fun to
play with for the theoretically-minded.

~~~
mst
There's also wat.js and my wat-pl port to perl5.

They're _vastly_ fun for prototyping complicated logic in.

------
qwertyuiop924
Kernel is what I really want scheme to be. It's like scheme, but better. And
if you're wondering why I say better, more first-class objects is always a
good thing.

~~~
shasta
That's a pretty simplistic explanation. There are lots of ways to mess up Lisp
in an attempt to enable the style of meta-programming that Kernel supports.
What distinguishes Kernel from these other approaches (many of which have been
seriously considered in the past) is mostly what you're _not_ able to do in
Kernel. That is, the vau construct still allows encapsulation in a useful way.
Kernel may have "more things first class" than Lisp, but that's not all that
sets it apart.

~~~
qwertyuiop924
That's certainly one way of looking at it, and it IS one of the reasons I like
kernel. fexprs > macros because of this.

------
sklogic
Fexprs do not offer that much vs. mere static compile-time macros, but they're
making compilation impossible, limiting an implementation to a lowly and buggy
interpreter.

------
S4M
Can't build it on Debian, getting:

    
    
        /usr/include/features.h:374:25: fatal error:    sys/cdefs.h: No such file or directory
        #  include <sys/cdefs.h>
    

(I installed uuidcdef, for what it's worth).

Also I don't understand the code for the operator _and_ , isn't it gonna
return #t whenever x is null?

~~~
striking
Builds just fine on Arch Linux.

Maybe this article might help you:
[http://askubuntu.com/questions/470796/fatal-error-sys-
cdefs-...](http://askubuntu.com/questions/470796/fatal-error-sys-cdefs-h-no-
such-file-or-directory/)

~~~
S4M
Yep, it works, thanks for pointing it!

------
prestonbriggs
One of Shutt's advisors (on his thesis) was Shriram Krishnamurthi who
certainly understands Scheme deeply. Makes me curious to read the thesis in an
effort to understand what's new and interesting here.

------
Someone
In Swift:

    
    
       func myAnd(lhs: Bool,
                  rhs: @autoclosure () -> Bool) -> Bool
       {
         return lhs ? rhs() : false
       }
    

(Heavily inspired by [https://medium.com/swift-programming/facets-of-swift-
part-5-...](https://medium.com/swift-programming/facets-of-swift-
part-5-custom-operators-1080bc78ccc#.j2kertet1). Not tested; any bugs likely
are mine)

~~~
junke
I don't know Swift, but it seems[0] that it is not possible to apply this with
multiple arguments, like in the original example (e.g. (and a b c d)).

[0] [https://stackoverflow.com/questions/29750244/variadic-
autocl...](https://stackoverflow.com/questions/29750244/variadic-autoclosures-
in-swift-1-2)

------
namelezz
> Kernel is a Scheme-like programming language by John N. Shutt in which all
> objects are first-class.

Ok, but what problems are this programming language trying to address?

~~~
joelg
What problems were a Turing machine designed to "address"? Sometimes the
things that have the most value are the things that we can't wrap our minds
around yet. Think forward.

~~~
groovy2shoes
The Entscheidungsproblem:
[https://en.wikipedia.org/wiki/Entscheidungsproblem](https://en.wikipedia.org/wiki/Entscheidungsproblem)

------
sdegutis
[http://clojure.org/](http://clojure.org/) used to have a macro definition of
either (and) or (or) somewhere on one of its basic pages. They reorganized it
recently though so I can't find it. But yeah, I'm not really sure what Klisp
offers over Clojure so far. This sensationalist version of a hello-world isn't
really anything new or special so far.

~~~
PuercoPop
You cannot pass macros as values as they do not exist at runtime. (So no
macros can be passed to map/reduce as opposed to the fexprs).

P.D. Msimoni has written about fexprs (and a Lisp dialect with fexprs on JS,
wat.js) if you want to read about them some more.

~~~
sdegutis
Long ago, when I was learning Clojure, and thought "it's so inconsistent that
I can't pass `if` to a function," I would have found fexprs interesting. But
I've since thought about it more and realized there's absolutely no need for
it at all.

------
mchahn
> Try that in your programming language ;)

Does this count?

    
    
        function and(a,b) { return (a ? b ? b : false : false) }

~~~
qwertyuiop924
Now try to run this:

    
    
        and(false, console.log("This shouldn't run"))
    

A critical part of the semantics of the kernel function, and the javascript
built in &&, is that they are _short circuit_, that is, they only evaluate the
second value if the first value evaluates to false. This is very important if
you're programming with side effects.

~~~
wtbob
This is from the SBCL source, and I think it's pretty elegant:

    
    
        (defmacro and (&rest forms)
          (cond ((endp forms) t)
                ((endp (rest forms))
                 ;; Preserve non-toplevelness of the form!
                 `(the t ,(first forms)))
                (t
                 `(if ,(first forms)
                      (and ,@(rest forms))
                    nil))))

~~~
mst
Right, what's interesting about klisp is that you can define that as something
that can be called at runtime, rather than having to be implemented as
compile-time macro expansion.

I sort of regard operative lisps as "lisp, but even more so", as it were (and
for sheer brain melting power when prototyping weird logic they're even more
fun than normal lisps, at least to me)

~~~
qwertyuiop924
I just like them because fexprs are in some ways more elegant and easier to
understand than macros.

------
corruptio
#define and &&

heh

~~~
cmrdporcupine
Yep, had the same thought. #define AND(a,b) a && b

~~~
analognoise
See answer above about arbitrary number of arguments.

