I like the idea, but I do not like the execution.
Designing a programming language that someone actually wants to use is a tiresome effort, fraught with pitfalls. Moreover, your language doesn't seem like something I'd actually want to use. If I want to draw a few lines, sure. But what if I want to define multiple shapes and compose them differently?
If I had to write SVG graphics programmatically, I would use diagrams every time.
Instead of having some half-assed programming language, I have the full power of Haskell, and a language very similar to this one could essentially be implemented as a DSL.
For example, the code below creates two checkerboards, using a function which takes two diagrams as arguments. I can even create a checkerboard, then pass that to checkerBoard
to a create a checkerboard of checkerboards.
squareChessBoard = checkerBoard (square 0.5 # fc red # lw none) (square 0.5 # fc black # lw none) 10 circleChessBoard = checkerBoard (circle 0.5 # fc blue # lw none) (circle 0.5 # fc yellow # lw none) 10
checkerBoard :: Diagram B -> Diagram B -> Int -> Diagram B checkerBoard d1 d2 dim = vcat . take dim $ cycle [fRow, sRow] where rowList = cycle [d1, d2] fRow = hcat . take dim $ tail rowList sRow = hcat . take dim $ rowList
If you know a general-purpose programming language, some have diagram libraries. For example:
Nice thing about this is that you can build up your own tailored library of useful functions and take advantage of the general nature of the language to fetch/generate/munge the content before drawing it.
Diagrams tries hard to be welcoming to newcomers, regardless of experience level. It's a large project with lots of moving parts, which can be a bit intimidating at first (from a technical rather than social point of view); on the other hand, it also means there are always tons of potential projects of varying difficulty. If you're interested come join us in the #diagrams IRC channel on Freenode (though note you may not get an immediate response depending on who is around when, just hang out and someone will respond eventually).
Ultimately, the best way to start getting involved is to start getting involved. There's no magic list of steps; just find some projects that are interesting to you, and start doing something, anything! Read the documentation and correct typos. Make some examples. Think about missing features. Maybe you'll find that the project you thought you were interested in is not so interesting after all; that's OK, you learned something in the process and you can find a different project.
Cool idea.
I agree with /u/gelisam that the notion of consumption makes no sense. Not to optimize too early, but your parser should also get more efficient if it can't modify the grid by consuming its contents.
On a more general note, jumping straight to the notion of a 2D parser seems like skipping a conceptual step or two. Think about grammars first. Chomsky-style generative grammars have properties like:
L (G1 | G2) = L(G1) U L(G2) L (G1 <> G2) = L(G1) <> L(G2)
A 2D grammar should have the same properties, except instead of simple string and grammar concatenation you'd need four different directions. Look at diagrams for some combinator inspiration.
> Strong host language type system harms an ability to build strong DSL type systems (not prohibits entirely, but makes it harder).
Would you elaborate? Outside of some provably impossible corner cases, like writing an interpreter for a total (= not Turing-complete, all programs terminate) language in itself, I think it's actually easier to embed a strongly typed language in another, as you can leverage the host's type system. For example Haskell has Diagrams, which is called an EDSL by the authors and indeed doesn't look much like Haskell at times, but at the end of the day it's just a library that can be used in unrelated code. I figure that with a more powerful type system, for example having dependent and refinement types (like F*, for example), there are even more options for writing DSLs.
The diagrams project has lots of potential places to contribute and is a lot of fun to work on. We're happy to help newcomers get up to speed and find ways to contribute.
I'm happy to see that many people have beat me to mentioning diagrams. I wager you would really enjoy playing with it. You should definitely come join us in the #diagrams IRC channel on freenode, we are a very friendly bunch (with a wide range of experience in both functional programming and art) and would love to chat, answer questions, and help you get started. There's an easy web interface here if you have never used IRC before.
+1 for giving haskell a go.
Whatever your problem domain, Haskell is a beautiful language and writing haskell has an aesthetic appeal that can only enhance your enjoyment of the hobby. You'll have some more laptop-throwing moments as you ascend the learning curve, but coding quickly becomes more pleasant and certainly more than a means to an end.
You'll also be going from a consumer
of ideas within the mature world of Processing (a fantastic project that no haskeller would bag just because its java) to an explorer
where the path isn't laid out for you.
Diagrams is the first place you should look for visual expression: http://projects.haskell.org/diagrams/
I have some ideas about examples to give.
I would include something that's easy to understand without too much programming at all. Something like diagrams would already be a pretty nice introduction to how combinators could be used to combine Haskell programs, or in this case, cute little shapes.
Monadic parser combinators would also be a nice-to-have.
servant shall amaze your audience by its ability to generate client Haskell functions, client JS code, as well as scaffolding around your whole server handler code base, all staticly, within Haskell, so you only write the functions and servant fits them together. An example that's a bit cheaty is this world most concise image conversion HTTP API.
I would say to include amazing equational reasoning, but I don't have anything good in mind.
I'm glad you asked! I used http://projects.haskell.org/diagrams/ to randomly generate the tiles with different weights, then tuned the "final" set of tiles manually. The source code for the tile generator is here: https://github.com/5outh/trash-kings
> Finally, best of luck with your GUI library. Honestly, even with its problems, matplotlib is the biggest reason I keep coming back to Haskell. It's amazing how many plotting utilities don't have something as fundamental as imshow. Actually, given my explorations into other plotting packages, it's disturbing how many utilities can't even handle errorbars or a log axes.
Thanks. You mean to Python? Yeah, in Haskell one would probably have to hack something up with Diagrams.TwoD.Image and then, if needed for any reason, glue it together with a Chart by using the Chart-diagrams backend. Though Chart at least does support errorbars and log axes ;)
With a declarative language like graphviz
it can be a real pain to fight the layout engine to get things looking "right", it seems a better solution for large graphs where the layout isn't precisely known before-hand. I just had this problem and resorted to using a GUI diagram editor (Dia), and svgbob for a second diagram, and while both worked only svgbob allows for the diagram to be seen in-line with documentation basically as it appears when rendered which is a plus for me.
edit: not that there aren't better declarative graph drawing tools out there, one I've looked at but not really tried is a Haskell library/DSL called Diagram
I would argue that overlay
makes for the more natural monoid instance. It reminds me of the Monoid
instance for diagrams where the monoid instance places one diagram on top of another and placing diagrams adjacent to one another is relegated to a separate operator.
The Diagrams Manual lists all of the type classes in the library and how they're used to organize and transform the contents of the affine space.
Personally, I have to agree with /u/nikofeyn . My experience is that simpler type signatures are often better, and I think that the Haskell Prelude
is a role model in Haskell API design. With more fine-grained type than that, things get unwieldy fairly fast.
(I have ventured into the realms of higher rank myself, but I am no longer convinced that the extra type parameter is a worthy trade-off.)
That said, I do think that the actual code in the diagrams tutorial and manual is very simple and clear, it is mostly the type signatures that I find rather complicated at times.
You could have a look at the diagrams package: http://projects.haskell.org/diagrams/ and try and wrap that up in an FRP library for the UI interaction.
(caveat I'm probably even newer than you to haskell so I probably don't know what I'm talking about)
The "spider web" is because the background is transparent.
To set an actual background color instead of transparent, use bg
:
> To "set the background color" of a diagram, use the bg function—which does not actually set any attributes, but simply superimposes the diagram on top of a bounding rectangle of the given color. The bgFrame function is similar but the background is expanded to frame the diagram by a specified amount.
(Taken from http://projects.haskell.org/diagrams/doc/manual.html#texture. It's at the very end of the "Color and Opacity" section, just before "Linear Gradients".)
From Brent Yorgey's paper on Monoids in Diagrams (bold added):
Actually, unD0 still suffers from another performance problem hinted at in the previous variation. A right-nested expression like d1 (d2 (d3 d4)) still takes quadratic time to compile, because it results in left-nested calls to (++). This can be solved using difference lists [Hughes 1986]: the idea is to represent a list xs :: [a] using the function (xs++):: [a] → [a]. Appending two lists is then accomplished by composing their functional representations. The“trick” is that left-nested function composition ultimately results in reassociated (right-nested) appends:
(((xs++) ◦ (ys++)) ◦ (zs++)) [ ] = xs++ (ys++ (zs++[ ])).
In fact, difference lists arise from viewing
(++)::[a] → ([a] → [a])
itself as a monoid homomorphism, from the list monoid to the monoid of endomorphisms on [a]. (H1) states that (++) ε = ε, which expands to (++) [ ] = id, that is, [ ] ++xs = xs, which is true by definition. (H2) states that (++) (xs ys) = (++) xs (++) ys, which can be rewritten as
((xs++ys)++) = (xs++) ◦ (ys++).
In this form, it expresses that function composition is the correct implementation of append for difference lists.
Huh, but you are not supposed to do these things by hand!
It is easy write programs to generate the mathematical structure, and there are libraries to make graphics from them. For example this would very easy to do with diagrams
I keep hearing about the difficulty of going from an imperative programming background to learning functional languages, and it makes me glad I got into Scheme and Haskell relatively early.
Have you tried working through Learn You a Haskell for Great Good? It's an excellent book and goes well with some of the introductory wikibook chapters. Probably the thing that's helped me most in getting familiar with Haskell has been reading through good expositions of code snippets, like on the LiteratePrograms wiki and in some of the more well-written libraries. For playing around with declarative programming there's the (slightly addictive) Diagrams package which can help make things more tangible by giving visual feedback.
And when I do functional programming I can see...
parsers that look like the grammar they're implementing
And writing a short, readable program and having it run perfectly the first time? How cool is that?