Live data from Hacker News

Lisp implemented in Rust macros

github.com

81–85 of 85 posts

Re: Lisp implemented in Rust macros

#81
post #79

Earlier quoted context omitted.

> Some Lisp compilers like SBCL are already capable of more extensive compile-time type-checking, but its information that the programmer is up to supply Which is nice and all, but very much gimped by the glaring holes in CL's typing tooling: you can't create actual types, only derived types (deftype) and struct/class types. The two consequences of that is that you can't type cons-based lists/trees (arguably THE Lisp…

> you can't type cons-based lists/trees (arguably THE Lisp data structure) because deftype can't be recursive and you can't create parametric types (deftype list-of (type) `(cons ,type (or null (list-of ,type)))) (typep '(1 2 3 4) '(list-of integer)) => T Most of the standard types from which derived types can be made are parametric types, which specialize on their arguments in different ways. They work the same way…

The CLHS sez "Recursive expansion of the type specifier returned as the expansion must terminate, including the expansion of type specifiers which are nested within the expansion." though. As expected, here on SBCL, your typep blows the stack.

> Most of the standard types from which derived types can be made are parametric types

I meant "parametric with a type parameter", but yeah.

> satisfies

I was (obviously, I hope) talking about static, not runtime typing.

Re: Lisp implemented in Rust macros

#82

Earlier quoted context omitted.

Pretty sure it applies to Common Lisp itself too.

The corollary to Greenspun’s rule is that any sufficiently complicated Common Lisp program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Prolog.

Well, the 'PAIP' book for sure does it, literally.

Re: Lisp implemented in Rust macros

#83
post #79

Earlier quoted context omitted.

> you can't type cons-based lists/trees (arguably THE Lisp data structure) because deftype can't be recursive and you can't create parametric types (deftype list-of (type) `(cons ,type (or null (list-of ,type)))) (typep '(1 2 3 4) '(list-of integer)) => T Most of the standard types from which derived types can be made are parametric types, which specialize on their arguments in different ways. They work the same way…

The CLHS sez "Recursive expansion of the type specifier returned as the expansion must terminate, including the expansion of type specifiers which are nested within the expansion." though. As expected, here on SBCL, your typep blows the stack. > Most of the standard types from which derived types can be made are parametric types I meant "parametric with a type parameter", but yeah. > satisfies I was (obviously, I hop…

> The CLHS sez "Recursive expansion of the type specifier returned as the expansion must terminate, including the expansion of type specifiers which are nested within the expansion." though. As expected, here on SBCL, your typep blows the stack.

Weird, I tried it in CLISP and ECL and it worked fine. It looks like this issue was considered during the standard: https://www.lispworks.com/documentation/HyperSpec/Issues/iss... If you ask me that's a misfeature and not the Right Thing, but I was able to work around it by using a helper function and the type I wrote earlier, although it does lose more in comparison:

  (defun list-of-p (list type)
    (and (consp list)
         (typep (car list) type)
         (or (null (cdr list))
             (list-of-p (cdr list) type))))

  (deftype list-of (type)
    `(satisfiesp (lambda (x) (list-of-p x ',type))))
I will admit one of the double-edged swords of Common Lisp is that some of these rough edges are ultimately left up to the implementation, so there are a lot of very powerful features that are only `de-facto' standard or come with a lot of portability glue. However, many programs are also not designed with portability in mind. It would be nice if SBCL in particular could be made to adopt this use of types.

> I was (obviously, I hope) talking about static, not runtime typing.

The only difference between static and runtime typing would be the stage at which the types are evaluated, and being the same as macros they might be more interesting in that regard since they might have to consider what it means to run at both stages of evaluation.

Re: Lisp implemented in Rust macros

#84
post #83

Earlier quoted context omitted.

The CLHS sez "Recursive expansion of the type specifier returned as the expansion must terminate, including the expansion of type specifiers which are nested within the expansion." though. As expected, here on SBCL, your typep blows the stack. > Most of the standard types from which derived types can be made are parametric types I meant "parametric with a type parameter", but yeah. > satisfies I was (obviously, I hop…

> The CLHS sez "Recursive expansion of the type specifier returned as the expansion must terminate, including the expansion of type specifiers which are nested within the expansion." though. As expected, here on SBCL, your typep blows the stack. Weird, I tried it in CLISP and ECL and it worked fine. It looks like this issue was considered during the standard: https://www.lispworks.com/documentation/HyperSpec/Issues/i…

> It would be nice if SBCL in particular could be made to adopt this use of types.

I agree, that would be an easy extension (at least from the user-facing API PoV) and would tremendously improve the language!

> The only difference between static and runtime typing would be the stage at which the types are evaluated, and being the same as macros they might be more interesting in that regard since they might have to consider what it means to run at both stages of evaluation.

That is the only difference, but that difference has important consequences on optimization.

Re: Lisp implemented in Rust macros

#85
post #78

Earlier quoted context omitted.

Store where? C++ templates are a lambda calculus, there's no notion of memory cells or state.

In a struct! Pseudo code for extracting the types from subclasses and calling a multimethod on them: template struct Foo : Visitor { Result res; UntypedList lst; // This does not exist! Tail... tail; // This is not possible! Foo(UntypedList l; Head hd, Tail... tl) : lst(l), tail(tl) { hd->accept(*this); } void visit(float *f) { res = Foo (append(lst, f), tail)::res; } } }; // Base case that calls the multimethod omit…

Not sure what Untyped list is or supposed to do in the above. In fact I'm not sure what the code above is trying to do at all.

If you want a cons-based tuple, boost::tuple will work just fine (or you can implement your own, it is not hard). std::tuple is not (visibly) cons based.

Post reply on HN