8 ms·
Why I prefer scheme to Haskell
- irahul 15y agoIf you use windows or mono is an option, F# is an alternative to Haskell. F# comprises on purity for practicality, and adds a couple of niceties of its own over the ML core. It also allows convenient OOP, but in now way forces to use it if your whole code base is F#. And if you are using Scheme, Racket is a scheme derivative which provides a nice and extensive library.
- getsat 15y agoDoes F# let you debug using printf? I stopped reading the linked post at that point.
- p4bl0 15y agoOCaml, on which if I understand it correctly, F# is based, allows you to do that easily, but it's not really natural to do so in this programming languages.
- deleted 15y ago[deleted]
- darklajid 15y agoYes, you could do that. Won't judge that approach - that's probably a cultural thing. But you have access to side effects and could dump stuff to the console (even, if you're so inclined, using the .Net framework standard way, calling Console.Write/WriteLine - although the print* stuff in F# is really better suited if you decided to go down that path).
- more_original 15y agoYes, printf is easy in F#. The following example works in F# and OCaml: let rec fact n = Printf.printf "%i\n" n; if n = 0 then 1 else n * (fact (n-1))
- getsat 15y agoFor the record, this was sarcasm. It's 2012. I really hope you guys aren't debugging using printf still. You'd think someone into esoteric languages would've heard of a debugger.
- jrockway 15y agoI'm pretty good at Haskell and prefer print to debuggers in pretty much every language. I'd rather have the computer produce output for me to read than to have to hand-hold the computer through evaluating my program. It's easier.
- gruseom 15y agoThe one doesn't replace the other. I wrote a JS debugger for Emacs so as to have a debugger when I wanted one. I still use print statements more.
- reddit_clone 15y agoPrint/Trace statements are invaluable in several situations. I don't trust debuggers for multi-threaded applications or applications with open, time-sensitive resources (open sockets etc..) Installing and firing up a debugger is not an option in a customer's system. > It's 2012 I expect to be using Printf's in 2022 and beyond.
- meric 15y agoFor debugging Haskell, use trace to print things inside pure functions. http://stackoverflow.com/questions/3546592/how-to-debug-haskell-with-printfs http://stackoverflow.com/questions/3546592/how-to-debug-hask...
- cageface 15y agoThe success of Parsec and its ilk has filled Hackage (the Haskell module repository) with hundreds of DSLs covering any task you care to mention. This is exactly why I've grown wary of DSLs. They have their place, but in a really expressive language like Ruby or Haskell I'd often just prefer to code in the native tongue.
- gruseom 15y agoDSLs have a significant up-front cost. If all goes well, the cost gets amortized over many usages and you come out ahead. But it takes a while. One-offs are not worth it. This is probably true of abstractions in general and not just DSLs. Another thing about DSLs is that you have to nail both the D and the L in order to get it right, so they are hard to make. Language design is not at all like program design.
- tptacek 15y agoDo you believe this about bottom-up programming in general, or is your concern specific to parsed DSLs?
- gruseom 15y agoHmm, good question. I'd say it's less true of bottom-up programming because there you're generalizing code you've already written. It's possible to get that wrong, i.e. introduce abstractions that capture what was there before but don't make it easier to write the program going forward, in which case the best thing to do is rip them out and replace them with their compiled equivalents until a better idea emerges. But it's all very incremental and the cost of getting any individual construct wrong is relatively low. Classical DSLs are harder because of the D. You have to nail the domain/language fit or it's more trouble than it's worth. Even then you don't necessarily win enough to justify the cost: a specialized language needs to be significantly better than "just coding your domain model in your general-purpose language", which is a high bar. There isn't only the cognitive cost of learning a specialized language, there's the interoperability hit (can a general program call the DSL and vice versa), lack of tool support and so on. It doesn't make sense for most domains, especially business domains that don't lend themselves to technical notation. The thing that bottom-up programming has taught me, not that I'm in any way sophisticated at it, is that good language constructs need to be an order of magnitude more lightweight than good application constructs. Application constructs are what you pack in your car for a road trip, language constructs are what you put in your backpack for a hike. Or another metaphor: application constructs are factory equipment, language constructs are hand tools - if you have to think about how to use it, it sucks. I find it's hard mentally to go back and forth between these two design levels. I'm spending a few days at the language level right now so these things are on my mind.
- yummyfajitas 15y agoIf you wish to debug a function in Haskell you can't insert a printf to inspect its inner workings unless that function happens to be on the IO monad. Sure you can. f x = let intermediate = 2*x intermediate2 = unsafePerformIO $ do putStrLn ("intermediate value is " ++ (show intermediate)) return intermediate in (intermediate2 * intermediate2) Output: intermediate value is 6 Result is 36 It's a little uglier, since you need to make sure intermediate2 is actually evaluated. The better way to go would be: f x = let intermediate = intermediateComputation x in (intermediate*intermediate) intermediateComputation x = 2*x And then you just don't expose intermediateComputation to stuff outside the module. This has the advantage that you can use quickCheck on intermediateComputation. If the value isn't what you think it is, quickCheck will tell you what it actually is.
- mcguire 15y agoYour unsafePerformIO version is essentially what Debug.Trace does.
- danieldk 15y agoAs elegant and appealing as Haskell's purely functional foundation is, it prohibits simple, but crucial, impure tasks such as writing to files and communicating over networks. [...] but they make it neither intuitive nor easy. Actually, such tasks have become much simpler thanks to the recent surge of packages such as conduit. These make typical I/O work easy, and very much resemble a UNIX pipe. You have a pure or impure source that produces data (e.g. reading a file), conduits that manipulate data, and sinks that consume data (e.g. writing data to a file, or storing it in a list). In fact, I have started to like conduit so much, that I/O in other languages feels quite kludgy. If you wish to debug a function in Haskell you can't insert a printf to inspect its inner workings unless that function happens to be on the IO monad. Actually, you can, using Debug.Trace.trace, which takes a String and an expression. The string is first printed, then the expression is evaluated. No need to be in the IO monad: http://www.haskell.org/haskellwiki/Debugging#Printf_and_friends http://www.haskell.org/haskellwiki/Debugging#Printf_and_frie... After a frustrutating hour with my Haskell version I was still struggling to understand the monadic API required to work with the XML parser and I gave up. I had to parse some XML data and used hexpat-pickle. Once you get the hang of it, it is pretty simple. But I agree that there is a learning curve involved. With such tasks, it usually takes longer to come up with an initial Haskell solution. But then that solution is usually very clean and elegant. If you have to write something quickly, it is not ideal, but often the things that we wrote quickly end up being used for years anyhow ;). By the way, my experience is exactly the opposite. I wrote some code in Clojure (which I do like very much, since it manages to leverage the Java platform while staying very clean). But I noticed that my productivity dropped - lots of things that Haskell detected through static type checking I had to verify myself by hand and write tests for.
- EvilTerran 15y agoit usually takes longer to come up with an initial Haskell solution. But then that solution is usually very clean and elegant The big thing that jumps out at me like that in my experience is: it takes longer to come up with an initial Haskell solution that compiles, but when it compiles, it almost always works first-time; while, in a less rigorous language, I can get it compiling a bit sooner, but any time saved there is lost many-fold when it doesn't actually work.
- dons 15y agoOP wasn't aware of Debug.Trace: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Debug-Trace.html http://www.haskell.org/ghc/docs/latest/html/libraries/base/D... Otherwise, this seems pretty light on technical details -- and big on hyperbole -- "Scheme shares Haskell's unsuitability for production code" -- I'm very wary of people who make claims like that, despite all the evidence to the contrary...
- maxcan 15y agohow do the hundreds of KLoC of Haskell in production at a certain bank headquartered in Singapore feel about Haskell being unsuitable for production?
- batista 15y agoLanguages and frameworks unsuitable from production have been used in production thousands of times. It doesn't prove anything.
- gtani 15y agoread this, in Hungarian http://gergo.erdi.hu/blog/2011-05-16-i%27m_leaving_on_a_jet_plane.../ http://gergo.erdi.hu/blog/2011-05-16-i%27m_leaving_on_a_jet_... google translate: rapid help deszantosokként trapped in the trade analysts,
- gtani 15y agohttp://code.haskell.org/~dons/talks/padl-keynote-2012-01-24.pdf http://code.haskell.org/~dons/talks/padl-keynote-2012-01-24....
- SkyMarshal 15y ago> Scheme shares Haskell's unsuitability for production code It's rather unfortunate something like that gets voted to the front page, though I tend to learn something from the comments to these kinds of submissions (scripting in Haskell! your slides). Cognitive dissonance.
- lucian1900 15y agoI used to have the same opinion about print debugging, but after a few months exclusively using pdb, I can say I'm a debugger convert. If Haskell's debugger is good, that point is moot. The other points still stand, of course.
- MaxGabriel 15y agoA little typo, I think you mean Backus-Naur form?
- tmhedberg 15y agoIn addition to the Debug.Trace facility that others have mentioned, it's also worth noting that GHCi has a built in debugger. I find that I need it pretty infrequently, since you can inspect anything defined at the top level simply by loading your module in GHCi and evaluating the expression in question. But if you need to inspect more local bindings, such as functions defined in a `where` clause in the body of a function, the debugger works really well. The only funny thing about it is that, since Haskell's syntax isn't organized in the "one statement per line" manner like most imperative languages, you often have to specify breakpoints not just by the line where execution should pause but by the column as well. For this, I recommend using an editor that can easily display the column number that the cursor is in. Most of the author's other comments I can understand, even if I don't share his opinions. There is certainly a cognitive barrier to entry inherent in a lot of the language's concepts. All I can say about this is that as I've used the language more and more, these barriers seem to have melted away to the point where, simply by browsing the types of names exported by a library module, I can pretty much intuit how it works. A lot of libraries are very well-documented, and some are definitely not, but even in the latter case, the type signatures alone can go a long way to helping me understand. I'd probably be a Scheme addict myself if Haskell hadn't convinced me of the indispensable power of strong static types. I love how elegantly simple Scheme is, and how you can construct so much from such humble beginnings. It feels like it distills functional programming down to its very essence. SICP is a beautiful thing as well. But Haskell naturally guides me to writing better, more robust, more correct code in ways that dynamic languages simply aren't capable of, and I just find myself getting frustrated when using other languages because I always end up wasting time fixing bugs that I know GHC would have caught for me up front. Someone in the Haskell community (I can't recall who it was) has said: "I think of types as warping our gravity, so that the direction we need to travel to write correct programs becomes 'downhill'." I couldn't agree more. Edit: I also have to state my disagreement about monads being a "wobbly crutch". While it is true that they are more or less necessary in order to introduce practical impurity into Haskell, being necessary doesn't make them a shim or a hack. Not only are they an elegant solution to many problems, but they are really quite simple to use. If people spent as much time actually writing monadic code as they do reading the zillions of silly, confusing monad tutorials, they'd quickly reach the point where they no longer see what the big fuss is about. There is nothing truly scary here; the worst part about monads is the name.
- ozataman 15y ago> This has always been my problem with Haskell; it is beautiful, but it is useless for hacking. Don't confuse a lack of experience and skill with an advanced tool's (Haskell in this case) lack of practical value. It's one thing to say "Haskell takes a long time to become useful for the average person" and another to say "Haskell is useless for hacking (as in quick prototyping as I understand from your article)". I, for one, can produce quick mock-ups and prototypes way faster in Haskell than in any other language I know; and I consider myself an advanced user of Ruby and Python. You need to, of course, absorb and internalize a large number of use cases and concepts in Haskell before you get to this point, but it is quite extraordinary once you're there. High expressiveness, modeling to fit the domain even for small, one-off tasks (thanks to algebraic data types) and many other elegant aspects all become second nature and really really fast once you're expert enough. dons' slides come to mind as a presentation on a related topic if anyone's interested[1]. [1]: http://donsbot.files.wordpress.com/2009/01/semicolon.pdf http://donsbot.files.wordpress.com/2009/01/semicolon.pdf
- TylerE 15y agoBut that is I think OP's point, Haskell forces you to "model", versus something like scheme or python where you can just sling dicts around. Haskell absolutely forces you to do a non-trivial amount of thinking up front, which is counter-productive when you're trying to throw something together in 10 minutes.
- DanWaterworth 15y agoYou can sling dicts around in Haskell too if you want to. The reason people don't is that the alternative is easier.
- jhuni 15y agoI would pose a harsher criticism against Haskell then the one posed in this article. I believe that logical relations are a better foundation for declarative programming then functions. As such, even when it comes to declarative programming I'd much rather use Prolog then Haskell. Fortunately, there are Prolog systems compatible with the JVM and most scheme environments so you can embed Prolog in Clojure and Scheme for declarative programming tasks.
- sold 15y agoIt took me two months to really comprehend monads. Now I find them very intuitive and easy. However, they are definitely not easy to learn. It is like you are learning programming for the first time. Initially, they seem weird. Haskell requires patience. It is not a language where you can jump in and immediately see results, like jumping from C to Python. Someone who starts learning vi might be frustrated too. You need to learn ten keys before it becomes as productive as notepad. > In Ruby or a similar object oriented language you expect to find three APIs/gems, all with a similar object oriented syntax, but for three Haskell DSLs designed for three different tasks to share syntax implies that their authors failed to optimise them for those tasks, hence instead of five minutes with API documentation you have hours of DSL tutorials ahead of you before you can begin work. You need to learn monads only once. I can use new monads without any trouble.
- giardini 15y agoWhat makes it difficult to "really comprehend monads"? Why did it take two months for you to really comprehend them?
- sold 15y ago- I made many mistakes in the learning process. Monads should be done after you know core language (higher order functions, ADTs and pattern matching, typeclasses). I was attempting to learn many things at once and perfectly, instead of climbing Wittgenstein's ladders. - Getting used to nested functions, \x -> f >>= (\y -> g >>= h x y) is not that easy. - The type of bind, m a -> (a -> m b) -> m b is rather complex for a noob. You've got polymorphism, and m can be different depending on the monad. Monads form a higher-kinded typeclass * -> * , unlike most other typeclasses * . I discovered Functor rather late. You need to realize Reader r is a monad, not Reader, not Reader r a. Partial application on types. - It took me some time to read and rederive all standard monads - [], Maybe, Reader, Writer, State, Cont. Those things enter the mind slowly, especially state and continuations. Now I can reimplement all of them given a scratch of paper. - If you do not know IO, you can only use GHCi to test expressions. I thought I need to know monads very well to do IO. This is not true, but I survived a month by loading modules and interacting with GHCi only. On the other side, after all this trouble IO clicked immediately. Fortunately Haskell has enough concepts you can learn for a month without writing a complete interactive program. Look at http://www.haskell.org/haskellwiki/Blow_your_mind http://www.haskell.org/haskellwiki/Blow_your_mind for example. - After you know (>>=), return you need to learn standard library functions such as join, mapM, sequence, forever etc. Then transformers. - When I was learning, there was no Learn You a Haskell or Typeclassopedia yet. I found sigfpe's famous http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad... very late. I found a lot of useless buzz and opinions but rarely with details or instructive code. I am happy I had a good curious attitude and did not resign.
- thu 15y agoFortunatly, repeatedly saying the same things "Scheme shares Haskell's unsuitability for production code" "it prohibits simple, but crucial, impure tasks such as writing to files and communicating over networks" "it is beautiful, but it is useless for hacking" doesn't make them true. Plenty of people use successfully Haskell in production. I wonder what kind of motivation one can have to say with such emphasis a tool is useless while they simply can't use it properly.
- DanWaterworth 15y agoHaskell is not a language that you can expect to pick up and be writing awesome stuff by lunch time. There's no substitute for humbling yourself and learning to program all over again. I understand that it's difficult; you think you've mastered the art of writing programs, but suddenly you're back at square one. No language is perfect, but if you persist and stick with it long enough to become productive, you will have learnt a huge amount and that knowledge is useful in the real-world.
- gtani 15y agoHaskell is very fun, and well tutorialized now (2nd half of Thompson book is very good tutorial(2nd ed, $5), there are small speed bumps: I needed a little better glossary than book provides for "invariant", "witness", other terms folks sling around. It took me a while to figure out hoogle, and I needed to ignore blog posts about bijective vs surjective functions and category theory as a beginner. Also the ghc instance extensions are probably the most thinly documented corner: TypeSynonymInstances, -XUndecidableInstances, Flexible, Overlapping, etc
- SkyMarshal 15y agoWhile we're at it, let me throw out a shoutout for Learn You a Haskell For Great Good. One of the best programming books I've read, Miran is excellent at explaining programming concepts.
- daivd 15y agoThere are good tutorials to Haskell, but it seems to me that Haskell best practices still evolves fairly quickly. After "Real World Haskell" and "Learn you a Haskell", I still did not know what most of the GHC extensions are for (especially those related to generalizing types seem interesting), how to write idiomatic IO-code (conduits now, apparently? Or is it Pipes?), or how I should choose between the many ways of computing on many cores. Is Data Parallel Haskell mature enough? STM? The par combinator? accelerate? I don't think they mention Template Haskell (which seems powerful). The recommended way to connect to SQL is also in a state of flux (possibly "persistent"?).
- mark_l_watson 15y agoLisping (written by the author of the article) purchaser here - a really interesting product. Now, nit-picks with this article: mostly that Haskell and Scheme are not suitable for production. I am fairly weak with Haskell. I have bought three books, read through parts of them, and played with a lot of little bits of code. My non-expert opinion based on reading people's and company's success stories with Haskell convinces me that either the language is fit for production or the people who use Haskell are great developers and can ship with anything. Probably both possibilities are true. I do have a lot of experience with Scheme (I wrote a (not very good) Springer Verlag Scheme book in ancient times, once ported all of OPS5 from Common Lisp to Scheme in about 10 hours flat, and lots of projects...). I find Gambit Scheme great for writing small and efficient utility programs and the Racket system certainly has a lot of available libraires for getting stuff done.
- egonschiele 15y agoI love Haskell, but parsing XML with it is a huge pain. Someday I want to write a better XML parsing library, but for now I use HXT. I wrote a blog post a while back that shows some sample usage: http://adit.io/posts/2012-03-10-building_a_concurrent_web_scraper_with_haskell.html http://adit.io/posts/2012-03-10-building_a_concurrent_web_sc....
- ericssmith 15y agoI use hexpat and it works nicely. I wasn't able to get very far with either haxml or hxt before having grief.
- reddit_clone 15y agoDoes hexpat work on Windows? I am asking since it is linking to expat dynamic library..
- egonschiele 15y agoI use HXT to parse HTML. AFAICT, Hexpat doesn't do much besides parse the XML file into a tree. It doesn't have the niceties that Nokogiri or BeautifulSoup do. For example, I can use Nokogiri to get all the links on a page like so: page.css("a"). HXT allows me to come close to this: tree >>> getXPathTreesInDoc "//a" But I haven't seen a single Haskell XML parsing library that is as nice as Nokogiri.
- ericssmith 15y agoIn my work, I read in XML, parse its elements, attributes, and data, producing new XML. Along with Parsec, Hexpat is well-suited to the task. I haven't had to parse HTML in Haskell. I use BeautifulSoup for that. I wouldn't be surprised if the Haskell libraries aren't as useful for that kind of thing.
- egonschiele 15y agoI wrote up a guide to working with HTML in HXT: http://adit.io/posts/2012-04-14-working_with_HTML_in_haskell.html http://adit.io/posts/2012-04-14-working_with_HTML_in_haskell... You might find it handy if you decide to give HXT another go :)
- ericssmith 15y ago" was trying to express my frustration at not being able to insert a little impure code temporarily to tweak behaviour and help with debugging." Why would you want to do that? Haskell is a functional language. You evaluate expressions, which can be done nicely in GHCI. When I first learned Haskell, I was also trying to apply my procedural programming habits. Looking back, the pain was a sign of doing it wrong. Once I learned to look at solutions 'functionally', it turned out not to be a big deal, and the resulting code is arguably better. However, it does sometimes become painful going back to procedural languages.
- prof_hobart 15y agoOne obvious reason would be if the input to your expression is relatively large or complex (e.g. a file).
- ericssmith 15y agoThat would not be obvious to me. I often have to process quite large and messy XML files and a functional approach works well. I'm not even sure how inserting print statements would be helpful.
- prof_hobart 15y agoThere may be far better ways of doing it, but for a Haskell beginner (and I'm certainly one of those), being able to quickly display what each function was seeing as its input/returning as its result as it chugged through a complex file would have made life a lot easier for me when I first tried this kind of parsing in Haskell.
- jroesch 15y agoI was once one of the people who was incorrectly told, and therefore believed simple tasks like IO in Haskell was hard. Though it couldn't be further from the truth. main = do handle <- openFile "filename.txt" ReadMode contents <- hGetContents h putStr contents Now that simple bit opens a file, reads its entire contents, and prints it to stdout. Look at something similar in Java: FileReader file = new FileReader("filename.txt") //Then I have to choose how to read the file in, how to //buffer it, ect. String contents = file.read(...) //... System.out.print(contents) In my opinion the Haskell approach is much cleaner and closer to reading a file in Python or Ruby, and more intuitive then trying to figure it out in Java.
- stcredzero 15y agoIt would be dishonest not to point out that despite it's utility to hackers, Scheme shares Haskell's unsuitability for production code. The difference is that Scheme is limited by its minimalistic standard library, not by a flaw in the language, and you can "upgrade" to a syntactically similar, but heavyweight, cousin such as Common Lisp, or Clojure, to get work done. I wonder if there's something to this notion. Would it be useful to study the "standard" libraries of various languages to determine what constitutes "suitability for production code?" Most likely, everything is relative to the particular application a shop wants to build.
- gosub 15y agoHe seems to prefer ruby.
- zrb 15y agoThat bank headquartered in Singapore uses something different from Haskell. It is almost Haskell in most aspects... but uses strict evaluation.