6 ms·
FWIW, I, too, have tried learning Haskell and ended up banging my head against the wall over and over. With Lisp, I eventually "got it", but Haskell has evaded
by krylon 9y ago
FWIW, I, too, have tried learning Haskell and ended up banging my head against the wall over and over. With Lisp, I eventually "got it", but Haskell has evaded my attempts at understanding it with impressive stubbornness[1].
Disclaimer: I do not hate Haskell, I just don't "get it". If you love the language, fine, have as much fun with it as you possibly can. I for one have given up, at least for now. Maybe I'll try again next year.
[1] NB that the word "stubbornness" has three pairs of double consonants. How fun is that?
- seagreen 9y agoHaskell's rough to learn because it hits you with purity, category theory inspired typeclasses, and laziness all at once. It's natural that people struggle with this (I sure did). If you feel like trying a pure language again someday you could consider PureScript (which just has the first 2 things above) or Elm (which just has the 1st). If you do try I'd like to hear how it goes, email in profile.
- krylon 9y agoMy main problem with Haskell was not the pure, funcational part. It was the side-effect-laden part. If I were ever to go there again, I would probably give OCaml a try. It seems to offer many of the benefits of Haskell, while also offering "a way out" into the familiar world of objects and side effects. But don't hold your breath, I don't think I will get there this year.
- hardwaresofton 9y agoWhat do you mean by the "side-effect-laden" part? Did you find yourself writing lots of side effecting code because of Haskell (which seems weird)? Or Haskell just wasn't a good fit for a project that was full of side-effecting code? If it's the latter, I can definitely tell you that part of the zen of Haskell is firming up the boundaries between side-effecting code and pure code -- for example, IMHO the better you get at Haskell, the less `do` statements show up in your code (for better or for worse, because >>=, <*>, and co make it harder for newcomers to enter a codebase)
- krylon 9y agoWriting a purely functional function like, say, factorial, or the Ackermann function, was no problem at all. Writing a "purely" side effect-based one, say, read a string from stdin, parse an age, and say, "What, you are %d years old?!?! Wow, you're old!" completely eluded me. Maybe it was just that all the tutorials I encountered sucked. Maybe I am just too dumb for Haskell. Given that I currently really love Go, I kind of suspect the latter. But who knows? I'll find out next year, I guess. ;-)
- hardwaresofton 9y agoSo yeah, I definitely get that. I'm no Haskell master, but I found that my code progressed this way (assuming I was trying to do what you mentioned": main :: IO () main = do putStrLn "Please input your age:" age <- getLine when (age < 10) (putStrLn "..." ++ (show age)) when (10 =< age < 40) (putStrLn "..." ++ (show age)) when (age >= 40) (putStrLn "..." ++ (show age)) But as you get more comfortable, you get something like: type Age = Int -- Imagine there are constants here for youngAgeMessage, middleAgeMessage, and oldAgeMessage, -- for simplicity they're just strings, though you could add even more descriptive aliases -- like "OldMessage" with a quick union type like AgeMesssage = YoungAgeMessage | MiddleAgeMessage | OldAgeMessage, etc etc makeAgeMessage :: Age -> String makeAgeMessage age | age < 10 = youngAgeMessage ++ show age | 10 =< age < 40 = middleAgeMessage ++ show age | age >= 40 = oldAgeMessage ++ show age main :: IO () main = putStrLn "Please enter your age:" >> getLine >>= putStrLn . makeAgeMessage . read This isn't even the final form of this code either, there are some more things you could do to make this code more axiomatic haskell. This code is approximate (like you probably can't copy and paste it, probably won't compile) but should at least show what I mean. It's similar to early clojure and the use (and eventual love, usually, of the threading macro "->") and the unix philosophy -- once you start writing those clean functions that pass whatever they need right along, it starts getting easier (and more desirable) to pluck out the parts that don't have to be side-effecting. Also, the type system expresiveness is just amazing -- it's what Java should have been but never got the chance to be: data Thing = OneThing | AnotherThing | ThirdThing Guess what a `Thing` can be? literally just those things, not even a null or anything. A lot of people say they really love/need/only use "strongly typed" languages (which means a ton of things to a ton of people), but the biggest slap in the face to me is how a language like Java (that people will reach for when they want to compare some usually weaker language to a "strongly typed" one), is a literal minefield of Null Pointer Exceptions (NPEs). "Anything can be anything or sometimes nil" is a hard pill to swallow once you've used Haskell. Also, trying to use Option<> everywhere feels wrong if you do it in Java, because it starts to bleed everywhere, but actually... it's absolutely right (IMO) -- imagine how much better java code could be if the default was to Option.map over things, and the second you decided to try and pull a value out, you knew you were opening yourself up to something bad, instead of just passing things around and hoping they're there or writing repetitive checks. Now, if you see a `Maybe Thing`, you instantly know that that thing is either JUST the thing, or it's Nothing, and maybe's type is: data Maybe a = Just a | Nothing Type classes are also amazing, they're basically just as ergonomic as Go's interfaces, without some of the weird hangups and interface{} All that said, I definitely get the hangup, Haskell is difficult to get started with, even to this day, but man, that hurdle is so worth. Maybe I'm just addicted to high-learning-curve things but Haskell feels good.
- todd8 9y agoI totally understand your frustration with Haskell. I understand the tutorials and have read though the books available, but when I try to use the language on a small real project, say a 2d barcode generator, I have trouble getting off the ground. Its not even clear to me which set of features are recommended for the language. It seems like different users program in different, incompatible, languages! Here is a list of optional language extensions supported by GHC: Cpp OverlappingInstances UndecidableInstances IncoherentInstances UndecidableSuperClasses MonomorphismRestriction MonoPatBinds MonoLocalBinds RelaxedPolyRec ExtendedDefaultRules ForeignFunctionInterface UnliftedFFITypes InterruptibleFFI CApiFFI GHCForeignImportPrim JavaScriptFFI ParallelArrays Arrows TemplateHaskell TemplateHaskellQuotes QuasiQuotes ImplicitParams ImplicitPrelude ScopedTypeVariables AllowAmbiguousTypes UnboxedTuples UnboxedSums BangPatterns TypeFamilies TypeFamilyDependencies TypeInType OverloadedStrings OverloadedLists NumDecimals DisambiguateRecordFields RecordWildCards RecordPuns ViewPatterns GADTs GADTSyntax NPlusKPatterns DoAndIfThenElse RebindableSyntax ConstraintKinds PolyKinds DataKinds InstanceSigs ApplicativeDo StandaloneDeriving DeriveDataTypeable AutoDeriveTypeable DeriveFunctor DeriveTraversable DeriveFoldable DeriveGeneric DefaultSignatures DeriveAnyClass DeriveLift DerivingStrategies TypeSynonymInstances FlexibleContexts FlexibleInstances ConstrainedClassMethods MultiParamTypeClasses NullaryTypeClasses FunctionalDependencies UnicodeSyntax ExistentialQuantification MagicHash EmptyDataDecls KindSignatures RoleAnnotations ParallelListComp TransformListComp MonadComprehensions GeneralizedNewtypeDeriving RecursiveDo PostfixOperators TupleSections PatternGuards LiberalTypeSynonyms RankNTypes ImpredicativeTypes TypeOperators ExplicitNamespaces PackageImports ExplicitForAll AlternativeLayoutRule AlternativeLayoutRuleTransitional DatatypeContexts NondecreasingIndentation RelaxedLayout TraditionalRecordSyntax LambdaCase MultiWayIf BinaryLiterals NegativeLiterals DuplicateRecordFields OverloadedLabels EmptyCase PatternSynonyms PartialTypeSignatures NamedWildCards StaticPointers TypeApplications Strict StrictData MonadFailDesugaring I've seen different subsets of these extensions recommended. Is there some canonical subset recommended by anyone doing real work in Haskell? Even more off topic: in reference to your note about the word "stubbornness", the word "bookkeeping" has three consecutive doubled letters. I believe that there are no examples of four consecutive doubled letters in any ordinary English dictionary, but I ought to grep the longer lexicons I've got at home.
- 9y ago