Hacker News new | past | comments | ask | show | jobs | submit login
Try Haskell (tryhaskell.org)
111 points by boryas on Feb 23, 2010 | hide | past | favorite | 56 comments



Does anyone have any suggestions for beginner Haskell projects?

I've read through some Haskell material before and tried following tutorials, but I always end up dropping it because I can't think of anything for which I would use it.

I have no problem with functional and functional-esque programming (Erlang, Common Lisp, etc.), but I just can't come up with anything to do in Haskell. :(

EDIT:

Thanks for the great suggestions, everyone! I think I'll do some crpyo-based maths work in Haskell since that is what holds my interest at the moment. :-)


I usually start picking up new languages by taking something I've written and translating it into the new language.


exactly my approach, also you can try college homework assignments found via google.


That's a good way to see if the language actually helps you do things easier, too!


I always end up dropping it because I can't think of anything for which I would use it.

What do you normally program? Do that, but in Haskell. It's a general-purpose programming language, and there are plenty of libraries to help you in any area.


As someone who sympathizes with the OP's way of learning programming languages, I think what I'm interested in seeing is some commentary on where Haskell's "sweet spot" may be. There are tons of languages out there, and I don't want to learn new ones just for the sake of it. Ok, actually I do if I'm honest with myself, but I need some kind of practical justification for it:-) With Erlang it's easy to say "oh, cool, this is really, really good for this type of application". Haskell seems like it's fairly fast and perhaps good for doing calculations, but that's the only vague notion I have of what it might be useful for in the real world.


I've been busy learning Haskell on and off between classes since December. And the main points I noticed so far are:

tl;dr version:

1) It's a pretty language.

2) It's fast.

3) Static typing (and its optional companion "formal verification") rock.

4) Higher-order functions, Algebraic Data Types, Polymorphism and currying are our friends.

5) Exceptions are evil[1], explicit error handling is safer. Finally a language that hands me more convenient way of explicit error handling then:

  int result = someCLibraryCall();
  if (result == -1) {
    fprintf(stderr, "Ach, mein leben!");
    exit(EXIT_FAILURE);
  }
Long verbose version: 1) Haskell comes with lots of nice syntactic sugar:

Arbitrarily changing prefix into infix functions or vice versa:

  elem foo list == foo `elem` list
  1 + 2 == (+) 1 2
Python-like indenting for blocks instead of braces (you could also use braces, but I've gotten allergic to them since learning python)

2) For a language as high-level as Haskell, it's FAST. Most of the benchmarks show it pretty consistently in the C/Java performance regions (depending on what you're doing of course).

3) I used to hate static typing and think dynamic typing was the "end all, be all" of typing solutions until I start learning Haskell and suddenly realized I don't hate static typing, but that I hate crappy static typing implementations (Java, C, I'm looking at you).

A bonus of this is that it makes program verification of Haskell programs A LOT easier. During my class on protocol validation the mu-calculus we used for verifying programs was almost trivial to translate to Haskell (and vice versa).

I'm a firm believer in "formal verification" as a means to detect/prevent bugs. And while it might not be an issue for the programming world at large right now[2] (who cares if a word processor or browser crashes), it is important for mission critical software on things like cars, train, airplanes and space shuttles...

As a side note, I still like and use dynamic systems like python, but only for "trivial" code. i.e. quick scripts and stuff where I don't care if it breaks.

4) I find that with Haskell I'm usually working on a much higher level of abstraction then otherwise. Which means I'm spending more time thinking and scribbling on my white board and less time writing code and fixing stupid mistakes.

5) Monads like Maybe and Either allow for various convenient ways to do explicit error handling (there's probably a gazillion more ways to do explicit error handling with monads, but I don't grok them enough yet).

While Haskell still has exceptions they're far more limited and more sparsely used then in other languages.

EDIT: Removed very verbose and vague description of the Maybe monad, examine the example posted by jmillikin below instead.

In conclusion, what's Haskell good for? Well, I find it lends itself pretty well for high-level, abstract, meta sort of programming. The type a lot of people advertise Lisp for. And while Lisp macro's might be a tad more expressive[3], Haskell is most certainly prettier. And as behoofs any (ex-)python programmer I'm convinced readability matters.

All this while still being fast, reasonably good at stopping you from writing bugs and relatively easy to debug. Sounds like good enough reasons to use it, for me.

[1] - I'm not gonna argue "why" here, if you want to know I recommend Googling "Exceptions considered harmful" or "why exceptions suck" and you'll find plenty of in-depth explanations.

[2] - Actually, I do think it is relevant to ALL programmers. But that's more of a personal opinion which not a lot of people seem to share.

[3] - This is a hunch, learning Lisp/Scheme/Clojure is still on my todo list, so I'm not entirely sure if Lisp macro's can do things which are impossible in Haskell or not.


Lisp's macros are a lot more expressive. They don't look weird (unlike Template Haskell) within the language, they look like normal constructs. And they're native to Lisp. I miss Lisp in Haskell because I can't define, e.g., my own macro to do this:

    case fileExists "sausage.txt"
      True -> putStrLn "Gonna do something with the sausage."
      False -> putStrLn "Woop."
And/or

    if do fileExists "sausage.txt"
       then putStrLn "Gonna do something!"
       else putStrLn "Woop."
Or lambda with alternate lambda cases.

    (\case of (Just a) -> a; Nothing -> b)
I wrote a little mini-lang to do this to see how much I liked it. I liked it a lot, Lou!

But Haskell is terse and predictable so one puts up with not having macros.

The Computer Language Shootout Haskell samples are low level, if you read them. Some are high level but many are nearly C, using malloc and such. But this is a good thing; you can write the "tight loops" that you need within Haskell.


try this (Write Yourself a Scheme in 48 hours)

http://jonathan.tang.name/files/scheme_in_48/tutorial/overvi...


I'll second that. 48 hours is optimistic as heck (or I'm just that bad), but it definitely has helped me wrap my head around Haskell a little better than it was before.


Awesome, I'll look into this, too. :D


I learned the basics of Haskell by doing some problems from http://projecteuler.net. It's probably not as exciting as actually building something using the language, but it's definitely worth checking out.


Something with lots of threads.


...with STM thrown inside (an in-memory DB?)


Install xmonad and configure it properly


That is 99% copypaste, and you don't learn how to actually write your own Haskell programs.


Probably true. At least you will see some Haskell-syntax.

Writing an extension for XMonad may be worthwhile, though. Or learning about its inner workings. (There are some good introductions floating around the net. They put a lot of thought into the types in XMonad.)


Cool! I really like what the Haskell community is doing lately to reach out to new users. As someone who didn't know anything about functional programming a year ago, I can say that I've learned a lot just by messing around with it a little bit.


Same here. I can only recommend to learn you a functional programming language for greater good. I love every minute I spend writing Haskell code, be it a simple console application or something more complex. It's really fun, interesting and educational, and I'm only at the beginning :)


I applaud the effort, but this is far from complete. As far as I can tell, you can only do standalone expressions, to the exclusion of anything interesting.

    Type Haskell expressions in here.
    > let x = 10
    not an expression: `let x = 10'
I understand that mueval has this limitation too? It's more defensible in the irc context that "state" would be disallowed. Here, it's just crippling.

I don't need the mtl stuff, but being able to define a basic function would be nice!

http://codepad.org/ will run full programs for you ... I guess that'll continue to be my tool of choice for online Haskell prototyping.

Still, this project does seem promising.


The developer posted on Reddit that this was a premature release. (Clarification: That is to say, he did something like email the link to a buddy and it unexpectedly ended up on Reddit, not that it was formally released and then regretted.)

To be honest, if you're at the point where you want that sort of thing, I'd generally suggest simply downloading ghci. ISTM that all these "try it online" things are good for are making the decision of whether you want to bother with that step. (Perhaps I'm spoiled on Linux where downloading GHC or Ruby is hardly any harder than visiting a web page anyhow.)


You can at least do this:

  > let x = 10 ; y = 5 ; in x + y
   => 15
   :: (Num t) => t


Nice, but needs more steps... get me to the point where I understand what a Monad is, because I really want to know!


I think the reason I've avoided getting into Haskell is that it seems like, no matter what tutorials or references I read on it, I never make it any further into http://www.willamette.edu/~fruehr/haskell/evolution.html before I completely lose track of what's going on. Haskell seems like it has all the same stuff as most other languages, but then there's this whole other layer of knowledge (mostly mathematical problem-domain knowledge) you have to add on before you can actually claim to "know" Haskell. I'm always hoping there'll be a tutorial that covers that sort of stuff, instead of just saying "here's how to do in Haskell the stuff you already know how to do in Ruby."


> all the same stuff as most other languages, but then there's this whole other layer of knowledge (mostly mathematical problem-domain knowledge) you have to add on before you can actually claim to "know" Haskell.

That's just computer science -- a bunch of CS stuff is easier to express in Haskell, so we do, but it might need some background.

> here's how to do in Haskell the stuff you already know how to do in Ruby

Try a different tutorial. Maybe: Real World Haskell?


I am not sure, but it's worth checking: You do know that link is a joke, right? "Senior Haskell programmer" is where reality stops (give or take an entry or two, not counting the last "tenured professor" one), and if you can't get "foldr" you're ill-equipped to deal with more advanced Javascript techniques either.


Yeah, I'm aware that the whole point of it is the needless complexity of the latter solutions—still, you have to know Haskell to understand exactly why the latter solutions are so ridiculous (beyond merely gawking at them unappreciatively) and you have to understand Haskell even better to actually come up with the penultimately-contrived solutions.

I'd like to be able to tell those jokes without it being like making sounds in a foreign language—that's what I mean by "knowing" Haskell. You can't speak a language until you can make a witty retort in it ;)


I think YAHT is sorta decent in that regard. In the fourth chapter it teaches you enough to do something, and then it ramps you up a bit. It's still really confusing, but it's better than usual.


Exactly, multiplying two numbers and reversing a string aren't what got me interested in Ruby. TryRuby was an absolutely frictionless way to learn the basics because it had a few lessons built in.

I'll be back to this site in a few weeks to check for progress...


I don't understand how people keep failing to understand monads. Maybe it's the line noise operator `>>=' ?

Lets define a simple type, `Maybe', which can store either a value or an absence of value:

  data Maybe a = Just a | Nothing
    deriving (Show)
And define a function which compares a number against a limit, and returns `Nothing' if the value is out of range:

  clamp :: Ord a => a -> a -> Maybe a
  clamp limit x = if x > limit then Nothing else Just x
Easy enough. Now, how should the number be compared against multiple limits?

One way is to just brute-force it:

  multiclamp :: Ord a => a -> a -> a -> Maybe a
  multiclamp lim1 lim2 x = case clamp lim1 x of
    Nothing -> Nothing
    Just x' -> clamp lim2 x'
But this is ugly. Lets use monads to simplify it.

First, take a look at the core Monad operations. I'm going to use `build' and `bind' instead of `return' and `>>=', because they're probably more familiar to most readers.

  class Monad m where
    build :: a -> m a
    bind :: m a -> (a -> m b) -> m b
Next, we'll define an instance of the `Monad' typeclass for `Maybe'. It will use the same semantics as the `multiclamp' example -- that is, if the first test returns `Nothing', the entire computation will return `Nothing':

  instance Monad Maybe where
    build x = Just x

    bind Nothing  _ = Nothing
    bind (Just x) f = f x
Using this definition, `multiclamp' can be written thus:

  multiclamp2 :: Ord a => a -> a -> a -> Maybe a
  multiclamp2 lim1 lim2 x = bind
    (clamp lim1 x)
    (\x' -> clamp lim2 x')
Although ugly, this notation is sufficiently generic that the compiler can generate it from an imperative notation. Lets look at two more examples. First, `multiclamp2' written using "real" monads. Notice that this is exactly the same as before, except `bind' is an operator named `>>=':

  multiclamp3 :: Ord a => a -> a -> a -> Maybe a
  multiclamp3 lim1 lim2 x =
    (clamp lim1 x) >>=
    (\x' -> clamp lim2 x')
And finally, using the imperative-style `do' notation. Note that although this is imperative, it is not impure -- this is semantically equal to `multiclamp3':

  multiclamp4 :: Ord a => a -> a -> a -> Maybe a
  multiclamp4 lim1 lim2 x = do
    x' <- clamp lim1 x
    clamp lim2 x'
This is, obviously, a superficial example -- you'd never see such verbose code in code written by an experienced programmer. But the verbosity helps to visualize what the compiler is doing.

For completeness, here's a "cleaner" version, which takes advantage of currying and the combinator `.':

  multiclamp5 :: Ord a => a -> a -> a -> Maybe a
  multiclamp5 lim1 lim2 = (clamp lim2 =<<) . clamp lim1


> I don't understand how people keep failing to understand monads. Maybe it's the line noise operator `>>=' ?

For me at least, the mathematics line-noise is a bigger issue, and it made more sense once I ignored it. As a programming construct, monads seem quite understandable to me, even clever. But many of the explanations, especially earlier ones, started out with a type-theoretic explanation with links to category theory...

In particular, I was under the misimpression for years, because of it being presented that way, that monads were essentially of interest only for people who were hung up on type-checking: that they were a solution to how to make the type-checking go through on a certain class of problems, by lifting an underlying type into the Monadic type and getting it back out again. As someone who mainly uses dynamically typed languages, this didn't seem of interest, since in Lisp, I don't care if the type-checking goes through or not. It was probably years later that I figured out they had some non-type-related programming benefit.


Which are? I've read somewhere they help improve the modularity of your code, is this what you're referring to?


Functional programming is very focused on composing operations. Function composition is an obvious example, but it is not the only one. As far as I understand monads, they allow you to write generic operations separate from the logic needed to compose those operations.

Inspired by this article. and in a fit of temporary insanity, I implemented a simple monad protocol and the Maybe and List monads in Clojure. It's not fit for use, but it was fun to write.

http://gist.github.com/312281

It may not be immediately evident what is being composed there, but if you look at lift, it breaks the multi-argument "+" operator into several partial applications and composes each of those under the given monad, giving interesting results. This was necessary to maintain support for a variable number of arguments.

Note that the code uses features only available in the git master branch, so you will need a snapshot build to run it.


I've used the Option class in Scala, which, if I understand correctly, is a direct translation of the Maybe monad, and honestly, I have an extremely difficult time trying to understand your post. I don't blame you, either. I've had a very had time understanding every explanation of monads on the web, even though on the surface they look like they'd be really easy to understand.

http://lamp.epfl.ch/~emir/bqbase/2005/01/20/monad.html has an explanation from scala's perspective. I can understand the first part when the author describes a monad as an object with a polymorphic type, a map function, a flatten function, and a singleton constructor function. Everything they said beyond that goes right over my head.


I think for those of us that have a C language family background, parallel examples in both C (or C# or Java or Python) and Haskell would be very beneficial! We have two hurdles to jump: the concept of monad AND the syntax.


C and Java can't represent monads at all, since they don't support closures.

C# and Python can, sort of, but their syntax and object-oriented semantics make it somewhat difficult. I don't know C# well, and Python needs a lot of magic[1] to get reasonable-looking code.

Here's a Python example. It's not a direct translation, but is close enough that you should be able to figure out the original. I've included the Haskell code in comments.

  import abc
  
  # class Monad m where
  #   build :: a -> m a
  #   bind :: m a -> (a -> m b) -> m b
  class Monad (metaclass = abc.ABCMeta):
  	@classmethod
  	def build (cls, x):
  		raise NotImplementedError
  
  	def bind (self, f):
  		raise NotImplementedError
  
  # data Maybe a = Just a | Nothing
  #   deriving (Show)
  class Maybe (Monad):
  	def __init__ (self, x):
  		self.__x = x
  
  	def __repr__ (self):
  		if self is Nothing:
  			return "Nothing"
  		return ("Just %r" % self.__x)
  
  # instance Monad Maybe where
  #   build x = Just x
  #
  #   bind Nothing  _ = Nothing
  #   bind (Just x) f = f x
  	@classmethod
  	def build (cls, x):
  		return Just (x)
  
  	def bind (self, f):
  		if self is Nothing:
  			return Nothing
  		return f (self.__x)
  
  def Just (x):
  	return Maybe (x)
  
  Nothing = Maybe (None)
  
  # clamp limit x = if x > limit then Nothing else Just x
  def clamp (limit, x):
  	if x > limit:
  		return Nothing
  	return Just (x)
  
  # multiclamp2 lim1 lim2 x = bind
  #   (clamp lim1 x)
  #   (\x' -> clamp lim2 x')
  def multiclamp2 (lim1, lim2, x):
  	return clamp (lim1, x).bind (lambda x2: clamp (lim2, x2))

[1] http://www.valuedlessons.com/2008/01/monads-in-python-with-n...


You don't need closures for using Monads. It `just' makes them usable in practise.


So, to see if I'm understanding: is the purpose of the Maybe monad to abstract the concept of "evaluate to Nothing if the previous expression evaluated to nothing?" Also, is 'build'/'return' being used implicity somewhere?


  is the purpose of the Maybe monad to abstract the concept of "evaluate to Nothing if the previous expression evaluated to nothing?
Exactly. It's a data type for short-circuiting.

  Also, is 'build'/'return' being used implicity somewhere?
Not in this example -- I thought about it, but ultimately decided additional changes between examples would just confuse things. It's worth including in the definition because it's one of the two fundamental operations.

In real code, it's mostly used when the exact monad being used isn't specified. For example, here's a function which runs a monadic computation until it returns `False'. The result is `()', sort of a Haskell void type.

  runUntil :: Monad m => m Bool -> m ()
  runUntil comp = loop where loop = do
    x <- comp
    if x then loop else return ()
Not useful for `Maybe', but stateful monads like `State', `Get', `Put', or `IO' could all be used on it reasonably.


Wouldn't

  multiclamp5 :: Ord a => a -> a -> a -> Maybe a
  multiclamp5 lim1 lim2 = Kleisli (clamp lim1) >>> Kleisli (clamp lim2)
be even cleaner? The composition looks more obvious to me that way (plus, I like the symmetry).


Sure, but it introduces two new, even scarier names and isn't even as short as

  multiclamp = clamp >=> return clamp
or as general as

  allclamp lims x = foldM (flip clamp) x lims
Haskell is easy to make very, very opaque at the promise of generality, but if you're just making Maybes there's no need to dig that deep.


Err, I don't know what >=> means. Do you have a pointer?


Yeah, I had to introduce one more scary name to do it, but (>=>) is really a good one to learn. It's monadic composition.

  (>=>) :: (Monad m) => (a -> m b) -> (b -> m c) -> (a -> m c)
  (>=>) c1 c2 a = (c1 a) >>= c2
It really helps to clean up some names that normally would be carried all throughout do-less monadic code.


You are right. Though actually foldM is not that opaque once you get used to it.


Oh, no. I like the foldM implementation. I like Kleisli arrows, too, but this application isn't even on the same planet of generality from where Kleisli lives on.


Totally agree. Try ruby isn't great because it's a ruby shell in your browser. It's great because it's a ruby shell in your browser that shows off many features of the language. By the end, though people are definitely still beginners, they have a decent handle on the syntax and many of the basic objects. More than just multiplying numbers and reversing a string.


The text area scrolls to the very top every time I type, not letting me see what I type [Safari 4.0.3]

Pretty cool app. A tutorial to go along with it would do wonders.


Also in Chrome 5.0.322.2 dev


Ah, but can it reverse an infinite list?

    > reverse [1..]

    Time limit exceeded


Pretty nifty. Needs import though, so you can do stuff like:

:m + Data.List intersperse '.' "hello"

And anything else you'd need if you want to use stuff other than just the Prelude.


Many modules are already imported, including Data.List.


Please add help for something beyond "beginners".


Very impressive


Pretty nifty. Needs import though, so you can do stuff like:

:m + Data.List intersperse '.' "hello"

And anything else you'd need if you want to use stuff other than just the Prelude.


Pretty nifty. Needs import though, so you can do stuff like:

:m + Data.List intersperse '.' "hello"

And anything else you'd need if you want to use stuff other than just the Prelude.


Pretty nifty. Needs import though, so you can do stuff like:

:m + Data.List intersperse '.' "hello"

And anything else you'd need if you want to use stuff other than just the Prelude.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: