Why does being untyped and having a Lisp heritage make Scheme suitable for these three tasks?
Why does being untyped and having a Lisp heritage make Scheme suitable for these three tasks?
Rapid prototyping is because it requires less explicit up front design due to dynamic types.
Artificial Intelligence is because metaprogramming is easier in homoiconic languages.
...the first thing I do when encountering JSON in TypeScript these days is to add type definitions to describe the schema. If I have a hard time describing the schema to TypeScript, I'm going to have an even worse time trying to keep it straight myself.
I think you mean JSON where the schema isn't defined. If you have full control over the JSON you're consuming, you control the schema. Typed languages aren't any worse than dynamic languages in this case.
> Rapid prototyping is because it requires less explicit up front design due to dynamic types.
Many types languages have a REPL environment specifically for this reason. In my experience, it's not any slower.
> Artificial Intelligence is because metaprogramming is easier in homoiconic languages.
I have no experience here, thus I will assume you are correct.
For a while now I have felt that the reason for the creation of languages like Python and Ruby is simply a response to the pain of one such as C++. Now that we have modern languages like Rust and Go, what is there to be gained from sacrificing a type system?
The type system definitely helps with long term maintainability (and therefore fast iteration) but when your goal is to whip out a Proof of Concept for a greenfield project Ruby wins for me hands down. (Provided it isn't overly complex, defined as "can be completed in an hour or two").
I say this not just from personal preference, but I've proctored many timed coding challenges that were language agnostic. The challenge involved consuming data from a handful of API endpoints and compiling a response. Most statically typed solutions took twice the time of a dynamically typed one. We catered the time limit to the static case and it was a simple pass fail so no bonus points for doing it faster, but there was a strong advantage to the dynamic languages.
Note: This is very much alleviated with typed interchange formats like protobuf.
Edit: I don't mean this to be snarky, I just feel that it is not a very good experiment to draw conclusions from.
It was for all candidates, meant to test ability to understand a problem and prototype a solution quickly.
Edit: most candidates did Java/Scala/Python/Ruby.
If I'm hacking together a quick and dirty prototype, I might not even care what type I get back from that operation as long as it's in the ballpark. Using Ruby means I just don't have to worry about it for longer than it takes me to type `a + b`. If I used Haskell, or Rust, or whatever, I have to be explicit. That's additional work, however minimal, and in my experience it really does add up.
Of course, if I'm writing code that's going to be in production, this sort of thing is highly irresponsible and using a strongly typed language will help me to avoid numerical errors that would not even be runtime errors in e.g. Ruby; they'd be silently swallowed instead. That's extremely valuable. And if development of my prototype is going to span multiple days or more, strong types and compile-time type checking are going to reduce my mental workload since I don't have to remember how everything fits together; it's explictly annotated throughout the code and checked every time I build.
Can you elaborate on this? Why are or what about homoiconic lnagunages make them more suitable for metaprogramming and AI in general?
Thanks
The relation to AI is an assumption that AI and metaprogramming are connected. This is probably debatable, but it makes sense to me (and others) that AI development would benefit from being able to easily generate code and modify itself, much like you or I would learn a new skill.
If what you want is a system that rewrites itself, then you definitely want homoiconicity. It also helps if everything is one big expression.
Let's say you want to write an evolutionary algorithm that rearranges fragments of its code and runs it. More successful functions make it to the new generation. You want LISP for that.
Realistically, you could probably do this on any abstract syntax tree. But the problem is that unless your language is homoiconic, what you get back might not actually be valid in your language. So, homoiconicity gives you bidirectional support for rearranging the AST and still getting something you can read.
It's also just a lot easier to write something that looks at the code and does computation on it when that code is also data.
But, like I said, I'm not sure many people are actually doing this these days. It was popular back in the day. It's not clear that it's the right way to do things.
Scheme is a popular extension language. You could use it the same way Torch uses Lua.
Artificial Intelligence is because
metaprogramming is easier in homoiconic
languages.
Homoiconicity is something you can add to any language, dynamically or statically typed, simple or complex, it doesn't matter. It used to be belived that only syntactically simple languages like Lisp are suitable for homoiconic extension, but this myth was destroyed by Walid Taha and his development of the MetaML family of languages.For an overview of how to add homoiconicity to languages, see https://arxiv.org/abs/1602.06568
Any dynamically-typed scripting language is good for that sort of thing. Scheme in particular is very productive because of its meta-programming capabilities and REPL-based development.
> artificial intelligence
"Scheme was created during the 1970s at the MIT AI Lab [...]"
Type isn't just an implementation system; it's how we can reason about the program, as a mathematical object. The reasoning which informs us that (+ (cons 1 2) 3) is not well-formed without evaluating it, has to do with type.
How we implement values (using a generic "cell" that is type-tagged) is just a convenience. We can get things working without being concerned for up-front type checking. It also represents the philosophy that type is innate to objects (not just a syntactic property of programs).
A piece of compiled code can have a type passed into it which didn't exist when that code was compiled, and sensible things can happen anyway.
You can of course go further with your static analysis—a language may support many type systems in principle regardless of what the compiler accepts.
Thats not a bad name as it is self consistent - there are no type expressions in that language. If you say that it is actally "unityped" it is (just) your (semantical) categorization looking at it from a higher level perspective.
Of course on the other side whole numbers were just "number"-s, before fractionals came, so in the end it may be ok to introduce higher level perspective in naming just to diferrentiate better. :)
Type pervades computing.
A directory is a different type from a file or character device. A JPEG is a different file type from a PNG. You have MIME types in your e-mail. An ICMP packet is a different type from a TCP datagram.
Machine language instruction sets have types: pointers, signed and unsigned words of various sizes, floating-point values.
"Type" is a very broadly encompassing word. What all notions of type have in common is that it refers to some representation by whose rules some digital bits are interpreted to have a meaning (in some context which somehow establishes which rules apply).
Every field has its terms of art. "Type" is a term of art in PL theory; PL theorists are entitled to define it how they want. Of course you can use the word however you want, but you can't complain if that non-standard usage results in miscommunication with others.
Besides that, it's very useful to able to talk about the "types" of syntactic terms as distinct from the "types" of runtime values. You can easily reason about syntactic types. You can, for example, use syntactic types to resolve syntax ambiguities (as in C++) or prove program properties. Runtime "types" are much less useful to PL theorists because it's hard to reason about them.
Now instead of writing a useful program, we can exploit the type system for doing logic in a separate domain, detached from the program. The proof occurs as a byproduct when we compile the program.
Somehow we encode, for instance, the "all men are mortal; Socrates is a man; therefore Socrates is mortal" argument into types and write the corresponding code. Then when the code compiles, it verifies: yes, the argument is valid. At that point, we throw the program away. What (if anything) that program does is irrelevant; its types have proven the modus ponens as it passed through the compiler, thus quod erat demonstrandum.
That is supposedly what type is all about in a very narrow, myopic branch of computer science.