6 ms·
Static languages, in particular Haskell, PureScript, etc, are unparalleled when it comes to fast prototyping or design space exploration. The compiler can show
by pka 10y ago
Static languages, in particular Haskell, PureScript, etc, are unparalleled when it comes to fast prototyping or design space exploration. The compiler can show you whether your idea even makes sense before writing big chunks of business code.
How? By building the structure/hard stuff first and letting the compiler verify it while leaving out the uninteresting parts.
A very simple example. Let's say you have some data model with people, addresses, whatever. You want to see what you need to do to get a list of addresses for some group of people.
You start by defining the structure of your data model (this can depend on DB schema, business requirements, whatever):
data Person = Person { name :: String, city :: String }
data Address = Address { city :: String, zipcode :: String, street :: String }
Now, go straight to the hard part. No need to fuck around with DB connections, mock data, whatever:
getAddresses :: [Person] -> [Address]
getAddresses = undefined
Leave out the implementation for now. So probably we are gonna need a way to get an Address for a Person. Ok:
addressForPerson :: Person -> Address
addressForPerson = undefined
Again, leave out the implementation. Now go back to `getAddresses` and see if we can implement it now:
getAddresses = map addressForPerson
Cool, the compiler doesn't complain. So far we've verified that if we have a function like `addressForPerson` we can safely assume that our design is going to work.
Now we can go back to `addressForPerson` and implement that. But turns out, we only have a city stored in Person, so the best we can do is get back a list of potential addresses for each person. So we need to adjust that type signature:
addressForPerson :: Person -> [Address]
addressForPerson = undefined
Leave out implementation, it's trivial so no need to spend time on it now. But now the compiler complains that `getAddresses` doesn't make sense anymore! We are saying that, having a list of people, we can get a list of addresses, but that's not true anymore. We found out that we can only get a list of potential addresses, so we have to adjust the type signature.
getAddresses :: [Person] -> [[Address]]
Now every use of `getAddresses` will have to be adjusted to the new requirements. Etc etc.
Granted, this is a very simple example, but I hope it illustrates how static languages facilitate extremely fast prototyping. Sure, a Lisp REPL is very very nice, but in my personal experience it's no match for a type system. We didn't even have to mock data to start experimenting!
(And yes, Haskell, OCaml, PureScript, Elm etc all have a REPL too).
- PeCaN 10y agoWhile I agree, getting used to that mode of thought takes time. IME you have to write a lot of Haskell (or OCaml) before it becomes a very fast prototyping language. Of course, it's 100% worth the investment, and I prefer prototyping in OCaml or Mercury to basically anything else, but it certainly wasn't like that from the first time I picked up OCaml.
- jakub_h 10y ago> "Static languages, in particular Haskell, PureScript, etc, are unparalleled when it comes to fast prototyping or design space exploration. The compiler can show you whether your idea even makes sense before writing big chunks of business code. How? By building the structure/hard stuff first and letting the compiler verify it while leaving out the uninteresting parts." Why shouldn't I be able to do this on a meta-level? There does not appear to be any restriction on, for example, Lisp code regarding the use of problem solvers and provers. The same should go for other metalanguages (perhaps even better, without forcing me into specific semantics). (Likewise, generative solutions might reduce this problem simply by performing a sequence of correctness-preserving transformations from a higher-level specification. That would shift the burden to checking the specification, which would require a custom checker anyway. Haskell's capability to check or automatically derive stuff seemed limited the last time I looked at it.)
- pka 10y agoAgreed. My comment wasn't aimed that much at Haskell in particular (even if it's my language of choice), but rather the idea of using structure/types for fast experimentation, rather than just a REPL. Also, using a type checker to wholly check your Lisp code basically makes it a static language, the difference then is pretty much philosophical I'd say.
- jakub_h 10y agoRecently I've found myself having severe problems with seeing clear borders between many concepts. IF expressions, type-based dispatching, matching, generic functions, predicate dispatching...a lot of it basically boils down to the same thing, only expressed in different ways. The problem is that the same thing goes for type systems in my head. Types define sets of values, but if your language hardcodes what kinds of sets of values you can express, chances are that you'll have to express whatever residual distinction between values there is (that you can't encode into the value type) into one of the above-mentioned decision-making processes, and at that point, they go sort of out of sight of the typing/proving machinery. I'd rather avoid someone forcing me into using a hardcoded type system, among other reasons because I'm contemplating a (perhaps novel?) search-based program/expression-manipulating system that wouldn't play well with any fixed typing system. For one thing, the types of expression results (being return values of operators applied to input expressions or programs) can easily be emergent (is the resulting expression linear? Is it an odd function? Is it analytically integrable? Etc.) and not easily arrived at in something ML-like. If I had to use something like Haskell, I'd still be rolling out my own type system/prover on top of the existing language implementation anyway. However, types in general (as something you can compute with in the meta-program) would be absolutely mandatory for a system like this (for example, some algorithms or operations can have more desirable refinements that work only on subsets of values - consider determinants of triangular matrices, with triangular matrices being an emergent type - and I absolutely want to find out if such a thing is available for the specific problem being transformed), just not types that any specific existing language offers, to my knowledge. So it's not that I dismiss the notion of proving things about programs - that is a vital thing to have - but the ability to impose restrictions on a program from the outside seems much more flexible to me than going for some fixed type discipline that could force me to straddle inconvenient fixed walls in the structure of a complicated program (such as this transformation system that would search the tree of possible transformations for a result with some desirable properties, with the transformations concisely expressed in some very-high-level DSL source code).