9 ms·
Learning Haskell – A Racket programmer's foray into the land of Haskell
- codygman 12y agoThis was a great read, I'll be passing it along to anyone wanting to learn Haskell so they can get a good feel for what it's like. You had some advantages though since you've used Racket in the past. I feel like your Racket experience helped you draw conclusions that many wouldn't have otherwise. Great work though, I hope you write about more of your experiences.
- lexi-lambda 12y agoI'm curious what conclusions you'd say those are... and if they're good or bad conclusions? That said, I'm sure I'm totally influenced by various languages I've tried in the past. And FWIW, Racket was also plenty far from my first experience with functional programming. I know so many programming languages that I've gotten pretty used to being able to just "pick them up" in a couple of days (Racket pretty much included). Haskell... not so much.
- Ixiaus 12y agoIt was the same for me. I had two years of production erlang experience before trying Haskell on and it was a rough ride but very worth it (we now use it exclusively in production).
- codygman 12y agoA little tired, but here are a few things that gave you a very big advantage in your Haskell endeavour IMO. - Knowing to start from scratch and assuming it's some install issue with ghc-mod (this probably saved you a lot of time) - already knowing partial application and that you can use backticks to take advantage of it in Haskell - just knowing what pointfree means - knowing about hoogle - knowing how to search hoogle and what type of function you needed - having an interest in the asthetics of your code leading to experimentation that seems pointless but teaches you a lot - having confidence/knowledge of being able to just plugin functions/types. As far as conclusions, I'm mostly commenting on the conclusions you simply made from the types... what people sometimes call "type tetris". Knowing you needed `(a, a) -> Bool`, searching hoogle, then coming to the conclusion of I'll implement it myself and moving on. For a while it seemed like you were going to get caught in "point free hell" and give up on your task... something I've sadly done in the past. Then knowing to ask for help in #haskell and /r/haskell really helped you. I know I haven't really answered your question of "what conclusions you'd say they are"... what I was really trying to say is you made a lot of conceptual leaps I wouldn't expect someone with very little Haskell experience to make. If I remember I'll try to come back to this tomorrow and look for a few examples of those conceptual leaps.
- rasur 12y agoI know what you mean here, especially wrt Haskell, however I've been recently ploughing through the Standard ML videos hosted by Washington University (which also later apparently goes into Racket and Ruby), and found it has aided my understanding greatly. I'd certainly suggest having a look too, if only for the SML stuff, then maybe having another go at Haskell. I'd also poke about at the wiki-book 'Write a scheme in 48 hours' (in Haskell) which I've also found useful (although the pdf version has some errors, so I've been preferring the HTML version http://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours http://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_H... ) Apologies if you've already been through these materials! :) http://courses.cs.washington.edu/courses/cse341/13wi/ http://courses.cs.washington.edu/courses/cse341/13wi/
- ics 12y agoLooking forward to reading this too. For the opposite trajectory (Haskell towards Racket) see this page from a little while back: http://artyom.me/learning-racket-1 http://artyom.me/learning-racket-1
- lexi-lambda 12y agoYep, that was the inspiration for this. :) I actually linked to it in the short intro bit at the beginning.
- losvedir 12y agoAha! I thoroughly enjoyed reading all that, and do hope you continue. It sounds like you're at or slightly ahead of my level of Haskell experience (I knew you'd need Eq before you did! But then the Applicative stuff was beyond me...), so this is very insightful for me as I wonder whether to try picking it up again. "Fine. It's good enough. Moving On." made me laugh! It seems like you thought that could be refactored in a much simpler way. Not knowing (much) Racket, it didn't appear super obvious to me how. Were you alluding to a macro or something? How would you do it in Racket?
- lexi-lambda 12y agoAh, no, I probably wouldn't do it any simpler in Racket. Racket tends to de-emphasize more complicated function composition, which tends to serve it just fine. I've always adopted a somewhat pro-functional approach in my usage of the language, but even here there wouldn't really be a distinctly better way to do it. I guess I was just hoping that Haskell, being a more composition-oriented language in many ways, would have some nice built-in to do that for me.
- evincarofautumn 12y agoIn concatenative programming languages, composition is the default, and it makes point-free code much easier to write. In Factor, for example, you could write your example as: : inexact-matches ( x y -- n ) [ matches ] [ exact-matches ] 2bi - ; That is, run both “matches” and “exact-matches” on both inputs, then take the difference of the results. If Haskell had functions of multiple parameters and results, 2bi’s type would look like this: (a, b, ((a, b) -> c), ((a, b) -> d)) -> (c, d)
- throwaway183839 12y ago> It feels a little redundant to have to manually list out all the elements when the information is known statically, and updating the list will be necessary if the Peg type changes. In Racket, writing a macro for this would be trivial, but alas, this is Haskell. Perhaps there is a way, I’m just not aware of it. A reasonably clean way would be to define data Color = Red | Green | Blue | Yellow | Orange | Purple deriving (Enum, Bounded, Show) and then (e.g. in ghci) you can do >> [minBound .. maxBound] :: [Color] [Red,Green,Blue,Yellow,Orange,Purple] I often define the useful function enumerate :: (Enum a, Bounded a) => [a] enumerate = [minBound .. maxBound] for exactly this purpose.
- lexi-lambda 12y agoYep, I posted this on r/haskell and someone pointed this out, which is cool. The provided type for Peg didn't derive Enum or Bounded, but it's a good trick to know.
- deleted 12y ago[deleted]
- throwaway183839 12y agoI'm kind of surprised that `enumerate` isn't defined in any standard libraries (as far as I know) since I need it pretty often. After a while spent programming in Haskell you would probably develop your own mini-library of functions that make your life easier. Another one I often find useful is (.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d (.:) f g = \x y -> f (g x y) which e.g. allows you to define the absolute distance function dist :: (Num a) => a -> a -> a dist = abs .: (-) A fun challenge is figuring out why the definition of (.:) is equivalent to (.:) = fmap . fmap !
- JadeNB 12y ago> A fun challenge is figuring out why the definition of (.:) is equivalent to > (.:) = fmap . fmap > ! Of course it's not really equivalent, since the most general type of the LHS is as you have said, whereas that of the RHS involves functor constraints; but inlining the definition of `fmap` for arrows gives the amusing definition: (.:) = (.) . (.) I tend to figure this sort of thing out by successive eta conversion: \f g x y -> f (g x y) \f g x y -> (f . g x) y \f g x -> f . g x \f g x -> ((f .) . g) x \f g -> (f .) . g \f g -> ((f .) .) g \f -> ((f .) .) \f -> (.) (f .) \f -> (.) ((.) f) \f -> ((.) . (.)) f (.) . (.) Is there a better way?
- cakoose 12y agoThe author spends a lot of effort trying to make his functions point-free. For example, the author first writes: inexactMatches xs ys = matches xs ys - exactMatches xs ys then decides it's not very "nice", and ends up with this: inexactMatches = pure2 (-) <**> matches <**> exactMatches I can sympathize with this preference. When I first started learning Haskell, figuring out how to make something point-free was extremely satisfying. And it also increases DRY, which is generally a good thing. But over time I realized I was overusing point-free style. It was fun to write, but harder to read. If I were actually writing "inexactMatches" for something real, I would strongly prefer the first over the second. From what I've read, I think many people take a similar path when learning Haskell. That said, I think everyone has a different threshold. For example, I've heard many people say that a for loop is more clear than something like "map" or "fold". I would disagree with that, but maybe that's just because I've gotten used to "map" and "fold". So maybe the author's brain is just able to handle point-free style better than mine can, but I do think this particular example if far enough on the spectrum that most Haskell programmers would prefer the first version (for real code). So if you're considering learning Haskell, don't be scared away. You will have to start getting used to point-free style, but probably not to this extreme.
- lexi-lambda 12y agoYou're going to spend all that work using "the author" everywhere and still manage to get my gender wrong ("his")? Okay. I don't really expect any different in this field, but just noting that. Anyway, I'm well-aware of the temptation of writing point-free code. I did include the sentence "I can see the road to hell is paved with point-free style" myself, after all. I wouldn't prefer point-free style if it ends up looking indiscernible, but in this case I sort of wanted a way to express semi-declaratively "this function is the difference between these other two functions". Does the version I ended up with do that? Yes. But for all I knew there could have been a much better, more idiomatic way. But yes, that was both a quest to improve that code and a mere learning exercise. I'm satisfied with the version I ended up with, though I don't think it's perfect, either.
- Guthur 12y ago
- bojo 12y agoGreat read. I've finally taken the plunge and have spent the last 3 weeks extensively studying Haskell in the evenings. My first attempt was a couple years ago, but somewhere between then and now I've grokked something mysterious and it's been easier to dig into. The last 6 months or so has been something like Common Lisp -> Racket -> Haskell, which may have contributed a little. My long term goal is to write a realtime game server with it, however, I keep flopping back and forth between wrapping my head around the high learning curve and jumping to something more familiar to Get Things Done. It seems the payoff for learning Haskell is intrinsic in and of itself even if I never end up using it, yet I can't help but wonder if I'm spending my time wisely.
- iopq 12y agoYeah, that feel when Cabal has the wrong version of the dependencies...
- nathankleyn 12y agoI really enjoyed reading what you've written so far, and I'm hoping you continue to write more. It was really refreshing to see somebody write about the struggle to pick up Haskell - indeed, I had a lot of the same issues. I often feel the Haskell community is burdened with this stigma of "if you have to ask questions, you're probably too stupid to get it". This is despite the fact that there is actually a really great group of people always willing to help in #haskell. It's primarily an image problem, one a lot of FP languages suffer from. We need more articles talking about the pain points of Haskell so we can get better at making this stuff accessible. We need to be honest with new starters, tell them it's okay to find this stuff challenging and show them where to find help. More than that, though, we need to think about what we can do in the language to fix some of these pain points in a way that the community is happy with.
- kamweti 12y agoFrom a PHP background, I've also been trying out haskell in the evenings, my guide being the learn you a haskell book[1]. So far so good, I've started a little blog[2] to clarify bits that sort of seem confusing to me. [1] http://learnyouahaskell.com http://learnyouahaskell.com [2] http://haskellrecipes.tumblr.com http://haskellrecipes.tumblr.com
- mayisnotacake 12y agoThat was an interesting read for me, because I started off with How to Design Programs + Racket, before switching to Haskell. (I would count Haskell as my first 'proper' language, and prior to all this, I had zero coding experience.) I experienced a lot of the same detours that you have gone through. re: point-free code There's a plug in that you can use, called pointfree (cabal install pointfree). I found that it was more useful to me for experimenting with point-free style than writing my own code in that way.