4 ms·
I enjoyed working through this book. Actually it helped me learn enough Haskell to realize that I wasn't that interested in it. I found that it wasn't as safe a
by rhizome31 12y ago
I enjoyed working through this book. Actually it helped me learn enough Haskell to realize that I wasn't that interested in it. I found that it wasn't as safe as it claimed to be and that the tooling was not very good. There are some refreshing and interesting ideas, but overall I'm not sure it was worth my time.
- codygman 12y ago> I found that it wasn't as safe as it claimed to be and that the tooling was not very good. How was Haskell not "as safe as it claimed to be"? What tooling was not very good? What tooling was missing for you?
- rhizome31 12y ago* Non-exhaustive patterns error was disappointing after being told that "if it compiles it will run". It seems to be the Haskell equivalent of NullPointerException (I'm told OCaml doesn't have this problem). * Cabal Hell: https://news.ycombinator.com/item?id=8011267 https://news.ycombinator.com/item?id=8011267 * Installing libraries is slow * The Haskell platform is not batteries included * JSON parsing seem to be more complicated than it needs to be * Also got confused by keywords naming: https://news.ycombinator.com/item?id=5689951 https://news.ycombinator.com/item?id=5689951 * I found Yesod API to be inelegant. I found it odd that it needs so many non-standard compiler extensions, which might be a sign that the language is not expressive enough. * One-letter variables seem to be idiomatic. This is unappealing to me because I try to make my code readable. * For the same reason, frequent use of special characters in operators (, <>, ///, etc.) in the standard library and in third-party libraries was not appealing. I was disappointed because I was attracted by referential integrity, strong compiler checks, pattern matching and function composition but overall I was left with the impression that the Haskell environment was not very well polished from a software engineering point of view.
- tome 12y ago> Non-exhaustive patterns error was disappointing after being told that "if it compiles it will run". Yes, it's somewhat strange this is only a compiler warning rather than a compiler error.
- codygman 12y agoI agree, I would prefer that it was an error as well. For my personal projects I use -WError, but sane defaults count for a lot.
- codygman 12y ago> * Non-exhaustive patterns error was disappointing after being told that "if it compiles it will run". It seems to be the Haskell equivalent of NullPointerException (I'm told OCaml doesn't have this problem). I agree that this should be an error by default, however -Wall would fix this issue for you now. > * Installing libraries is slow It is slow, but can be made much faster by using "cabal install -j${num_cpu_cores}". I also use -O0 to disable optimizations during development. There is also Halcyon, which I believe allows you to do some caching of libraries. A little more extreme (but complete imo) solution is to use the nix package manager or if you want to go all in, NixOS. > * The Haskell platform is not batteries included I keep going back and forth on how I feel about this. It's harder in the beginning because you aren't sure what to use. Once you get a feeling for what libraries are best though, it's a great advantage that those libraries move forward so quickly without being tied to GHC development practices which have to move more slowly. > * JSON parsing seem to be more complicated than it needs to be Really? Here is some JSON parsing code I wrote the other day[0] to show how pattern matching and exhaustiveness checks in Haskell are useful: {"purchaseType": "Rent","price": 0.99,"title": "inception"} Here is an implementation in Haskell: {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} import Data.Aeson import GHC.Generics import qualified Data.ByteString.Lazy as BL data PurchaseType = Free | Rent | Buy | Subscriber deriving (Show, Generic) instance FromJSON PurchaseType instance ToJSON PurchaseType data Media = Media { title :: String, price :: Float, purchaseType :: PurchaseType} deriving (Show, Generic) instance FromJSON Media instance ToJSON Media jsonData = "{\"title\": \"inception\", \"price\": 0.99, \"purchaseType\": \"Rent\"}" main = print $ (decode jsonData :: Maybe Media) -- running main gets: -- λ> main -- Just (Media {title = "inception", price = 0.99, purchaseType = Rent}) > * Also got confused by keywords naming: https://news.ycombinator.com/item?id=5689951 https://news.ycombinator.com/item?id=5689951 Those are just things you have to get used to and imo don't really seem like a big deal. Every language has these kinds of things, but Haskell has less than most. To qualify that last statement, once you've learned their very different set of abstractions you know everything you need to know. It is less work in general dealing with programmer defined abstractions built on top of functor, monoid, etc because those custom abstractions more closely resemble them, which is an effect of them having to follow laws. > * I found Yesod API to be inelegant. I found it odd that it needs so many non-standard compiler extensions, which might be a sign that the language is not expressive enough. Looking at a Yesod example[1], the most language extensions I saw were: {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} TemplateHaskell and OverloadedStrings are both just conveniences, I suppose there could be an argument that MutliParamTypeClasses and TypeFamilies mean the language is not expressive enough. One of the reasons for use of language extensions so much in Haskell is that it is designed by committee, it's quite possible that other languages might have already deprecated these language extensions and moved them into the core language. > * One-letter variables seem to be idiomatic. This is unappealing to me because I try to make my code readable. The only place I usually see one letter variable names is where it's quite obvious what they are. I don't think anyone would argue it's better to use something besides x and y in this function definition for instance: add x y = x + y To check out your claims, let's grab a few random snippets of code (I'm hitting the spacebar randomly then choosing first function I see) from the most popular[2] Haskell libraries: containers[3]: isSubmapOf :: (Ord k,Eq a) => Map k a -> Map k a -> Bool isSubmapOf m1 m2 = isSubmapOfBy (==) m1 m2 bytestring[4]: -- | Add a list of non-negative numbers. Errors out on overflow. checkedSum :: String -> [Int] -> Int checkedSum fun = go 0 where go !a (x:xs) | ax >= 0 = go ax xs | otherwise = overflowError fun where ax = a + x go a _ = a directory[5]: setOwnerReadable :: Bool -> Permissions -> Permissions setOwnerReadable b p = p { readable = b } What I personally take from above is that while Haskell does use single letter variables, the types make it obvious what those variables are. As a test, I'll go to the next popular library and look for a longer function to see if this line of thought breaks down. text[6]: fromString :: String -> Builder fromString str = Builder $ \k (Buffer p0 o0 u0 l0) -> let loop !marr !o !u !l [] = k (Buffer marr o u l) loop marr o u l s@(c:cs) | l <= 1 = do arr <- A.unsafeFreeze marr let !t = Text arr o u marr' <- A.new chunkSize ts <- inlineInterleaveST (loop marr' 0 0 chunkSize s) return $ t : ts | otherwise = do n <- unsafeWrite marr (o+u) c loop marr o (u+n) (l-n) cs in loop p0 o0 u0 l0 str where chunkSize = smallChunkSize Alright... str is obviously string, marr is mutable array.. o, u, and l... what could those be? Well it's getting set from the Buffer type, so it looks like I'll have to see what the type of that is. Prelude GHC.IO.Buffer> :i Buffer type role Buffer phantom data Buffer e = Buffer {bufRaw :: {-# UNPACK #-} !RawBuffer e, bufState :: BufferState, bufSize :: {-# UNPACK #-} !Int, bufL :: {-# UNPACK #-} !Int, bufR :: {-# UNPACK #-} !Int} -- Defined in ‘GHC.IO.Buffer’ Prelude GHC.IO.Buffer> :t Buffer Buffer :: RawBuffer e -> BufferState -> Int -> Int -> Int -> Buffer e I'll concede that names other than o, u, l, and k would have helped here. Perhaps even renaming ts as texts would have been more clear. > * For the same reason, frequent use of special characters in operators (, <>, ///, etc.) in the standard library and in third-party libraries was not appealing. "Special characters" in operators? When most people say special characters they mean unicode. <> and /// look to be normal characters to me. With that said I go back and forth between finding operators appealing/unappealing. For instance I find this to be understandable and a good choice: "home" </> "cody" </> "Downloads" I also think that making users learn a few symbols isn't so bad, as long as you don't go to far. The main symbols I'd say you need to know are >>=, <$>, <>, and maybe <> and >=>. >>= doesn't have a non-symbol alternative I don't believe, <$> is fmap, <> is ap, <> is mappend, and I'm not sure if >=> has a non-symbol alternative. > I was disappointed because I was attracted by referential integrity, strong compiler checks, pattern matching and function composition Those are many of the reasons I was attracted to Haskell and still use it today, are you claiming Haskell doesn't have those things? If you are making that claim just because exhaustiveness checking isn't an error by default, I'd say that seems disingenious. > but overall I was left with the impression that the Haskell environment was not very well polished from a software engineering point of view. Was it just the above that left you with that impression, or was it other things as well? Can you give an example of a language that is well polished from a software engineering point of view and what makes it "polished"? 0: https://news.ycombinator.com/item?id=9037452 https://news.ycombinator.com/item?id=9037452 1: https://www.fpcomplete.com/school/project-templates/file-server https://www.fpcomplete.com/school/project-templates/file-ser... 2: http://kwangyulseo.com/2014/02/03/top-30-haskell-pakcages-with-most-reverse-dependencies/ http://kwangyulseo.com/2014/02/03/top-30-haskell-pakcages-wi... 3: http://hackage.haskell.org/package/containers-0.5.6.3/docs/src/Data-Map-Base.html#isSubmapOf http://hackage.haskell.org/package/containers-0.5.6.3/docs/s... 4: http://hackage.haskell.org/package/bytestring-0.10.4.1/docs/src/Data-ByteString-Internal.html#checkedSum http://hackage.haskell.org/package/bytestring-0.10.4.1/docs/... 5: http://hackage.haskell.org/package/directory-1.2.1.0/docs/src/System-Directory.html#setOwnerReadable http://hackage.haskell.org/package/directory-1.2.1.0/docs/sr... 6: http://hackage.haskell.org/package/text-1.2.0.4/docs/src/Data-Text-Internal-Builder.html#fromString http://hackage.haskell.org/package/text-1.2.0.4/docs/src/Dat...