5 ms·
Haskell is badly designed language in many respects which promotes ugly code. I think, it won't be mainstream statically typed functional language in any time.
by solomatov 13y ago
Haskell is badly designed language in many respects which promotes ugly code. I think, it won't be mainstream statically typed functional language in any time.
Here is my list of bad language features:
1. It doesn't support dot notation for records.
2. Record names can't be overloaded.
3. Monads might lead to messy code due to verbose syntax. For example, instead of writing c <- openDbConnection (readConfigData), I have to write ugly code
do
conf <- readConfigData
c <- openDbConnection
The situation becomes worse, the more side effecting parameters you need for a function call.
5. Many extensions, essential for productive development are out of the language standard. For example, multi param type classes, existential types. Haskell' standard is in progress for a very long time, and still isn't finished.
- sseveran 13y ago1. Nonissue in real life. 3. Don't modify parameters. It makes code easier to test in any language. 5. GHC may as well be the standard. Are you really going to use a different compiler.
- solomatov 13y ago>3. Don't modify parameters. It makes code easier to test in any language. It's not about modifying parameters. It's about verbosity of the code. The type of the parameter is IO String. >5. GHC may as well be the standard. Are you really going to use a different compiler. It's a real issue. Different language extensions might modify how type inference works. If you add one more extension, you program might suddenly stop to compile. We need a fixed set of language extensions which are always available.
- sseveran 13y ago3. in general haskell is even terser then i like. 5. What on earth are you talking about? Conjecturing about type inference is not useful. While I may prefer some extensions to be on be default, in hundreds of thousands of lines of haskell code I am yet to see adding an extension break existing code. The worst I have seen is adding an extension slow down compilation. In haskell you have to forget most of what you have learned in order to be successful. Otherwise you will fight the language.
- quchen 13y ago> The type of the parameter is IO String. No, the type of the parameter is String. IO String is the type of the expression that gets that parameter when executed. There's a popular quote by shachaf, "getLine :: IO String contains a String in the same way that /bin/ls contains a list of files" that illustrates this nicely.
- enigmo 13y ago> If you add one more extension, you program might suddenly stop to compile. Do you have some real examples of this happening with GHC extensions? I haven't run across one in the field. > We need a fixed set of language extensions which are always available. This sounds very much like a language standard. Haskell isn't much different than other languages here, though the language committee is slow to ratify generally accepted extensions into the standard. GHC at least makes them available to people who want to kick the tires. Then read about closures in Java. Look at C++11 revisions and notice that sometimes meant cutting features, even if they were previously implemented by some compilers (template exports) or prototyped (concepts).
- solomatov 13y ago>Do you have some real examples of this happening with GHC extensions? I haven't run across one in the field. I am not that advanced in how GHC types work. However, I understand, that in any language extensions there are tradeoffs between how expressive a language is and how much type inference we have.
- enigmo 13y agoMany (most?) of GHC's commonly used language extensions enable new functionality or syntax (DataKinds, GADTs, RankNTypes, KindSignatures, TypeFamilies, FunDeps, MPTCs, etc). Enabling such extensions and not using these newly enabled features shouldn't affect type inference.
- gonnakillme 13y agoYou can write the example in your third problem as "readConfigData >>= openDbConnection". This is, in fact, something like what your code desugars to. "do" notation is a useful crutch for difficult code; it's not fair to use that as an example of "verbose syntax".
- sanxiyn 13y agoI do think 2 is a real problem, but it seems Haskell people couldn't agree on the solution. Simon Peyton Jones (Haskell 98 standard editor) proposed a change but many people didn't like it. http://ghc.haskell.org/trac/haskell-prime/wiki/TypeDirectedNameResolution http://ghc.haskell.org/trac/haskell-prime/wiki/TypeDirectedN...
- merijnv 13y agoFWIW, there is currently a GSoC project supervised by SPJ that is working on making overloadable fields available in GHC.
- davorak 13y agoThe code: do conf <- readConfigData c <- openDbConnection Or just do c <- openDbConnection =<< readConfigData -- do something with c Where `=<<` can be thought of an infix apply for monads.
- quchen 13y agoI'm not sure what you mean with "do notation for records", but yes, there are some problems with record notation. Lens/zipper libraries can help with that though. (Overloading record names would be sweet in any case.) > Monads might lead to messy code due to verbose syntax. Your example could be written `do c <- openDbConnection =<< readConfigData` (assuming there should be a `conf` in the third line). If you need multiple parameters passed like this you're right, you probably need to execute them separately and give their results names. That however can also lead to more readable code if getting the parameters isn't just a single statement. > Many extensions, essential for productive development are out of the language standard. There is always this discussion what "valid Haskell" is, on the one side the "Haskell Report" guys, on the other the "whatever GHC accepts for the next 10 years" section. A few remarks: - GHC is a giant project that uses neither multi-parameter typeclasses nor existentials. - I don't think language extensions are ever removed from GHC, just pronounced deprecated. (I don't know about such a case at least, correct me if I'm wrong) - Heavy use of language extensions does mean GHC lock-in. It's free software, but I can still see how that could be a concern.
- enigmo 13y agoI previously agreed with complaints #1 and #2, though at some point over the last few years this has stopped being a problem. It's not even Stockholm syndrome, I just don't use records that much anymore. The various lens packages can help with record overloading and dot indexed fields, but without some compiler support it will remain a sore spot for people who want/need a better record system. #5 is a fair to a point. I don't find MPTC or existential types to be useful in almost any case: I actively try to avoid both. ScopedTypeVariables, FlexibleContexts, FlexibleInstances and potentially RankNTypes and the poorly named UndecidableInstances should be standard though (imo). Some people also find OverlappingInstances and the like to be generally useful but you probably don't want to hear what I'd say about the subject. There are plenty of other (also subjectively ugly) ways to write #3. SHE (a Haskell preprocessor) deals with it in one way, see the pigworker's idiom brackets: https://personal.cis.strath.ac.uk/conor.mcbride/pub/she/idiom.html https://personal.cis.strath.ac.uk/conor.mcbride/pub/she/idio.... Without a preprocessor you can certainly use applicatives or some regular monad combinators to git'r'done but a little sugar could go a long ways. I'm not attached to any of these. Lucky for us there are many languages to choose from, personal taste has proven a fickle mistress. import Control.Applicative import Control.Monad data ConfigData data DbConnection readConfigData :: IO ConfigData readConfigData = undefined openDbConnection :: ConfigData -> IO DbConnection openDbConnection = undefined openDbConnection2 :: ConfigData -> ConfigData -> IO DbConnection openDbConnection2 = undefined openDbConnection3 :: ConfigData -> ConfigData -> ConfigData -> IO DbConnection openDbConnection3 = undefined main :: IO () main = do -- it does work... conf <- readConfigData _c0 <- openDbConnection conf -- how about a flipped bind? _c1 <- openDbConnection =<< readConfigData -- or join/fmap... _c2 <- join $ openDbConnection <$> readConfigData -- need two parameters? liftA2/liftM2 has been around for a while _c3 <- join $ liftA2 openDbConnection2 readConfigData readConfigData -- or use Functor/Applicative to deal with arbitrary numbers of side effecting parameters, longhand idiom brackets... _c4 <- join $ openDbConnection3 <$> readConfigData <*> readConfigData <*> readConfigData return ()
- swift 13y ago1. Don't see the appeal. 2. Definitely agreed. 3. "readConfigData >>= openDBConnection" can be used in a simple case like your example. Cases with more arguments can use "ap" or "<*>", which are perhaps a bit ugly, but most of the time you don't need them. 5. The fact that Haskell is a living language that is improving all the time is a point in its favor, I think.
- IsTom 13y agoYou can use operators to deal with 3. do c <- openDbConnection =<< readConfigData As for 5., GHC is de-facto standard.