[OpenSCAD] Extending OpenSCAD from assembler to C or Perlish language and adding standard library
doug at moens.org
Tue Oct 1 11:08:26 EDT 2019
On Tue, Oct 1, 2019, at 3:02 AM, nop head wrote:
> People say it is hard to write algorithms without mutable variables. Does that mean it is hard to write algorithms in Haskell or does that have them as well?
Haskell and OpenSCAD are at opposite ends of the spectrum, in terms of expressive power. It's true that Haskell and OpenSCAD are both declarative languages with immutable variables, but aside from that, they are totally different.
Haskell has many features and idioms which are not available/not possible in OpenSCAD, which are used as an alternative to mutable variables.
0. Haskell has generalized tail recursion optimization. The corresponding feature in OpenSCAD is restricted to one specific code pattern, and only works for self-recursive functions, not mutually recursive functions.
1. Haskell has combinators, which are functions that take functions as arguments, and return functions as results. There is a large standard library of combinators, which are used as functional control structures, and replace most uses of tail recursion. These library combinators use tail recursion internally, and encapsulate high level patterns of tail recursion. Tail recursion is considered to be a "low level" coding pattern, which you only resort to when necessary.
This style of programming will become possible in OpenSCAD once function values are added to the language. To fully support this style of programming, we would want better tail recursion support, and a very terse syntax for anonymous function literals.
2. Haskell has lazy data structures. Notably, it has lazy lists. A lazy list is a potentially infinite list, in which list elements are only computed the first time you access them, then the element values are cached. Using lazy lists, you can decompose an imperative loop into two pieces: the piece that generates the sequence of elements is encapsulated as a lazy list. The piece that consumes the sequence of elements is now separate. This enables a new kind of modularity and a new style of programming.
3. Haskell has monads, which are a generalization of sequentially executed statements in imperative programming. In OpenSCAD, you can use sequences of if statements and for statements at the top level, or inside a module, to construct an "implicit union" of shapes. In Haskell terminology, we would call that the "union monad". In OpenSCAD, you can also use this same statement syntax inside a list comprehension, to construct a sequence of list values. This corresponds to the List Monad in Haskell. Haskell has many other monads, and it's easy to define new ones.
One of the things that originally impressed me about OpenSCAD is the fact that it has monads (which are declarative) dressed up to look exactly like C statements and control structures (which are imperative). In Curv, I've created something that is essentially a "mutable variable monad". It looks just like imperative programming, but it is syntactic sugar for something that is actually declarative and referentially transparent.
Haskell monads are notoriously difficult to learn (due to the way they are presented). In F#, the same feature is called "computation expressions". The syntax and presentation of computation expressions is much more friendly to imperative programmers. In F#, the "list monad" is called the "sequence builder", and F# sequence expressions are very similar to OpenSCAD list comprehensions, except that there are more statement types, including a "while" statement.
4. In imperative programming languages, you use mutable variables to incrementally build up a compound data structure. You can assign an individual component of an array using `a[i] = newvalue`, and this is an efficient operation. Haskell has functional data structures, which support efficient incremental update without mutation, and Haskell has an "optics" library for efficiently constructing and composing get and set operations on individual elements of a large data structure. Think of optics as a declarative query language.
I think that function values are an essential programming feature, and they will allow us to cherry pick some of the easiest to understand idioms from Haskell. But I also think that imperative style programming idioms are easier for the OpenSCAD community than the corresponding Haskell idioms that are used for doing the same job.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Discuss