Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Haskell
Wiki community
Recent changes
Random page
HaskellWiki
Search
Search
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Syntactic sugar/Cons
(section)
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Special pages
Page information
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== General == Haskell's basic syntax consists of function definition and function application. Though in some cases function application is hard to read and digs into details that are not essential for the situation they describe. For this purpose special syntaxes like <hask>do</hask> syntax, guards, list notation, list comprehension, infix notation were introduced for some frequent programming tasks to allow a more pleasant look. Many people seem to like Haskell only because of its syntactic sugar. But adding syntactic sugar to a language is not a big achievement. Python, Perl, C++ have lots of syntactic sugar, but I wouldn't prefer them to Haskell. Why? Because they lack the transparency of data dependency of functional programming languages, they lack static but easy to use polymorphism, they lack lazy evaluation, they lack reliable modularisation. It's not amazing that Haskell provides a lot of syntactic sugar. It's amazing that every syntactic sugar has pure functional explanations. That proves the power of the functional concept. === Syntactic heroin === Compiler writers can only lose if they give way to the insistence of users requesting more syntactic sugar. Every user has his own preferred applications, everyone has his taste and everyone wants his special application and his taste to be respected in future language revisions. Who is authorised to decide which application is general and which is too special? Is it more important to have many syntactic alternatives such that all people can write with their individual styles or is it more important that code of several authors have homogenous appearance such that it can be read by all people? You can bet if new syntactic sugar arises many users will rush at it and forget about the analytic expression the special notation shall replace. To argue against that is like trying to take the most beloved toy from children. Every special notation leads to the question if it can be extended and generalised. Guards are extended to [[pattern guard]]s and [[list comprehension]] is generalised to [[parallel list comprehension]] in current versions of Haskell compilers. Infix notation for alphanumeric functions is already possible in Haskell98 but "lacks" the possibility to add arguments like in <hask>x `rel c` y</hask>. The last is not implemented, but was already requested. A solution using only Haskell98 infix operators is already [http://www.haskell.org/pipermail/haskell-cafe/2002-July/003215.html invented]. Further on, the more general [http://www.dcs.gla.ac.uk/mail-www/haskell/msg02005.html MixFix] notation was already proposed, not to forget the silent lifting of map data structures to [http://www.haskell.org/pipermail/haskell/2002-October/010629.html functions], [https://downloads.haskell.org/ghc/9.4.4/docs/users_guide/exts/rebindable_syntax.html#postfix-operators postfix operators], [[section of an infix operator|sections]] of [http://www.haskell.org/pipermail/haskell-cafe/2006-July/016683.html tuples], like <hask>(?,x,?)</hask>, [http://www.haskell.org/pipermail/haskell-cafe/2007-September/031544.html symbolic prefix operators]. What comes next? Rodney Bates called the phenomena not only "syntactic sugar" but "[http://portal.acm.org/citation.cfm?id=1071738 syntactic heroin]". :(See also http://www.cs.wichita.edu/~rodney/languages/Modula-Ada-comparison.txt) People start with a small dosis of syntactic sugar, they quickly want more, because the initial dose isn't enough for ecstasy any longer. If one drug no longer helps then stronger ones are requested. It is so much tempting because the users requesting syntactic sugar are not responsible for implementing it and for avoiding inferences with other language features. === Parse errors === Compiler users have contradictory wishes. On the one hand they want more syntactic sugar, on the other hand they want better parser error messages. They don't realize that one is quite the opposite of the other. E.g. when a parser reads an opening bracket it doesn't know whether it is the start of a list comprehension expression like <hask>[f x | x <- xs]</hask> or the start of a list of comma separated expressions like <hask>[f x, f y, g z]</hask>. Thus if you accidentally mix bars and commas the parser don't know if you wanted to write a list comprehension or a comma separated list. So it can't tell you precisely what you made wrong. Type error messages of GHC have already reached a complexity which can't be processed by many Haskell newbies. It is the price to be paid for a type system which tries to cope with as few as possible type hints. Let's consider another example from the view of a compiler. Internally it transforms the source code <haskell> (+1) </haskell> to <haskell> flip (+) 1 </haskell> then it compiles it like regular functional code. Though what happens if it encounters an error? If it reports the error like <code> type error in flip (+) 1 </code> (as Hugs November 2002) you wouldn't understand it, because you typed <hask>(+1)</hask> but not <hask>flip (+) 1</hask>. A compiler which handles this properly must support syntactic sugar at the same level like regular syntax which is obviously more complicated. === Sugar adds complexity === Syntactic sugar are usually special grammatical constructions. They can interfere badly with other constructions: * http://hackage.haskell.org/cgi-bin/haskell-prime/trac.cgi/wiki/FixityResolution But syntactic sugar does not only touch the compilers. Many other tools like those for syntax highlighting (emacs, nedit), source code markup (lhs2TeX), source code formatting (Language.Haskell.Pretty), source code transform (e.g. symbolic differentation), program proofs, debugging, dependency analysis, documentation extraction (haddock) are affected. Each tool becomes more complicated by more syntactic sugar. === Flexibility === The use of functions and functions of functions (i.e. higher order functions) allows for very flexible usage of program units. This is also true for the function notation, but it is not true for some syntactic sugar. E.g. <hask>map</hask> can be used with partial application which is not possible for list comprehension syntax. Thus <hask>map toLower</hask> can be generalised to lists of strings simply by lifting <hask>map toLower</hask> with <hask>map</hask>, again, leading to <hask>map (map toLower)</hask>. In contrast to that <hask>\s -> [toLower c | c <- s]</hask> has to be turned into <hask>\ss -> [[toLower c | c <- s] | s <- ss]</hask> or <hask>\ss -> map (\s -> [toLower c | c <- s]) ss</hask>. A function can get more arguments as the development goes on. If you are used to write <hask>x `rel` y</hask> then you have to switch to <hask>rel c x y</hask> after you added a new parameter to <hask>rel</hask>. The extended infix notation <hask>x `rel c` y</hask> is (currently?) not allowed, probably because then also nested infixes like in <hask>x `a `superRel` b` y</hask> must be handled. The prefix notation <hask>rel x y</hask> tends to need less rewriting. Guards need to be rewritten to <hask>if</hask>s or to [[Case]] statements when the result of a function needs post-processing. Say we have the functions <haskell> isLeapYear :: Int -> Bool isLeapYear year = mod year 4 == 0 && (mod year 100 /= 0 || mod year 400 == 0) leapYearText :: Int -> String leapYearText year | isLeapYear year = "A leap year" | otherwise = "Not a leap year" </haskell> where <hask>leapYearText</hask> shall be extended to other languages using the fictitious function <hask>translate</hask>. If you stick to guards you will possibly rewrite it to the clumsy <haskell> leapYearText :: Language -> Int -> String leapYearText lang year = translate lang (case () of () | isLeapYear year -> "A leap year" | otherwise -> "Not a leap year") </haskell> But what about <haskell> leapYearText :: Language -> Int -> String leapYearText lang year = translate lang (if (isLeapYear year) then "A leap year" else "Not a leap year") </haskell> So if you find that simpler why not using <hask>if</hask> also in the original definition? <haskell> leapYearText :: Int -> String leapYearText year = if (isLeapYear year) then "A leap year" else "Not a leap year" </haskell>
Summary:
Please note that all contributions to HaskellWiki are considered to be released under simple permissive license (see
HaskellWiki:Copyrights
for details). If you don't want your writing to be edited mercilessly and redistributed at will, then don't submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION!
Cancel
Editing help
(opens in new window)
Toggle limited content width