4 ms·
Common Lisp has had this for decades: DEFINE-COMPIILER-MACRO.
by lisper 5y ago
Common Lisp has had this for decades: DEFINE-COMPIILER-MACRO.
- GolDDranks 5y agoBut I have an impression that Common Lisp doesn't have a type system, whereas this languages strives to have all "levels" of it's metaprogramming typed, so it's not like this language doesn't have any novelty.
- lisper 5y agoCommon Lisp has a very sophisticated type system. The only thing it doesn't have (among things that are currently fashionable) is compile-time typing by default. Peridot is "novel" in that it introduces user-level compiler optimizations into a language that does have compile-time typing by default. But that's kind of like Chevrolet making a plug-in hybrid version of the C8 Corvette (which they recently announced they are going to do). Neither the C8 nor plug-in hybrids are new. A plug-in hybrid C8 will be new, and when it happens it will be a Big Deal to a niche market: the intersection of C8 fans and plug-in-hybrid fans. But it won't change the world. (For the record, I happen to be a member of the niche market to which a plug-in hybrid C8 will appeal, so I am very excited about it. So I get that some people may be excited about Peridot. I just think it's important to keep things in perspective.)
- Mikeb85 5y agoHaving dynamic typing != no type system.
- lapinot 5y agoActually no, not in programming language theory. What researchers call 'type system' is much more precise than what programmers call 'type system'. In the PL field, the behavior of a term is traditionally split into static behavior (described by types) and dynamic behavior (described by reduction/evaluation). What programmers call 'dynamic type systems' is just a way to instrument the runtime with dynamic data-shape checks. Note that most dynamic languages do have a non-trivial type system, where functions are typed with their number of arguments (eg static scoping and other structure-related static checks). Languages like bash otoh do really have a trivial type system, whith every term merrily going into the evaluator without any static/typing well-formedness analyzis. You might also be interested in gradual typing, which is about deriving systematic dynamic checks from a type system and then augmenting a given type system with an 'any' type to go into untyped (ie dynamically checked) mode.
- lisper 5y ago> dynamic data-shape checks What is the difference between a "data-shape check" and a type system?
- lapinot 5y agoI'm assuming you why want me to explain what the difference between a static data-shape check and a type system is (since i'm already saying type systems are about static information). For sure there is a non-empty intersection in some way, but the two are differently structured. For one 'data' is a runtime concept (some programs might be data, but some others are computations). So already a data-shape check isn't always doable statically like you would at runtime. And the other way around, some information might be statically available but not materialized in any kind of data shape, like type parameters for polymorphic functions, lifetimes in rust or in general irrelevant proof-terms in dependently-typed languages. Perhaps you would be satisfied if i said that type-systems are a shape-check for terms and not for data.
- lisper 5y agoNo, that would not satisfy me. It's not that I don't understand the concept you are trying to convey, or even that I disagree with it. What I object to is the co-opting of the word "type" to mean something other than it means in common usage. I understand that "type system" is a term of art within a certain research community, but this is not that community. HN is much broader than that, and within the context of that audience, "type system" already has an established meaning that encompasses things that happen both at compile time and at run time, and which applies to both terms and data [1]. > 'data' is a runtime concept (some programs might be data, but some others are computations) And how do you distinguish between runtime and non-runtime? It's true that most languages have a distinction between compile-time and run-time but this is purely artificial, a design choice, not a reflection of any deep underlying mathematical truth. Common Lisp notably does not have a sharp distinction between the two. Compilation can trigger macro-expansion, which can in turn trigger arbitrary computations. This process can even loop back on itself: the computations triggered by a macro expansion can themselves invoke the compiler, and can even define new macros. So when you say "Common Lisp does not have a type system" what you really mean is "the structure of Common Lisp is different from what is currently being studied by a group of researchers who have chosen to call the object of their study 'type theory'." The problem with phrasing it the way that you do is that it implies that Common Lisp is lacking something (a type system, according to your narrow definition of what a type system is). It isn't. Common Lisp isn't lacking anything, it is just structured differently. But this is a feature, not a bug, because if you want to avail yourself of the technology of what in academic circles is called "type systems" in Common Lisp you very easily can. But you don't have to. In fact it is so-called "strongly typed" language that are lacking something, namely, the freedom to write code that does not conform to the constraints of the "type system". [1] https://en.wikipedia.org/wiki/Type_system https://en.wikipedia.org/wiki/Type_system
- tonyg 5y agoCL has many merits, but it does not and cannot ever have a type system like Peridot has. (If it did, it wouldn't be CL anymore.) It also does not have a logic-based metaprogramming language. Peridot's metaprogramming model is quite far from DEFINE-COMPILER-MACRO. You could build Peridot as a DSL in CL, using DEFINE-COMPILER-MACRO, even, but that's not the same thing as CL having "had this" at all, let alone "for decades".
- lisper 5y agoWhether or not CL would still be CL if you embedded a Peridot-style type system is debatable. But the example given in TFA can be easily and straightforwardly rendered as a CL compiler macro. There might be useful things that Peridot can do easily that CL can't but these are not immediately evident, at least not to me.
- kazinator 5y agoCompiler macros are kind of a fluff feature that can easily be subsumed into regular macros. You need two ingredients: (1) it must be possible to define a macro and function simultaneously for the same symbol. (2) the regular macro expander must detect fixed points in macro expansion and stop expanding. You want (2) anyway; if a macro returns the original form, so that its output is eq to its input, it make no sense to call it again. This is the TXR Lisp interactive listener of TXR 275. Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet. TXR Lisp has no protected class members; C++ refugees may face discrimination. 1> (sqrt 5) 2.23606797749979 2> (fboundp 'sqrt) t 3> (mboundp 'sqrt) nil 4> (defmacro sqrt (n :form f) (if (constantp n) (sqrt (eval n)) f)) ** expr-4:1: warning: defmacro: defining sqrt, which is also a built-in defun sqrt 5> (sqrt 5) 2.23606797749979 6> (macroexpand '(sqrt 5)) 2.23606797749979 7> (macroexpand '(sqrt x)) (sqrt x) 8> (mboundp 'sqrt) t 9> (mmakunbound 'sqrt) sqrt 10> (mboundp 'sqrt) nil 11> (macroexpand '(sqrt 5)) (sqrt 5) Unlike a compiler macro, sqrt will always expand, guaranteed. User-defined optimizations want to be tree rewrite patterns. We can impose that onto macros (or compiler macros). In the TXR world, this can be done with a parameter macro, and one is provided for that, namely :match. 12> (defmacro sqrt (:match :form f) (((@(constantp @exp)) (eval exp))) (((* @exp @exp)) exp) (((expt @exp 2)) exp) ((@else) f)) ** expr-23:1: warning: defmacro: defining sqrt, which is also a built-in defun sqrt 13> (macroexpand '(sqrt (* (+ x y) (+ x y)))) (+ x y) 14> (macroexpand '(sqrt (* (+ x y) (+ x z)))) (sqrt (* (+ x y) (+ x z))) 15> (macroexpand '(sqrt (* 5.5 5.5))) 5.5 16> (macroexpand '(sqrt (expt (sin x) 2))) (sin x) 17> (macroexpand '(sqrt (expt (sin x) 3))) (sqrt (expt (sin x) 3)) Parameter macros like :match are bound in the keyword namespace. When these bound keywords occur at the head of a parameter list, their macro gets invoked, receiving the parameter list and the function body, rewriting both of them together.
- lisper 5y agoFirst I've heard of TXR. Very impressive!
- deleted 5y ago[deleted]