
Carp: A statically typed Lisp, without a GC, for real-time applications - tosh
https://github.com/carp-lang/Carp
======
brudgers
a recent discussion,
[https://news.ycombinator.com/item?id=15778530](https://news.ycombinator.com/item?id=15778530)

------
tombert
This is insanely cool. To me, once I learned Lisp (Clojure and then Racket),
it kind of gave me this "OMG why isn't every language like this????" feeling.

I wonder if Carp could fair well with a more academic, heavy-processing
sector....

~~~
oblio
> I wonder if Carp could fair well with a more academic, heavy-processing
> sector....

Could you expand on this? I'm not sure I understand your comment.

~~~
tombert
Academia, in my experience, has a tendency to use more theory-heavy languages
(Haskell, OCaml, and of course Lisp), or the "easy-for-engineering" languages,
like R or Matlab. When I used to work for a university, our stuff was done
almost exclusively with Haskell.

This is fine, but a lot of academic work (bioinformatics, video processing,
advanced statistical analysis, etc...) can be very computationally heavy,
leading to a lot of academics and post-docs writing some ad-hoc C++ in order
to squeeze out better performance.

What I was suggesting is that, since Carp might have better performance
characteristics for more CPU bound tasks than something like, say, Racket, it
might satisfying the niche of academic-friendly languages.

------
cies
Really well done. The lang design, the docs: intend is clear in every case and
very on point.

I've never been a fan of lisps, but that has more to do with the common lack
of strong typing discipline, than that it was a syntax issue. Currently I'm
using Haskell a lot.

But this lisp is a breath of fresh air to my type-loving brain.

Maybe I've overlooked them, but what about higher kinded types and reflecting
purity at type level? Are they not-in-and-never-will-be-by-design, or maybe-
if-someone-implements, or on-the-road-map?

~~~
aidenn0
Have you looked at Shen[1] at all? It is a lisp dialect with a reasonably full
featured type system[2]

1: [http://www.shenlanguage.org/](http://www.shenlanguage.org/)

2: [http://www.shenlanguage.org/learn-
shen/index.html#9%20Types](http://www.shenlanguage.org/learn-
shen/index.html#9%20Types)

~~~
djur
Is the open source version of Shen suitable for production use? It's not clear
to me how actively it's developed or how much it differs from the
"professional" version. The website suggests it lags far behind, but I recall
there being an acrimonious split between the original creator and the open
source community.

------
j_m_b
It's really nice to see Clojure syntax being adopted in newer lisps.

~~~
M_Bakhtiari
Well, I suppose it's better that they re-use someone else's gratuitously
different syntax than invent their own gratuitously different syntax.

~~~
fsloth
I think most modern programmers prefer explicit destructuring and taking an
element from a collection by its key rather than excplicitly traveling node
links using car and cadr. The 'original' lisp has some really arbitrary naming
conventions. Languages are cognitive tools and as such they should be able to
evolve, rather than dogmatically stick to a specific formulation laid down in
the formative years of a field.

It does not manner how you name your tokens or how you choose to destruct your
data structures. It's still lisp.

~~~
aidenn0
I disagree that Clojure's AST changes are gratuitous. Rich has repeatedly
provided his reasons for them. You may think they are bad reasons, but it's
not like he just said "ZOMG there are too many parens!"

That being said, I tend to use destructuring in common-lisp, and if you are
taking an element from a collection by using c*r then you are probably doing
it wrong.

Optima has more complete support for destructuring, but this works just fine
in CL with out any libraries:

    
    
        (let ((some-plist '(:foo 1 :bar 2)))
          (destructuring-bind (&key foo &allow-other-keys) some-plist
            foo))

~~~
kbp
And while it didn't make it into the Common Lisp version of LET, there were
versions in earlier dialects that supported destructuring. For example, the
Maclisp reference manual's description of LET[0] says:

It is permissible to place an s-expression pattern in place of a symbol in the
(sym init) form of an element of the bvlspec. The symbols in the pattern will
become bound to the matching elements of the initialization (see DESETQ). This
kind of pattern-matched assignment is called destructuring.

    
    
        (let (((a b) '(1 2)))
          (cons b a))
        => (2 . 1)
    

0:
[http://www.maclisp.info/pitmanual/contro.html#5.6.1](http://www.maclisp.info/pitmanual/contro.html#5.6.1)

------
radarsat1
Any discussion about real-time Lisp is incomplete without a mention of Snd-RT:
[http://archive.notam02.no/arkiv/doc/snd-
rt/](http://archive.notam02.no/arkiv/doc/snd-rt/) so I'll just drop that here
;)

It's very ground-breaking work imho that is unfortunately very poorly
known/cited, having been presented mainly to the computer music community, but
it represents a real-time garbage-collected Scheme.

------
OtterCoder
The readme is very terse, but exciting. Can anyone elaborate about the
ownership model?

~~~
tonyg
The page on syntax and semantics says "To learn more about the details of
memory management, check out Memory.md", linking to [https://github.com/carp-
lang/Carp/blob/master/docs/Memory.md](https://github.com/carp-
lang/Carp/blob/master/docs/Memory.md)

------
jgh
Whoa time to try this out, this seems awesome. (nb: c++ guy who love clojure)

------
amelius
How and when does it clean up memory allocated for closures?

~~~
andy_ppp
Presumably it's up to you to manage that?

------
andybest
Will be interesting to see how compiling to C affects debugging in the real
world. LLVM is nice as a target, since it allows you to map generated IR
blocks to source locations. Of course, it also means that the compiler needs
to link to all of the LLVM libs, which is a bit of a hassle too. (I've found
this when working on a Clojure->LLVM compiler bootstrapped from Clojure).

~~~
groovy2shoes
You can map locations in generated C code to locations in some other file,
too. Standard C has a pragma for it:

    
    
        #line <num> "filename"
    

or, if the filename is the same as the previous pragma, you can omit it from
the pragma:

    
    
        #line <num>
    

This pragma is used to inform the compiler of what information it should use
when displaying error messages and such. I think it's meant to be used by the
C preprocessor, but the preprocessor isn't _required_ to use it, and other
programs aren't _prohibited_ from using it.

You might wind up generating a lot of these, but they're really easy to
generate as long as you preserve that information all the way through
compilation (which I'd assume you'd have to do for LLVM IR regardless).

~~~
andybest
Interesting, I wasn't aware of the #line directive, thanks!

Yes, you would need to keep track of the source locations for each node in the
AST. There is a nice example in the LLVM Kaleidoscope tutorial here:
[https://llvm.org/docs/tutorial/LangImpl09.html](https://llvm.org/docs/tutorial/LangImpl09.html)

~~~
gnulinux
Bison and lex use #line to make generated C/C++ code (lexer, parser)
debuggable, or at least their GNU implementation does, I don't know about
other implementations.

------
nerdponx
I've been wanting a true statically-typed Lisp for a while. Very excited to
try this for keyboard firmware!

~~~
leshow
Typed Racket has been around for a while, is that not close enough to a lisp
for you?

~~~
nerdponx
I tried using it for some small projects, and it was really fun but seemed to
not mesh well with the rest of the Racket ecosystem.

------
Koshkin
> _(defn_

What's wrong with "def"?

~~~
jetrink
At least in Clojure, (defn my-function [] ...) is syntactic sugar for (def my-
function (fn [] ...)), removing one level of nesting.

