6 ms·
I always feel that for lisp-like languages it's just not a good idea to make them statically typed. Their power is derived from macros and the fact that code is
by valenterry 5y ago
I always feel that for lisp-like languages it's just not a good idea to make them statically typed. Their power is derived from macros and the fact that code is data and the other way around.
For statically typed languages, they only feel ergonomic to me if they have highly specialized syntax and if they really leverage the type-system (which is often in conflict with macros and runtime flexibility).
- threatofrain 5y agoHow do you feel about typed Racket?
- valenterry 5y agoI have never used racket, but what I have seen so far is pretty cool. But for typed Racket, I don't have a good feeling about it either. In particular because it is gradually typed, which kind of defeats the purpose, even though it might be practically useful. But I prefer to have actually compiler guarantees and not just best-effort help.
- samth 5y agoThis might be a confusion about what "gradual typing" means. Typed Racket is a sound type system, and not just best effort. You get real compiler guarantees.
- valenterry 5y agoI don't think so. Here's an example: https://docs.racket-lang.org/ts-guide/typed-untyped-interaction.html https://docs.racket-lang.org/ts-guide/typed-untyped-interact... What that means is: I might call a function that tells me it will give me type X but instead it blows up. It's good that it blows up btw - that is the best thing a language with gradual typing can do for these cases. But it's not something I would be satisfied with. Now, you can say that "blowing up" is part of any function anyways, but then my response would be that this severely hurts my ability to reason about how code will behave when run, so I'm giving up a huge benefit of a static type-system in general.
- brundolf 5y agoSeems like you could still have macros, they would just evaluate before type checking. Rust works this way
- valenterry 5y agoTo my knowledge, Rust's macros are not generally safe/sound by definition. And that can be a big problem down the line. Compare it to Scala. When they developed Scala 3, they changed macros and dropped a lot of their powers to make the safe/sound by definition and compatible with the typesystem. But they are now severely restricted when compared to Lisp macros. EDIT: here's an example of a discussion about that in Rust: https://github.com/rust-lang/unsafe-code-guidelines/issues/278 https://github.com/rust-lang/unsafe-code-guidelines/issues/2...
- tines 5y ago> I always feel that for lisp-like languages it's just not a good idea to make them statically typed. Their power is derived from macros and the fact that code is data and the other way around. I completely agree with the idea that their power is derived from macros, but I vehemently disagree that macros are incompatible with a static type system. The type of a form can be just a simple ADT data Form = FInt Int | FCons Form Form | FNil | FString String | ... and a macro is just a function taking Form as arguments and returning a Form. With standard HM type inference, your macros can look exactly like they do in a dynamically typed Lisp. If the backquote is just a reader macro that produces a Form: (defmacro double (x) `(* x x)) that would be expanded into (defmacro double (x) (FCons '* (FCons x (FCons x FNil)))) and type inference would determine that the type of double is double :: Form -> Form And destructuring Forms is just normal ADT pattern matching.
- valenterry 5y ago> and a macro is just a function taking Form as arguments and returning a Form Why would it not just be a normal function then?
- nerdponx 5y agoBecause it's evaluated at compilation time.
- dgb23 5y agoNitpicking: I think we say „expanded“ since evaluation is reserved for runtime.
- tines 5y agoFor the same reason that it wouldn't be a normal function in any Lisp. The difference is that the macro expander keeps a list of macros (separate from the set of normal functions in the program), so that when it sees a list with a symbol in the first position, it can look up that symbol in its macro list, and if it is a macro, it can call the macro and replace the macro call form with the return value of the macro. Then that gets fed into the evaluator, just like how macros work in any lisp.
- michaelsbradley 5y agoNim is statically typed and has a powerful macro facility: https://nim-lang.org/docs/manual.html#macros https://nim-lang.org/docs/manual.html#macros https://nim-lang.org/docs/macros.html https://nim-lang.org/docs/macros.html
- dharmaturtle 5y agoHere's a Lisp that's statically typed with macros: https://github.com/lexi-lambda/hackett https://github.com/lexi-lambda/hackett