Hobby-hacking Eric

2007-07-19

monomorphism redux

There may be errors in this, of course!

the context from wikibooks


Following the previous example, you might be tempted to try storing a value for that radius. Let's see what happens:
Prelude> let r = 25
Prelude> 2 * pi * r

<interactive>:1:9:
Couldn't match `Double' against `Integer'
Expected type: Double
Inferred type: Integer
In the second argument of `(*)', namely `r'
In the definition of `it': it = (2 * pi) * r


Whoops! You've just run into a programming concept known as types. Types are a feature of many programming languages which are designed to catch some of your programming errors early on so that you find out about them before it's too late. We'll discuss types in more detail later on in the Type basics chapter, but for now it's useful to think in terms of plugs and connectors. For example, many of the plugs on the back of your computer are designed to have different shapes and sizes for a purpose. This is partly so that you don't inadvertently plug the wrong bits of your computer in together and blow something up. Types serve a similar purpose, but in this particular example, well, types aren't so helpful.

the new monomorphism-based explanation


The quick solution to this problem is to specify a type for the number 25. For lack of other information, Haskell has "guessed" that 25 must be an Integer (which cannot be multiplied with a Double). To work around this, we simply insist that it is to be treated as a Double
Prelude> let r = 25 :: Double
Prelude> 2 * pi * r
157.07963267948966


Note

There is actually a little bit more subtlety behind this problem. It involves a language feature known as the monomorphism restriction. You don't actually need to know about this for now, so you can skip over this note if you just want to keep a brisk pace. Instead of specifying the type Double, you also have given it a polymorphic type, like Num a => a, which means "any type a which belongs in the class Num". The corresponding code looks like this and works just as seamlessly as before:
Prelude> let r = 25 :: Num a => a
Prelude> 2 * pi * r
157.07963267948966


Haskell could in theory assign such polymorphic types systematically, instead of defaulting to some potentially incorrect guess, like Integer. But in the real world, this could lead to values being needlessly duplicated or recomputed. To avoid this potential trap, the designers of the Haskell language opted for a more prudent "monomorphism restriction". It means
that values may only have a polymorphic type if it can be inferred from the context, or if you explicitly give it one. Otherwise, the compiler is forced to choose a default monomorphic (i.e. non-polymorphic) type. This feature is somewhat controversial. It can even be disabled with the GHC flag (-fno-monomorphism-restriction), but it comes with some risk for inefficiency. Besides, in most cases, it is just as easy to specify the type explicitly.


2007-07-17

Write Yourself a Scheme in 48 Hours (PDF)

One of the wikibookians has made a rather nice PDF out of Johnathan Tang's Write Yourself a Scheme in 48 Hours. The conversion was done semi-automatically from mediawiki syntax to LaTeX [in Java... tsk]. Many thanks to Hagindaz for the conversion!


2007-07-15

monomorphism and the unintentional fib

The monomorphism restriction is a simple problem with a scary name.

I think I've run into the first instance where I have actually been able to identify something as being the monomorphism restriction in action (*). The good news is that if you don't understand what the restriction is, this might be your chance. The bad news is that many Haskell newbies might have been hurt in the process, because it involves an unintentional fib that I told in near the beginning of the Haskell wikibook.

(*) I'd appreciate it if somebody could fact-check me on this.

circles and half-truths

High school Geometry. We've got a circle of radius 25 and we want to know its circumference (2 * pi * r). Now let's see what happens when we type it into GHCi

Prelude> let r = 25
Prelude> 2 * pi * r

<interactive>:1:4:
No instance for (Floating Integer)
arising from use of `pi' at :1:4-5
Possible fix: add an instance declaration for (Floating Integer)
In the second argument of `(*)', namely `pi'
In the first argument of `(*)', namely `2 * pi'
In the expression: (2 * pi) * r


Oops! At this point, the reader runs into types for the very first time. This morning, I realised to my horror that I might have given a very wrong explanation of the problem to the gentle Haskell newbie. I said

The main problem is that Haskell doesn't let you multiply Integers with real numbers. We'll explain why later, but for now, you can get around the issue by using a Double for r so that the pieces fit together:

Prelude> let r = 25.0
Prelude> 2 * pi * r
157.07963267948966


Which is true, but is only sort of a half-truth. The problem with my explanation is that it lets the reader walk away with the mistaken belief that numbers without a decimal point, such as 25, can only be integers, when really they can be any Num a. It's as if somebody had taught OCaml too recently and forgotten that haskell /= ocaml! (Coughs discretely)

A concrete example of why it's important to get this right can be found further down the chapter. Here, I want to show that we can use variables within other variables. So here's what I have the reader type in area = pi * 5^2:
Prelude> let area = pi * 5^2

And here everything works... except...


Except if you are a sharp-eyed reader, you remember from above that I had just said that types prevent you from multiplying integers with reals and I had unintentionally implied that numbers like 5 are integers. So if you are a sharp-eyed reader, you look at that thing and you say to yourself, "HUH? That shouldn't work! You can't multiply an integer with a real!"

monomorphism, like polymorphism without the poly

The real problem is not that we had set r to an integer. By right r = 25 should give us any Num a => a; however, since we do not give it a type signature, r gets restricted to being an Integer. In fact, the example of 2 * pi * r would have worked if (a) we had given r a polymorphic type signature or (b) we had run GHC with its 'no monomorphism restriction' extension.

polymorphic type signature

Here we add an explicit type signature to r. Everything works:
Prelude> let  r :: Num a => a; r = 25
Prelude> 2 * pi * r
157.07963267948966
(Thanks to shachaf on #haskell for reminding me that we can use {}/; syntax and showing me how to apply it to write type signatures)

-fno-monomorphism-restriction

And if you don't like type signatures, here's what it looks like running without the monomorphism restriction:
dewdrop /tmp % ghci -fno-monomorphism-restriction
___ ___ _
/ _ \ /\ /\/ __(_)
/ /_\// /_/ / / | | GHC Interactive, version 6.6, for Haskell 98.
/ /_\\/ __ / /___| | http://www.haskell.org/ghc/
\____/\/ /_/\____/|_| Type :? for help.

Loading package base ... linking ... done.
Prelude> let r = 25
Prelude> 2 * pi * r
157.07963267948966
No surprises.

helping the newbies

Clearly, my explanation needs to be fixed. I just need to figure out the right way to do it though. I really don't want to get too technical (the reader doesn't even know about types yet!), but I'll need to avoid lying to the reader. It's already bitten two users, and it took me one of my readers typing in this text for me to figure out what had happened:
You might be thinking that this won't work--isn't 5 an integer, and therefore 5^2 also an integer? And didn't we just get an error trying to multiply pi by an integer?. What's going on is that when you "let r = 25", the "r" you get is more restricted than using the literal string "25" or 5^2. Try :t r and :t 5^2 and see the difference

I'm not entirely satisfied with this attempt (sorry), and want to deal with the situation more gracefully. Just don't know how to go about it yet.

knowing, Knowing and poly/mono


Oh a word about the scary name 'monomorphism restriction'. I find it curious that I should have found that name scary for so long. I mean, for the longest time, I've told myself that I liked 'polymorphism' right? So how difficult would it have been to do a little etymology and notice that 'monomorphism' sounds exactly like 'polymorphism', except that you replace the 'poly-' (many) by 'mono-' (one). By the right, the two words have equivalent scariness! But for some reason, my brain somehow refused to recognise the fact. Instead, it associated one word with warm fuzzies and the other word with huh-does-not-compute.

Otherwise, one thing I found interesting about this is how you can simultaneously (a) hold a piece of knowledge and (b) not apply it consistently. For example, when I had written that module, I knew that numbers could be any Num a (and that you could do fun things making up crazy implementations of Num), yet at the same time as I was using this knowledge (I told myself 'true, but let's not talk about that now, no point confusing the newbies'), I can completely failed to apply that knowledge, because I went back and reflexively treated 25 as an Integer, probably due to all that freshman OCaml teaching. You know something, but you don't Know it.


2007-07-13

what's in season?

Another programming project for those of you who are just itching for something to code. Basically, I want a website which can tell me, given my current location, what fruits and vegetables are in season right now.

Some thoughts, questions and requirements
  • The site must be dead simple to and very pleasant to use. This is not something you should have to read documentation to figure out.
  • This kind of thing could be easily international, so I want pictures. Maybe you can grab them from the Wikimedia Commons. I guess it would be fair to give you bonus points if you localise the thing, or maybe let me play with the language settings so I learn how to say 'rutabaga' in Arabic.
  • How does the user tell you where s/he lives? As a default, it would be nice if you auto-detected it, but what might be nicer also is if I could play around and plug in different locations. How would you pick a location? By pointing at a map of the world? Also, maybe you don't just want a single point in the map, but a region of N kilometers around me. The question is basically, what grows N kilometers from where I live, where I get to specify
  • Likewise, what do you do about the current date? It would also be nice if I can play around with this, asking not just 'what's in season right now' but 'what's in season during wintertime?'
  • Where is all of your data coming from? How are you going to store it and look it up? What kind of data do you really need?
  • If you want to get really really fancy, you can make the site adapt to current events. Maybe parse newspaper texts to find out that it's really not a good year for mangoes.
This is not necessarily a Haskell project (although in my silly, silly eyes, everything is potentially a Haskell project), but this might be a fun way to learn how to do web stuff and maybe play around with databases. In fact, such a project might also be useful for building a Haskell web tutorial, a kind of site that we can build together. Simple objectives that everybody can understand, and actually useful for something.

This project might also be a good way to learn about building user interfaces. Or maybe if you're not interested in working on that stuff, it would be a good opportunity to partner up with somebody else. They worry about the UI stuff and you worry about the code. I don't know anything about UI, except that I think it's important to get it right. If it helps, I greatly enjoyed Donald Norman's The Design of Everyday Things, as well as Bret Victor's Magic Ink.


2007-07-05

mediawiki code projects

Three more projects to practice your Haskell with, and produce something useful while you're at it:
  1. a mediawiki writer for Pandoc (should be a piece of cake)
  2. a mediawiki reader for Pandoc (perhaps less easy, note that there is also some HTML to deal with)
  3. a mediawiki template engine : given a set of mediawiki pages on the local filesystem, convert mediawiki input into mediawiki output, with all templates interpreted
My super-seekret reason for suggesting these projects is so that we can one day convert the Haskell wikibook to LaTeX, or something else, and produce a nice PDF. Naturally, it would also be useful for the other wikibooks, many of which have crappy PDFs, or none at all. But that's not for you to worry about :-)... just have some nice exercises to play with.

(#3 might be a bit of work... and also, it's not clear that this is exactly what we want for converting wikibooks. It seems that the point would not be to expand the templates, but to convert them to something else. If I have a template called HaskellExercises, I don't want to expand it to a bunch of div tags or whatever; I want to convert it to something else)


2007-07-01

haskell for reprap?

Another potentially fun and probably big project for Haskellers: software for the RepRap project. The goal of RepRap is to build an open-source 3D printer for under $500 and with the ability to print out its own parts. Their control software is written in Java... borriiing.

Maybe this is the kind of niche that Haskell could jump in to, something a little unusual (like darcs and xmonad), and very useful at the same time (like darcs and xmonad). My rough thought was that we could similar successes with xmonad, building solid and minimal code for something that is real world (you don't get any more real than physical objects).