Something that bugs me is I couldn't copy the code in the upper right to the code "try it" section. I haven't used haskell for 6-12 months, so I'm not sure what I'm doing wrong.
It's a somewhat limited shell. You can't make local definitions. Normally you'd do that using `let` in GHCi, but this prompt only evaluates expressions.
The box for "Try haskell expression here" is a little confusing, I tried to click on the white area to focus and didn't get any response. You apparently have to click on the same line, near the lambda symbol to focus?
Edit: Additionally, I really miss the lovely download page http://www.haskell.org/platform/ - and the non-home pages feel a little underwhelming and underdeveloped in general.
Neat! A nitpick: I haven't used Haskell, so I'm trying to read the prime sieve example in the corner, but there's very little contrast between the background and the nonalphanumeric characters. Some brighter syntax highlighting would be a better choice against that dark background.
Finding primes is something that is taught in the first programming class in Indian high schools. I guess I've never thought of it as something hard.
I looked at nodejs.org, and their first example is a web server! Python has the Fibonacci as it's second example (the first one show's numeric operations).
Ruby does simple string operations on it's home page. While I think that is indeed simpler, it's a little nuanced in Haskell. Depending on how you're doing it you'll need to Map toUpper from Data.Char or use toUpper from Data.Text, and I don't think it's a good first impression have something that uses Data.Text, and the OverloadedStrings extension.
PS - Although, I do agree with some other commentors here that this code isn't actually the Sieve of Eratosthenes, and is far more inefficient, and that is a valid reason to replace that example.
I think a neat algorithm to demonstrate laziness and Haskell clarity would be enumerating the Calkin-Wilf rationals. [0] It's quite a bit longer but demonstrates a number of neat ideas. I'll start first with a derivation which demonstrates all of the structure of the algorithm and then go through a series of mechanical transforms so that by the end I have a one-liner and a comparable Python implementation.
The first algorithm comes directly from the paper and uses an intermediary infinite tree to represent the rationals.
data BTree a = Node a (BTree a) (BTree a)
fold :: (a -> x -> x -> x) -> BTree a -> x
fold f (Node a l r) = f a (fold f l) (fold f r)
unfold :: (x -> (a, x, x)) -> x -> BTree a
unfold f x = let (a, l, r) = f x in Node a (unfold f l) (unfold f r)
breadthFirst :: BTree a -> [a]
breadthFirst = concat . fold glue where
glue a ls rs = [a] : zipWith (++) ls rs
allRationals :: Fractional a => [a]
allRationals = breadthFirst (unfold step (1, 1)) where
step (m, n) = ( m/n, (m, m+n)
, (n+m, n) )
In 16 lines I've got an infinite binary tree, its natural fold and unfold, a breadth first search, and a lazy algorithm for generating all of the rationals with no repeats. The whole thing is simple, natural, beautiful, and efficient! It demonstrates infinite recursive types, laziness, higher-order functions, and bounded polymorphism.
And also a neat algorithm!
The downside is that 16 lines is pretty long.
By inlining the fold and unfold I can get it down to 9 lines:
data BTree a = Node a (BTree a) (BTree a)
breadthFirst :: BTree a -> [a]
breadthFirst = concat . glue where
glue (Node a ls rs) = [a] : zipWith (++) (glue ls) (glue rs)
rats :: Fractional a => [a]
rats = breadthFirst (generate (1, 1)) where
generate (m, n) = Node (m/n) (generate (m, m+n)) (generate (n+m, n))
If I'm allowed imports we can use Data.Tree and make this a one-liner!
Finally, if I go another route and fuse the fold and unfold together into a hylomorphism
data Trip a x = Trip a x x deriving Functor
hylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b
hylo phi psi = phi . fmap (hylo phi psi) . psi
allRationals :: Fractional a => [a]
allRationals = concat (hylo glue step (1, 1)) where
glue (Trip a ls rs) = [a] : zipWith (++) ls rs
step (m, n) = Trip (m/n) (m, m+n) (n+m, n)
we can hide the tree entirely and demonstrate `deriving`... at considerable cost to clarity! With a little more golfing (read: inlining) we arrive at this beauty:
allRationals :: Fractional a => [a]
allRationals = concat (go (1, 1)) where
go = glue . next . step
next (a, b, c) = (a, f b, f c)
glue (a, ls, rs) = [a] : zipWith (++) ls rs
step (m, n) = ( m/n, (m, m+n), (n+m, n) )
which at least has the bonus of demonstrating some nice co-recursion between go and next. Or even, ultimately:
allRationals :: Fractional a => [a]
allRationals = concat (go 1 1) where go m n = [m/n] : zipWith (++) (go m (m+n)) (go (n+m) n)
which is actually kind of nice again if almost all of the structure has vanished.
Note that if `interleave` were part of the Prelude then we could write
allRationals :: Fractional a => [a]
allRationals = go 1 1 where go m n = (m/n) : interleave (go m (m+n)) (go (n+m) n)
It's also utterly incomprehensible for someone who hasn't seen Haskell before. Whereas with the existing example, one can at least piece together an idea of what's going on.
The point is to demonstrate the directness of expression and conciseness of Haskell, not to show how to create an efficient implementation of an involved algorithm.
I agree that the first formulation is a bit incomprehensible, though two-liner breadth-first search is understandable if a bit amazing.
Some of the latter versions (and perhaps ultimately the very last version) are easier to walk through for a beginner, though, and are calculated from properties expressed in the first.
To be honest: This would turn me off even more than the current example which is also hard to read/understand as a non Haskell programmer.
The fibonacci example in another comment in this thread however is very easy to understand and would fit much better.
Well the one-liner form I probably have overseen. It's a lot better than the other variations but I do think that the fibonacci example does show Haskell in a much more understandable way than the allRationals one-liner.
But maybe that's a bit me: I don't particularly like one-liners because as an outsider it takes usually a bit more time to understand it than more lines..
* "Find the Nth Fibonacci Number" is among the most universally known programming tasks, so visitors are far more likely to immediately pick up the example than they are with sieve.
* It shows off a bit of Haskell syntax that (A) can be learned just by looking at an example like this, (B) has a clear benefit to readability that any programmer can appreciate, and (C) is a syntax not found in most mainstream languages.
* The visitor needs no functional programming experience to follow it; it doesn't even use any higher-order functions! This is important, as many visitors will be completely new to FP, and an example that they can't follow is not going to be effective at encouraging them to continue reading.
That's a horrible algorithm though, it takes exponential time. Any good implementation of Fibonacci numbers would be logarithmic in the number of arithmetic operations and polynomial in overall running time (because the numbers get bigger). Here's a good implementation in Haskell: http://nayuki.eigenstate.org/res/fast-fibonacci-algorithms/f... , and the same in Python: http://nayuki.eigenstate.org/res/fast-fibonacci-algorithms/f... . BTW, I think even functional programmers would find the Python code slightly easier to follow :-)
Maybe it's because I've been using Haskell exclusively for a few months, but I find the Haskell example more clear. This surprises me because I have much more experience with Python.
Remember, the target audience is newcomers to Haskell. The purpose of a code sample is to give them a glimpse into the syntax of the language, which should be understandable enough that it piques their interest to learn more.
It would be to the detriment of haskell.org to showcase a superior algorithm that is harder for newcomers to follow.
True, but remember that, say, a Rubyist arriving at haskell.org has no knowledge of:
* what zipWith does
* that (+) is a function being passed, not an operator being invoked
* cons syntax for 1 : 1 : ...
* how this could terminate (having no preexisting knowledge of laziness, remember)
A better goal than "show off all the features of Haskell" is "show a Haskell example that's understandable, demonstrates a clear benefit, and makes you want to learn more."
If a newcomer encounters so much unfamiliar territory that Haskell comes across as too alien to be useful, that only reinforces existing negative stereotypes about it.
Better to give a first impression of "you absolutely can pick up Haskell, and it'll be nice!"
> True, but remember that, say, a Rubyist arriving at haskell.org has no knowledge of:
> * what zipWith does
haskell:
zipWith f xs ys
ruby:
xs.lazy.zip(ys).map(&f)
While Ruby doesn't have a method of the same name, its not exactly foreign.
> * that (+) is a function being passed, not an operator being invoked
Again, sure, Haskell has different syntax than ruby, but the parens signal something special is going on here.
> * cons syntax for 1 : 1 : ...
Sure, but if you know what the Fibonacci sequence is -- and the reason it and primes are almost without exception the two things chosen for these infinite stream examples in every language is because its presumed that programmers do, its pretty easy to get the idea of what is being done from knowing what the function is trying to do and looking at the values presented.
> * how this could terminate (having no preexisting knowledge of laziness, remember)
A Rubyist that has no knowledge of laziness isn't a very knowledgable Rubyist, since laziness is an important and central concept in Ruby's Enumerable module (one of the core modules most frequently used by Rubyists.)
Anything that can be Googled and understood what it is trying to accomplish is less than 2 minutes.
I tried Googling "sieve" and got nothing of use, then "prime sieve" that has a good wikipedia article that is (probably?) about the correct thing but doesn't fit into the "easily understood in a couple of minutes) rule.
So... literally anything. Hello world. First impression shouldn't be that you need to be a math expert to use the language.
FWIW I think the sieve is a great example. Fibonacci is trite and a toy, whereas this is nontrivial and shows off a lot of what's powerful about Haskell (infinite lists, list comprehensions, pattern matching with cons...).
It's complex enough that it encourages people to stare at it for a few minutes and engage with it, which is also good.
Love it! Looks like all that's missing are the "View Examples" links under the features.
One note: the quick walkthrough mentions "up there" in reference to the repl, but the repl is actually to the left of that text when viewing on a non-mobile-sized screen. It should probably just not mention the relative positioning.
I suspect Fibonacci would be a more familiar code sample than Sieve, no?
I like the look. A question: I have always used the "The Haskell Platform" download page and installer. The new download page looks like it is just Haskell, cabal, and default libraries.
I am running ghc version 7.6.3 and cabal version 1.16.0.2.
Haskell experts: should I do a fresh install? (I am on OS X and Ubuntu).
The "Try It" section doesn't load without cookies/localStorage enabled. Having run-time state should be fine for tracking where someone is up to on the tutorial; persistent state shouldn't be necessary.
The "Try It" section really needs to have the text cursor be active anywhere I can click on the box to type. At first it made me think that I had to move over to the grey bracket-cursor (and thus a little frustrating/confusing/unexpected). Especially since I can click to the right (when the cursor is a normal pointer) and it gains focus.
This page is strongly trying to convert a viewer, the experience can be smoothed here.
Please note this homepage is NOT final and it's going to see revisions before we push it out to the actual website, including many tweaks to the content and probably some styling tweaks too.
There are a lot of other things we still need to do as well, like ensure all redirects and subpages work properly.
Source: I'm one of the Haskell.org administrators, and we pushed this out only today.
Is there a practical reason why there's so much empty space with this new design, and why so little valuable content and functionality is visible by default?
Viewing the existing site in a desktop browser, I get to see the description of Haskell, and a bunch of useful links about learning it, downloading an implementation, using it, and participating in the community. Recent news items and upcoming events are also visible, as is the search field.
This new design lacks pretty much all of that. Instead of useful content, links and functionality, all I'm seeing are large areas of purple and white, and an extremely blurry photo, along with content of very limited value.
I just can't see this new design being beneficial in any way. It makes it much harder to get useful information about Haskell, which seems very contradictory to what a website like this should be doing.
The existing design seems to do a good job of using the space available to convey a large amount of important and relevant information, with very little effort required from the viewer.
For example, a viewer of the existing site can quickly get to various types of documentation right away, without having to click on a link to visit a dedicated "Documentation" page, like with the new design. The same goes for news and community details, as well. An inefficient, unnecessary extra link click or press is now needed to get to very core information.
It isn't worth making an informational website look "pretty" if that means ruining its ability to effectively convey information.
Upvoted you. Even I find the new design to be terrible. One more point - the old webpage seems to be "simple" HTML - which loads properly even in very bad internet connections and old browsers like Hacker News. The new design seems to include video links in the homepage, which is always a bad idea, however "modern" you want it to be.
Also, the old homepage immediately gives a sense that Haskell is mature - with separate links about the language, books, libraries, IDEs, etc. The new webpage does not convey anything at all.
Yes - the practical reason is to focus on the newcomer's experience. Information overload is actively harmful to someone coming to haskell.org to learn about the language from scratch.
Omitting content that is primarily valuable to experienced Haskellers is a feature, not a bug.
This sounds like a dangerous trade off to be making. It's reminiscent of what we saw with GNOME 3, or even Windows 8. The experience is made much worse for existing users, in a vain attempt to "simplify" the design to allegedly appeal to new users who may not even really exist in practice. It's obvious now that it didn't work well in those cases, and I don't see why this case would be any different.
As an occasional Haskell user, I'm served much, much better by the existing site than by this new design. The existing one lets me get to the information I'm looking for with minimal effort. This new site denies me that accessibility, I'm afraid to say.
I don't see the point in trying to attract new users if doing so also means harming the experiences of established users. Drawing in new users becomes pointless if retention starts to suffer.
This case is different because it's an introductory page rather than a tool intended for heavy daily use, like GNOME or Windows.
Newbies are going to head to haskell.org when they want to learn about the language, and it's sensible for them to be greeted by a pleasant introduction to the language.
As "an occasional Haskell user," you aren't the target audience for the haskell.org landing page. :) If you're visiting on a regular basis, there's no reason your needs couldn't be met by some page other than the landing page.
"This sounds like a dangerous trade off to be making. It's reminiscent of what we saw with GNOME 3, or even Windows 8."
It's also reminiscent of what we saw with the iPhone, and nobody would say that the experience was much worse for users of previous smartphones. There are times when simplifying and giving structure to existing content just makes sense.
I'm curious, what content do you miss from the old page that can't be found in the Community or Documentation sections in the new design?
I'd like to see the Documentation, Community and News content on the front page, rather than hidden away on those separate pages. The new design adds an extra, unnecessary level of indirection in order to get to this useful information.
Fair enough, but as other posters have noted there's no reason why those contents need to be placed directly at the home page; they could be located at an inner page that you'd bookmark for reference.
The purpose of a good landing page is not to serve as an index for all the content (that's what site maps are for), but to explain the concept and structure of the site to someone that haven't seen it before. The new page is much better in that respect.
I miss a link to the current Haskell wiki in the new design, but I definitely wouldn't expect to find a list of all the wiki pages on the land page, but available under the Documents section.
I don't want to deal with numerous bookmarks to internal pages, or site maps, or any crap like that.
I want to be able to type "haskell.org" into any browser, and from there be able to quickly get to the standard library documentation, to the language spec, to Planet Haskell, to the downloads, and so on, without having to dig through subpages of subpages of subpages, and without having to scroll.
The Rust website at http://www.rust-lang.org/ is a good example of how a programming language home page should be laid out. There are many relevant links at the top. I can almost always find what I want within the first inch or two of the page. Yet it still shows all of the marketing junk for those who want that stuff, but it's placed well below the useful content.
The new Haskell design is the complete opposite of that. It puts a lot of useless junk front and center, and almost totally discards everything that actually is useful.
i don't think you can speak for all gnome 3 users. I'm the happiest i've ever been with gnome 3. I don't have a bunch of options and other knobs to twiddle. It just works and stays out of the way.
The real reason is that one of the standard bootstrap layout examples was used. The 'bootstrapped' web today is extraordinarily boring. It is the same big banner followed by striped two column grid again and again and again.
Would you need some help in curating a better set of videos?
I think that having some topics this advanced on the home page might scare of users, especially given their visual priority on the page.
Also, what's the plan on the view examples links on the page? Currently these don't link anywhere. Are you looking for existing articles that exist online to link to, or are you looking to have some content written that can be hosted on haskell.org.
I liked that the videos showed a glimpse into the active community around Haskell -- they are not just a fixed set of tutorials for newcomers, but show the variety of talks that Haskell programmers around the world give (including some deeper topics).
I'd hope there's some way to keep that perpetually current -- for it to include recent talks, kept up to date.
I love the tutorial! I couldn't help writing down some notes while going through it, here they are if you're interested in reading:
- Really would love to return to previous steps to review things (for example, reviewing what the difference is between a list and a tuple)
- "You just passed the (+1) function to the map function." But didn't I also pass [1..5] to it too? It's unclear to me whether map is a function which takes two arguments ... or if the first part "map (+1)" evaluates to a function which acts on [1..5]
- Is a (+1) a tuple with one item (the function "+1") or is it just similar syntax?
- Really like the exercises and would love to have more challenges interspersing the intake of new content. It honestly feels like the best way to learn.
I'm going to sleep for the night, otherwise I'd keep going. I'll return to it later. Looks promising!
P.S. Mini-bug report: Somehow this happened and it really confused me https://i.cloudup.com/0wRJS7FZls.png - looks like my 'try it again anyways' strategy saved me here. (there were no js console errors).
Not sure if you would like to know some answers to your questions, here are they anyway:
- It's unclear to me whether map is a function which takes two arguments ... or if the first part "map (+1)" evaluates to a function which acts on [1..5]
The latter is true. In Haskell you can pass arguments to functions one at a time each time the result could be a function that takes another argument. You might even say that Haskell functions always take one argument, and that Haskell's function syntax is just a bit of sugaring. The process of returning a function that takes the second argument is called a 'curry' after the man Haskell Curry.
- Is a (+1) a tuple with one item (the function "+1") or is it just similar syntax?
A tuple of 1 is just an expression. The ('s are just to determine expression scope, it's the commas that would make it a tuple. A tuple of 2 would just be 2 expressions bundled together, so I don't think there's a meaningful difference :P
Nah, Haskell has no functions with zero arguments.
You could say that a value is a function that takes no arguments, but then you lose the distinction between functions and other values, and more importantly, the distinction between function types and other types! For example, types like Bool have decidable equality, but function types in general have undecidable equality, so you really don't want to be caught saying that Bool is a function type. It's much more sensible to say a type is a function type iff it was constructed by the type constructor ->, which takes two types, the argument type and the return type. In other words, all functions take one argument and return one result.
You could also say that a value is an unevaluated thunk that takes no arguments, but that's not always true. The thunk may be already evaluated and replaced with a value, without affecting the visible type. It's better to keep the idea of "thunk" separate from the idea of "function", because a value could be both, either, or none.
You could also say that every value x can be converted to and from a function () -> x. But that's not a function with no arguments, that's a function with one argument of type "unit" (the type with a single member, a.k.a. the empty tuple).
The above might sound pedantic, but for some reason it's fascinating to me to think about such things. Language design is a kind of addiction and Haskell is like a drug, because its original purpose was to be a laboratory for programming language research, which you can see in the million GHC extensions.
In Haskell, all functions take one argument. Also, operators are functions.
First, the one argument thing is known as currying. With higher-order functions, returning a function is admissible, so
map :: (a -> b) -> [a] -> [b]
can also be thought of as:
map :: (a -> b) -> ([a] -> [b])
like so:
ghci> :t map length
map length :: [[a]] -> [Int]
As for operators being functions, function names that are alphanumeric default to prefix (e.g. f 10) while those that are symbolic default to infix (e.g. 10 + 18). To use an alphanumeric name in infix, use backticks, e.g.:
ghci> 5 `max` 6
6
Use parentheses to prefix an "operator"-style name, like so:
ghci> (+) 5 6
11
The (+1) that you're meeting is an additional bit of syntactic sugar. It's identical to (\x -> x + 1). It allows you to do things like this:
I'm a bit late, but perhaps you'll see this. Can you catch Ctrl+W in the REPL and use it to delete the prior word, instead of closing the tab? Kind of jarring to get into the groove of using a REPL and then accidentally close the tab.
λ primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
<hint>:1:8: parse error on input `='
Doesn't work.
Now, I know enough about Haskell to know what I can and can't type into ghci, but what about people who are encountering Haskell for the first time? They'll try to run the given example in the "Try It" section and will get nothing but errors. Just my two cents.
P.S. Is Haskell still avoiding success at all costs? (A philosophy I continue to be okay with, but it seems to getting futile :) )
Haskell is still avoiding (success at all costs), the bracketing is very important. Haskell may seem like a slow to develop language and community at times, but this is because most users want to see well thought out solutions to problems, and if they have theoretical backgrounds showing that what they're doing is a good idea, even better.
I dislike this. Where is the 'call for me to do something'?
Why are there blurred people on an escalator(?). Don't make me pick between concise and reliable.
I'm more than willing to distill your messaging if it would help in any way. If only as an alternative.
I like the new site. It's beautiful and elegant. The weird flowers on the download page are gone. But the link to "Introduction to Functional Programming Using Haskell" takes me to the publisher page for the textbook "Aqueous Environmental Geochemistry".
It bugs me a bit that the example code is brute force trial division instead of a true prime sieve. Sure, it highlights lazyness but the algorithm is less efficient.
that's just nonsense. there are many people very concerned about performance.
i guess you are right that some do not care about constant factors, but i am very sure most do care about algorithmic complexity. and thinking about it, that's the approach you should use for anything where every last bit of performance is not utterly needed.
Well it's the haskell.org landing page, of course they're showing off the type of code that Haskell is good at. In your link, the purely functional version (15 lines around a priority queue) is more complicated than a naive version with a mutable array, so why would they advertise it?
I personally think the priority queue one is somewhat simpler than a fixed array algorithm. It also produces an infinite list of primes (or generator) instead of the primes up to a particular number. This is especially important in Haskell.
I'd love to see it as it shows off some great data structures available in the libraries (like priority queues) but it's getting longish.
The mutable array version is basically the same as imperative code everywhere
sieveUA :: Int -> UArray Int Bool
sieveUA top = runSTUArray $ do
let m = (top-1) `div` 2
r = floor . sqrt $ fromIntegral top + 1
sieve <- newArray (1,m) True
forM_ [1..r `div` 2] $ \i -> do
isPrime <- readArray sieve i
when isPrime $ do
forM_ [2*i*(i+1), 2*i*(i+2)+1..m] $ \j -> do
writeArray sieve j False
return sieve
It's a bit noisy syntactically and doesn't show off as much interesting stuff.
I feel like the sieve is a poor example, since it's not actually the same algorithm as a sieve, and has a worse running time. It is possible to write a very nice lazy infinite sieve.
See O’Neill's "The Genuine Sieve of Eratosthenes" paper for details.
That example does match some high level definitions of quicksort; "pick a pivot element (the first element of the list), split the rest of the list into elements less than and greater than or equal to the pivot, quicksort those recursively, then reassemble the lesser, pivot and then greater elements". But I do agree it's not quicksort as it's usually known with its in place sorting and O(1) extra storage.
Excellent! This is a big improvement. There seem to be some bugs with the "try it now" terminal, but it was easy enough that I actually gave Haskell a try after many years. It's got me interested enough to actually install it and start hacking away!
Great timing, as I've just started to explore Haskell in the last few days.
First, I really like the style of the new site. My only gripe is that the section with the lecture hall photo and the videos right below it don't seem like an efficient use of prime real estate (and there is no context for the videos, I have no idea what they are or why I would want to watch it. The thumbnails suggest that I'd be clicking on an hour long lecture.). As a new user, I'd rather see the features in this space.
257 comments
[ 3.0 ms ] story [ 350 ms ] threadI understand the Haskell wikibook is also great at the introductory level.
Anyone know if there are plans to add the interactive/javascript examples as well?
EDIT: Had noscript on, everything looks great.
Something that bugs me is I couldn't copy the code in the upper right to the code "try it" section. I haven't used haskell for 6-12 months, so I'm not sure what I'm doing wrong.
Here's a screenshot: http://imgur.com/N2SdFVq
Regardless of how to fix this, I think something should be changed so this can't be someone's first impression.
`let { f x = x ^ 2 } in f 2`
Edit: Additionally, I really miss the lovely download page http://www.haskell.org/platform/ - and the non-home pages feel a little underwhelming and underdeveloped in general.
Just a little nitpick:
though the first expression is what suggested in lesson 4.Edit: looks like some random bug.
λ foldr (:) [] [1,2,3]
:: Num a => [a]
λ foldr (:) [] [1,2,3]
[1,2,3] :: Num a => [a]
Finding primes is something that is taught in the first programming class in Indian high schools. I guess I've never thought of it as something hard.
I looked at nodejs.org, and their first example is a web server! Python has the Fibonacci as it's second example (the first one show's numeric operations).
Ruby does simple string operations on it's home page. While I think that is indeed simpler, it's a little nuanced in Haskell. Depending on how you're doing it you'll need to Map toUpper from Data.Char or use toUpper from Data.Text, and I don't think it's a good first impression have something that uses Data.Text, and the OverloadedStrings extension.
PS - Although, I do agree with some other commentors here that this code isn't actually the Sieve of Eratosthenes, and is far more inefficient, and that is a valid reason to replace that example.
I think a neat algorithm to demonstrate laziness and Haskell clarity would be enumerating the Calkin-Wilf rationals. [0] It's quite a bit longer but demonstrates a number of neat ideas. I'll start first with a derivation which demonstrates all of the structure of the algorithm and then go through a series of mechanical transforms so that by the end I have a one-liner and a comparable Python implementation.
The first algorithm comes directly from the paper and uses an intermediary infinite tree to represent the rationals.
In 16 lines I've got an infinite binary tree, its natural fold and unfold, a breadth first search, and a lazy algorithm for generating all of the rationals with no repeats. The whole thing is simple, natural, beautiful, and efficient! It demonstrates infinite recursive types, laziness, higher-order functions, and bounded polymorphism.And also a neat algorithm!
The downside is that 16 lines is pretty long.
By inlining the fold and unfold I can get it down to 9 lines:
If I'm allowed imports we can use Data.Tree and make this a one-liner! Finally, if I go another route and fuse the fold and unfold together into a hylomorphism we can hide the tree entirely and demonstrate `deriving`... at considerable cost to clarity! With a little more golfing (read: inlining) we arrive at this beauty: which at least has the bonus of demonstrating some nice co-recursion between go and next. Or even, ultimately: which is actually kind of nice again if almost all of the structure has vanished.Note that if `interleave` were part of the Prelude then we could write
givenThe point is to demonstrate the directness of expression and conciseness of Haskell, not to show how to create an efficient implementation of an involved algorithm.
Some of the latter versions (and perhaps ultimately the very last version) are easier to walk through for a beginner, though, and are calculated from properties expressed in the first.
This comment was really bad at exposition, but I think it got somewhere nice.
But maybe that's a bit me: I don't particularly like one-liners because as an outsider it takes usually a bit more time to understand it than more lines..
I wrote a post elaborating the ideas here: http://tel.github.io/2014/07/09/calkin_wilf_for_early-ish_ha...
* "Find the Nth Fibonacci Number" is among the most universally known programming tasks, so visitors are far more likely to immediately pick up the example than they are with sieve.
* It shows off a bit of Haskell syntax that (A) can be learned just by looking at an example like this, (B) has a clear benefit to readability that any programmer can appreciate, and (C) is a syntax not found in most mainstream languages.
* The visitor needs no functional programming experience to follow it; it doesn't even use any higher-order functions! This is important, as many visitors will be completely new to FP, and an example that they can't follow is not going to be effective at encouraging them to continue reading.
Also, I think the example should not be a partial function ;).
It would be to the detriment of haskell.org to showcase a superior algorithm that is harder for newcomers to follow.
* what zipWith does
* that (+) is a function being passed, not an operator being invoked
* cons syntax for 1 : 1 : ...
* how this could terminate (having no preexisting knowledge of laziness, remember)
A better goal than "show off all the features of Haskell" is "show a Haskell example that's understandable, demonstrates a clear benefit, and makes you want to learn more."
If a newcomer encounters so much unfamiliar territory that Haskell comes across as too alien to be useful, that only reinforces existing negative stereotypes about it.
Better to give a first impression of "you absolutely can pick up Haskell, and it'll be nice!"
> * what zipWith does
haskell:
ruby: While Ruby doesn't have a method of the same name, its not exactly foreign.> * that (+) is a function being passed, not an operator being invoked
Again, sure, Haskell has different syntax than ruby, but the parens signal something special is going on here.
> * cons syntax for 1 : 1 : ...
Sure, but if you know what the Fibonacci sequence is -- and the reason it and primes are almost without exception the two things chosen for these infinite stream examples in every language is because its presumed that programmers do, its pretty easy to get the idea of what is being done from knowing what the function is trying to do and looking at the values presented.
> * how this could terminate (having no preexisting knowledge of laziness, remember)
A Rubyist that has no knowledge of laziness isn't a very knowledgable Rubyist, since laziness is an important and central concept in Ruby's Enumerable module (one of the core modules most frequently used by Rubyists.)
Anything that can be Googled and understood what it is trying to accomplish is less than 2 minutes.
I tried Googling "sieve" and got nothing of use, then "prime sieve" that has a good wikipedia article that is (probably?) about the correct thing but doesn't fit into the "easily understood in a couple of minutes) rule.
So... literally anything. Hello world. First impression shouldn't be that you need to be a math expert to use the language.
It's complex enough that it encourages people to stare at it for a few minutes and engage with it, which is also good.
I vote to keep it!
One note: the quick walkthrough mentions "up there" in reference to the repl, but the repl is actually to the left of that text when viewing on a non-mobile-sized screen. It should probably just not mention the relative positioning.
I suspect Fibonacci would be a more familiar code sample than Sieve, no?
I am running ghc version 7.6.3 and cabal version 1.16.0.2.
Haskell experts: should I do a fresh install? (I am on OS X and Ubuntu).
Also, shameless plug: I blogged earlier today about using Haskell to access OpenCalais and the DBPedia SPARQL endpoint: http://blog.markwatson.com/2014/07/some-haskell-hacks-sparql...
This page is strongly trying to convert a viewer, the experience can be smoothed here.
> You shouldn't have rewrite half your code base when it's time to scale.
There are a lot of other things we still need to do as well, like ensure all redirects and subpages work properly.
Source: I'm one of the Haskell.org administrators, and we pushed this out only today.
Viewing the existing site in a desktop browser, I get to see the description of Haskell, and a bunch of useful links about learning it, downloading an implementation, using it, and participating in the community. Recent news items and upcoming events are also visible, as is the search field.
This new design lacks pretty much all of that. Instead of useful content, links and functionality, all I'm seeing are large areas of purple and white, and an extremely blurry photo, along with content of very limited value.
I just can't see this new design being beneficial in any way. It makes it much harder to get useful information about Haskell, which seems very contradictory to what a website like this should be doing.
The existing design seems to do a good job of using the space available to convey a large amount of important and relevant information, with very little effort required from the viewer.
For example, a viewer of the existing site can quickly get to various types of documentation right away, without having to click on a link to visit a dedicated "Documentation" page, like with the new design. The same goes for news and community details, as well. An inefficient, unnecessary extra link click or press is now needed to get to very core information.
It isn't worth making an informational website look "pretty" if that means ruining its ability to effectively convey information.
Also, the old homepage immediately gives a sense that Haskell is mature - with separate links about the language, books, libraries, IDEs, etc. The new webpage does not convey anything at all.
Omitting content that is primarily valuable to experienced Haskellers is a feature, not a bug.
As an occasional Haskell user, I'm served much, much better by the existing site than by this new design. The existing one lets me get to the information I'm looking for with minimal effort. This new site denies me that accessibility, I'm afraid to say.
I don't see the point in trying to attract new users if doing so also means harming the experiences of established users. Drawing in new users becomes pointless if retention starts to suffer.
Newbies are going to head to haskell.org when they want to learn about the language, and it's sensible for them to be greeted by a pleasant introduction to the language.
As "an occasional Haskell user," you aren't the target audience for the haskell.org landing page. :) If you're visiting on a regular basis, there's no reason your needs couldn't be met by some page other than the landing page.
It's also reminiscent of what we saw with the iPhone, and nobody would say that the experience was much worse for users of previous smartphones. There are times when simplifying and giving structure to existing content just makes sense.
I'm curious, what content do you miss from the old page that can't be found in the Community or Documentation sections in the new design?
The purpose of a good landing page is not to serve as an index for all the content (that's what site maps are for), but to explain the concept and structure of the site to someone that haven't seen it before. The new page is much better in that respect.
I miss a link to the current Haskell wiki in the new design, but I definitely wouldn't expect to find a list of all the wiki pages on the land page, but available under the Documents section.
I want to be able to type "haskell.org" into any browser, and from there be able to quickly get to the standard library documentation, to the language spec, to Planet Haskell, to the downloads, and so on, without having to dig through subpages of subpages of subpages, and without having to scroll.
The Rust website at http://www.rust-lang.org/ is a good example of how a programming language home page should be laid out. There are many relevant links at the top. I can almost always find what I want within the first inch or two of the page. Yet it still shows all of the marketing junk for those who want that stuff, but it's placed well below the useful content.
The new Haskell design is the complete opposite of that. It puts a lot of useless junk front and center, and almost totally discards everything that actually is useful.
Would you need some help in curating a better set of videos? I think that having some topics this advanced on the home page might scare of users, especially given their visual priority on the page.
Also, what's the plan on the view examples links on the page? Currently these don't link anywhere. Are you looking for existing articles that exist online to link to, or are you looking to have some content written that can be hosted on haskell.org.
I'd hope there's some way to keep that perpetually current -- for it to include recent talks, kept up to date.
<p><a>View examples</a></p>
- Really would love to return to previous steps to review things (for example, reviewing what the difference is between a list and a tuple)
- "You just passed the (+1) function to the map function." But didn't I also pass [1..5] to it too? It's unclear to me whether map is a function which takes two arguments ... or if the first part "map (+1)" evaluates to a function which acts on [1..5]
- Is a (+1) a tuple with one item (the function "+1") or is it just similar syntax?
- Really like the exercises and would love to have more challenges interspersing the intake of new content. It honestly feels like the best way to learn.
I'm going to sleep for the night, otherwise I'd keep going. I'll return to it later. Looks promising!
P.S. Mini-bug report: Somehow this happened and it really confused me https://i.cloudup.com/0wRJS7FZls.png - looks like my 'try it again anyways' strategy saved me here. (there were no js console errors).
- It's unclear to me whether map is a function which takes two arguments ... or if the first part "map (+1)" evaluates to a function which acts on [1..5]
The latter is true. In Haskell you can pass arguments to functions one at a time each time the result could be a function that takes another argument. You might even say that Haskell functions always take one argument, and that Haskell's function syntax is just a bit of sugaring. The process of returning a function that takes the second argument is called a 'curry' after the man Haskell Curry.
- Is a (+1) a tuple with one item (the function "+1") or is it just similar syntax?
A tuple of 1 is just an expression. The ('s are just to determine expression scope, it's the commas that would make it a tuple. A tuple of 2 would just be 2 expressions bundled together, so I don't think there's a meaningful difference :P
This is exactly true. Every Haskell function takes either zero arguments, or one.
You could say that a value is a function that takes no arguments, but then you lose the distinction between functions and other values, and more importantly, the distinction between function types and other types! For example, types like Bool have decidable equality, but function types in general have undecidable equality, so you really don't want to be caught saying that Bool is a function type. It's much more sensible to say a type is a function type iff it was constructed by the type constructor ->, which takes two types, the argument type and the return type. In other words, all functions take one argument and return one result.
You could also say that a value is an unevaluated thunk that takes no arguments, but that's not always true. The thunk may be already evaluated and replaced with a value, without affecting the visible type. It's better to keep the idea of "thunk" separate from the idea of "function", because a value could be both, either, or none.
You could also say that every value x can be converted to and from a function () -> x. But that's not a function with no arguments, that's a function with one argument of type "unit" (the type with a single member, a.k.a. the empty tuple).
The above might sound pedantic, but for some reason it's fascinating to me to think about such things. Language design is a kind of addiction and Haskell is like a drug, because its original purpose was to be a laboratory for programming language research, which you can see in the million GHC extensions.
First, the one argument thing is known as currying. With higher-order functions, returning a function is admissible, so
can also be thought of as: like so: As for operators being functions, function names that are alphanumeric default to prefix (e.g. f 10) while those that are symbolic default to infix (e.g. 10 + 18). To use an alphanumeric name in infix, use backticks, e.g.: Use parentheses to prefix an "operator"-style name, like so: The (+1) that you're meeting is an additional bit of syntactic sugar. It's identical to (\x -> x + 1). It allows you to do things like this:Additionally, all examples could be loaded into the "Try It" section, so I could type `take 4 primes` or something.
Instead, in my attempt to load the primes function.. I was met with this bit.
For this example:
I tried to type it into the shell: It doesn't work. Okay, what if I copy and paste? Doesn't work.Now, I know enough about Haskell to know what I can and can't type into ghci, but what about people who are encountering Haskell for the first time? They'll try to run the given example in the "Try It" section and will get nothing but errors. Just my two cents.
P.S. Is Haskell still avoiding success at all costs? (A philosophy I continue to be okay with, but it seems to getting futile :) )
You missed the tongue-in-cheek, there. "Concise and Reliable: Pick Two."
And those people are in a lecture hall. Under "Open-source community effort."
http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf
i guess you are right that some do not care about constant factors, but i am very sure most do care about algorithmic complexity. and thinking about it, that's the approach you should use for anything where every last bit of performance is not utterly needed.
I'd love to see it as it shows off some great data structures available in the libraries (like priority queues) but it's getting longish.
The mutable array version is basically the same as imperative code everywhere
It's a bit noisy syntactically and doesn't show off as much interesting stuff.See O’Neill's "The Genuine Sieve of Eratosthenes" paper for details.
http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf
First, I really like the style of the new site. My only gripe is that the section with the lecture hall photo and the videos right below it don't seem like an efficient use of prime real estate (and there is no context for the videos, I have no idea what they are or why I would want to watch it. The thumbnails suggest that I'd be clicking on an hour long lecture.). As a new user, I'd rather see the features in this space.