Haskell (programming language)

From Bauman National Library
This page was last modified on 8 June 2016, at 20:25.
Haskell
Logo of Haskell
Paradigm functional, lazy/non-strict, modular
Designed by Lennart Augustsson, Dave Barton, Brian Boutel, Warren Burton, Joseph Fasel, Kevin Hammond, Ralf Hinze, Paul Hudak, John Hughes, Thomas Johnsson, Mark Jones, Simon Peyton Jones, John Launchbury, Erik Meijer, John Peterson, Alastair Reid, Colin Runciman, Philip Wadler
Stable release Haskell 2010[1] / July 2010; 10 years ago (2010-07)
Typing discipline static, strong, inferred
OS Cross-platform
Filename extensions .hs, .lhs
Website Template:Url
Major implementations
GHC, Hugs, NHC, JHC, Yhc, UHC
Dialects
Helium, Gofer
Influenced by

Clean,[2] FP,[2] Gofer,[2] Hope and Hope+,[2] Id,[2] ISWIM,[2] KRC,[2] Lisp,[2] Miranda,[2] ML and Standard ML,[2] Orwell, SASL,[2]

Scheme,[2] SISAL[2]
Influenced
Agda,[3] Bluespec,Template:Sfn C++11/Concepts,[4] C#/LINQ,Template:Sfn[5][6][7] CAL,Template:Fix/category[citation needed]]] Cayenne,Template:Sfn Clean,Template:Sfn Clojure,[8] CoffeeScript,[9] Curry,Template:Sfn Elm, Epigram,Template:Fix/category[citation needed]]] Escher,[10] F#,[11] Frege,[12] Hack,[13] Idris,[14] Isabelle,Template:Sfn Java/Generics,Template:Sfn LiveScript,[15] Mercury,Template:Sfn Omega,Template:Fix/category[citation needed]]] Perl 6,[16] Python,Template:Sfn[17] Rust,[18] Scala,Template:Sfn[19] Swift,[20] Timber,[21] Visual Basic 9.0Template:Sfn[5]

Haskell is a computer programming language. In particular, it is a polymorphically statically typed, lazy, purely functional language, quite different from most other programming languages. The language is named for Haskell Brooks Curry, whose work in mathematical logic serves as a foundation for functional languages. Haskell is based on the lambda calculus, hence the lambda we use as a logo.

It is specifically designed to handle a wide range of applications, from numerical through to symbolic. To this end, Haskell has an expressive syntax, and a rich variety of built-in data types, including arbitrary-precision integers and rationals, as well as the more conventional integer, floating-point and boolean types.

History

Following the release of Miranda by Research Software Ltd, in 1985, interest in lazy functional languages grew: by 1987, more than a dozen non-strict, purely functional programming languages existed. Of these, Miranda was the most widely used, but it was proprietary software. At the conference on Functional Programming Languages and Computer Architecture (FPCA '87) in Portland, Oregon, a meeting was held during which participants formed a strong consensus that a committee should be formed to define an open standard for such languages. The committee's purpose was to consolidate the existing functional languages into a common one that would serve as a basis for future research in functional-language design[22].

Haskell 1.0 to 1.4

The first version of Haskell ("Haskell 1.0") was defined in 1990[23]. The committee's efforts resulted in a series of language definitions (1.0, 1.1, 1.2, 1.3, 1.4)

Haskell 98

In late 1997, the series culminated in Haskell 98, intended to specify a stable, minimal, portable version of the language and an accompanying standard library for teaching, and as a base for future extensions. The committee expressly welcomed the creation of extensions and variants of Haskell 98 via adding and incorporating experimental features[22].

In February 1999, the Haskell 98 language standard was originally published as "The Haskell 98 Report"[22]. In January 2003, a revised version was published as "Haskell 98 Language and Libraries: The Revised Report"[22]. The language continues to evolve rapidly, with the Glasgow Haskell Compiler (GHC) implementation representing the current de facto standard[24].

Haskell 2010

The current Haskell standard, Haskell 2010, was announced at November 24th 2009; GHC supports it since revision 7.0.1.

Changes since Haskell '98:

  • Do And If Then Else
  • Hierarchical Modules
  • Empty Data Declarations
  • Fixity Resolution
  • Foreign Function Interface
  • Line Comment Syntax
  • Pattern Guards
  • Relaxed Dependency Analysis
  • Language Pragma
  • Remove n+k patterns

Furthermore, changes that were made in the base libraries, were added to the report.

An additional change was published at January 7th 2011: No Datatype Contexts

  • Bulleted list item

Features

Staticaly typed

Every expression in Haskell has a type which is determined at compile time. All the types composed together by function application have to match up. If they don't, the program will be rejected by the compiler. Types become not only a form of guarantee, but a language for expressing the construction of programs.

All Haskell values have a type:

char = 'a'    :: Char
int = 123     :: Int
fun = isDigit :: Char -> Bool

You have to pass the right type of values to functions, or the compiler will reject the program:

Type error
isDigit 1

You can decode bytes into text:

bytes = Crypto.Hash.SHA1.hash "hello" :: ByteString
text = decodeUtf8 bytes               :: Text

But you cannot decode Text, which is already a vector of Unicode points:

Type error
doubleDecode = decodeUtf8 (decodeUtf8 bytes)

Type inference

You don't have to explicitly write out every type in a Haskell program. Types will be inferred by unifying every type bidirectionally. However, you can write out types if you choose, or ask the compiler to write them for you for handy documentation.

This example has a type signature for every binding:

main :: IO ()
main = do line :: String <- getLine
          print (parseDigit line)
  where parseDigit :: String -> Maybe Int
        parseDigit ((c :: Char) : _) =
          if isDigit c
             then Just (ord c - ord '0')
             else Nothing

But you can just write:

main = do line <- getLine
          print (parseDigit line)
  where parseDigit (c : _) =
          if isDigit c
             then Just (ord c - ord '0')
             else Nothing

You can also use inference to avoid wasting time explaining what you want:

do ss <- decode "[\"Hello!\",\"World!\"]"
   is <- decode "[1,2,3]"
   return (zipWith (\s i -> s ++ " " ++ show (i + 5)) ss is)
 => Just ["Hello! 6","World! 7"]

Types give a parser specification for free, the following input is not accepted:

do ss <- decode "[1,2,3]"
   is <- decode "[null,null,null]"
   return (zipWith (\s i -> s ++ " " ++ show (i + 5)) ss is)
 => Nothing

Lazy

Functions don't evaluate their arguments. This means that programs can compose together very well, with the ability to write control constructs (such as if/else) just by writing normal functions. The purity of Haskell code makes it easy to fuse chains of functions together, allowing for performance benefits.

Define control structures easily:

when p m = if p then m else return ()
main = do args <- getArgs
          when (null args)
               (putStrLn "No args specified!")

If you notice a repeated expression pattern, like

if c then t else False

you can give this a name, like

and c t = if c then t else False

and then use it with the same effect as the orginal expression.

Get code re-use by composing lazy functions. It's quite natural to express the any function by reusing the map and or functions:

any :: (a -> Bool) -> [a] -> Bool
any p = or . map p

Reuse the recursion patterns in map, filter, foldr, etc.

Purely functional

Every function in Haskell is a function in the mathematical sense (i.e., "pure"). Even side-effecting IO operations are but a description of what to do, produced by pure code. There are no statements or instructions, only expressions which cannot mutate variables (local or global) nor access state like time or random numbers.

The following function takes an integer and returns an integer. By the type it cannot do any side-effects whatsoever, it cannot mutate any of its arguments.

square :: Int -> Int
square x = x * x

The following string concatenation is okay:

"Hello: " ++ "World!"

The following string concatenation is a type error:

Type error
"Name: " ++ getLine

Because getLine has type IO String and not String, like "Name: " is. So by the type system you cannot mix and match purity with impurity.

Concurrent

Haskell lends itself well to concurrent programming due to its explicit handling of effects. Its flagship compiler, GHC, comes with a high-performance parallel garbage collector and light-weight concurrency library containing a number of useful concurrency primitives and abstractions.

Easily launch threads and communicate with the standard library:

main = do
  done <- newEmptyMVar
  forkIO (do putStrLn "I'm one thread!"
             putMVar done "Done!")
  second <- forkIO (do delayThread 100000
                       putStrLn "I'm another thread!")
  killThread second
  msg <- takeMVar done
  putStrLn msg

Use an asynchronous API for threads:

do a1 <- async (getURL url1)
  a2 <- async (getURL url2)
  page1 <- wait a1
  page2 <- wait a2
  ...

Atomic threading with software transactional memory:

transfer :: Account -> Account -> Int -> IO ()
transfer from to amount =
  atomically (do deposit to amount
                 withdraw from amount)

Atomic transactions must be repeatable, so arbitrary IO is disabled in the type system:

Type error
main = atomically (putStrLn "Hello!")

Packages

Open source contribution to Haskell is very active with a wide range of packages available on the public package servers.

There are 6,954 packages freely available. Here is a sample of the most common ones:

  • bytestring - Binary data
  • base - Prelude, IO, threads
  • network - Networking
  • text - Unicode text
  • parsec - Parser library
  • directory - File/directory
  • hspec - RSpec-like tests
  • attoparsec - Fast parser
  • monad-logger - Logging
  • persistent - Database ORM
  • template-haskell - Meta-programming
  • tar - Tar archives
  • snap - Web framework
  • time - Date, time, etc.
  • happstack - Web framework
  • yesod - Web framework
  • containers - Maps, graphs, sets
  • fsnotify - Watch filesystem
  • hint - Interpret Haskell
  • unix - UNIX bindings
  • SDL - SDL binding
  • OpenGL - OpenGL graphics system
  • criterion - Benchmarking
  • pango - Text rendering
  • cairo - Cairo graphics
  • statistics - Statistical analysis
  • gtk - Gtk+ library
  • glib - GLib library
  • test-framework - Testing framework
  • resource-pool - Resource pooling
  • conduit - Streaming I/O
  • mwc-random - High-quality randoms
  • QuickCheck - Property testing
  • stm - Atomic threading
  • blaze-html - Markup generation
  • cereal - Binary parsing/printing
  • xml - XML parser/printer
  • http-client - HTTP client engine
  • zlib - zlib/gzip/raw
  • yaml - YAML parser/printer
  • pandoc - Markup conversion
  • binary - Serialization
  • tls - TLS/SSL
  • zip-archive - Zip compression
  • warp - Web server
  • text-icu - Text encodings
  • vector - Vectors
  • async - Asyn concurrency
  • pipes - Streaming IO
  • scientific - Arbitrary-prec. nums
  • process - Launch processes
  • aeson - JSON parser/printer
  • dlist - Difflists
  • syb - Generic prog.

Code examples

The following is a Hello world program written in Haskell (note that all but the last line can be omitted):

module Main where
main :: IO ()
main = putStrLn "Hello, World!"

Here is the factorial function in Haskell, defined in a few different ways:

-- Type annotation (optional)
factorial :: (Integral a) => a -> a

-- Using recursion
factorial n | n < 2 = 1
factorial n = n * factorial (n - 1)

-- Using recursion, with guards
factorial n
  | n < 2     = 1
  | otherwise = n * factorial (n - 1)

-- Using recursion but written without pattern matching
factorial n = if n > 0 then n * factorial (n-1) else 1

-- Using a list
factorial n = product [1..n]

-- Using fold (implements product)
factorial n = foldl (*) 1 [1..n]

-- Point-free style
factorial = foldr (*) 1 . enumFromTo 1

Quicksort in Haskell

quicksort :: Ord a => [a] -> [a]
quicksort []     = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
    where
        lesser  = filter (< p) xs
        greater = filter (>= p) xs

Implementations

All listed implementations are distributed under open source licenses[25]. The following implementations comply fully, or very nearly, with the Haskell 98 standard.

  • The Glasgow Haskell Compiler (GHC) compiles to native code on a number of different architectures—as well as to ANSI C—using C-- as an intermediate language. GHC has become the de facto standard Haskell dialect[26]. There are libraries (e.g. bindings to OpenGL) that will work only with GHC. GHC is also distributed along with the Haskell platform.
  • The Utrecht Haskell Compiler (UHC) is a Haskell implementation from Utrecht University. UHC supports almost all Haskell 98 features plus many experimental extensions. It is implemented using attribute grammars and is currently mainly used for research into generated type systems and language extensions.

The following implementations are no longer being actively maintained:

  • Hugs, the Haskell User's Gofer System, is a bytecode interpreter. It used to be one of the most widely used implementations alongside the GHC compiler[27]., but has now been mostly replaced by GHCi. It also comes with a graphics library.
  • nhc98 is another bytecode compiler. Nhc98 focuses on minimizing memory usage.
  • Yhc, the York Haskell Compiler was a fork of nhc98, with the goals of being simpler, more portable and more efficient, and integrating support for Hat, the Haskell tracer. It also featured a JavaScript backend, allowing users to run Haskell programs in a Web browser.
  • HBC is an early implementation supporting Haskell 1.4. It was implemented by Lennart Augustsson in, and based on, Lazy ML. It has not been actively developed for some time.

The following implementations are not fully Haskell 98 compliant, and use a language that is a variant of Haskell:

  • Gofer was an educational dialect of Haskell, with a feature called "constructor classes", developed by Mark Jones. It was supplanted by Hugs.
  • Helium is a newer dialect of Haskell. The focus is on making it easy to learn by providing clearer error messages. It currently lacks full support for type classes, rendering it incompatible with many Haskell programs.

Applications

Darcs is a revision control system written in Haskell, with several innovative features. Cabal is a tool for building and packaging Haskell libraries and programs[28]. Linspire GNU/Linux chose Haskell for system tools development[29]. Xmonad is a window manager for the X Window System, written entirely in Haskell[30]. GHC is also often a testbed for advanced functional programming features and optimizations in other programming languages.

Industry

  1. Facebook implements its anti-spam programs in Haskell.
  2. Bluespec SystemVerilog (BSV) is a language for semiconductor design that is an extension of Haskell. Additionally, Bluespec, Inc.'s tools are implemented in Haskell.
  3. Cryptol, a language and toolchain for developing and verifying cryptographic algorithms, is implemented in Haskell.
  4. The first formally verified microkernel[31], seL4, used Haskell as a prototyping language for the OS developer[31]. At the same time the Haskell code defined an executable specification with which to reason, for automatic translation by the theorem-proving tool[31]. The Haskell code thus served as an intermediate prototype before final C refinement[31].

Web

There are Haskell web frameworks[32], such as:

  1. Yesod
  2. Happstack
  3. Snap[33]

Why use Haskell?

Writing large software systems that work is difficult and expensive. Maintaining those systems is even more difficult and expensive. Functional programming languages, such as Haskell, can make it easier and cheaper. For example, a new user who wrote a small relational DBMS in Haskell had this to say:

"WOW! I basically wrote this without testing just thinking about my program in terms of transformations between types. I wrote the test/example code and had almost no implementation errors in the code! The compiler/type-system is really really good at preventing you from making coding mistakes! I've never in my life had a block of code this big work on the first try. I am WAY impressed."

Even if you are not in a position to use Haskell in your programming projects, learning Haskell can make you a better programmer in any language.

"I learned Haskell a couple of years ago, having previously programmed in Python and (many) other languages. Recently, I've been using Python for a project (the choice being determined by both technical and non-technical issues), and find my Python programming style is now heavily influenced (for the better, I hope ;-) by my Haskell programming experience."

Graham Klyne

Haskell offers you:

  • Substantially increased programmer productivity (Ericsson measured an improvement factor of between 9 and 25 using Erlang, a functional programming language similar to Haskell, in one set of experiments on telephony software).
  • Shorter, clearer, and more maintainable code.
  • Fewer errors, higher reliability.
  • A smaller "semantic gap" between the programmer and the language.
  • Shorter lead times.

Haskell is a wide-spectrum language, suitable for a variety of applications. It is particularly suitable for programs which need to be highly modifiable and maintainable.

Much of a software product's life is spent in specification, design and maintenance, and not in programming. Functional languages are superb for writing specifications which can actually be executed (and hence tested and debugged). Such a specification then is the first prototype of the final program.

Functional programs are also relatively easy to maintain, because the code is shorter, clearer, and the rigorous control of side effects eliminates a huge class of unforeseen interactions.

Criticism

Haskell’s main technical weakness compared to popular, mainstream languages is probably the lack of a comprehensible cost model. Essentially, laziness makes it difficult to reason about when computation happens, and it can result in serious space leaks. While GHC can produce very efficient code, convincing it to do so in cases where that isn’t the default behavior is a dark art with few real masters.

There are some other things that are easy in many other languages but difficult in Haskell. For example, purity makes it slightly painful to discover and propagate run-time configuration information. In most languages it’s easy to read a configuration file at startup and store the result in a global variable, but in Haskell that requires dirty tricks.

Haskell has some other weaknesses compared to other academic/research languages. For example, its module system (if you can even call it that) is clearly inferior to Standard ML’s and OCaml’s module systems. Its compile-time meta-programming facility, Template Haskell, is occasionally useful, but it’s a poor substitute for a real, state-of-the art macro system. And of course, there are many things that some languages can do but others can’t. For example, if you want to prove your programs correct, Haskell’s type system, even with recent extensions in that direction, won’t let you prove as much as Coq or Agda—but that’s asking a language to do something that it wasn’t designed for, so I don’t really consider it a valid criticism.

From a theoretical perspective, some people have complained that call-by-need makes Haskell harder to reason about. It’s true that Haskell’s function space is a bit messier what you get in a language that’s both pure and total, but I don’t buy that it’s worse than your standard impure, call-by-value language—it’s just different.

Finally, Haskell does suffer some social weaknesses by being weird and researchy. Hiring large numbers of Haskell programmers is going to be difficult (though the ones you do find are likely to be very good). Because it’s so different from the languages that most people know, it presents a potentially steep learning curve. And of course, the community, while helpful and prodigious, is tiny compared to more popular languages. The variety and quality of libraries available on Hackage is impressive given the number of Haskell programmers out there, but it cannot compete with Java for mindshare. Finally, because Haskell is still very research-oriented, it changes quickly and sometimes unpredictably[34].

References

Cite error: Invalid <references> tag; parameter "group" is allowed only.

Use <references />, or <references group="..." />
  1. Template:Cite mailing list
  2. 2.00 2.01 2.02 2.03 2.04 2.05 2.06 2.07 2.08 2.09 2.10 2.11 2.12 Template:Harvnb
  3. Norell, Ulf (2008). "Dependently Typed Programming in Agda" (PDF). Gothenburg: Chalmers University. Retrieved 9 February 2012. 
  4. Template:Cite journal
  5. 5.0 5.1 Template:Cite journal
  6. Meijer, Erik (1 October 2009). "C9 Lectures: Dr. Erik Meijer&nbsp;– Functional Programming Fundamentals, Chapter 1 of 13". Channel 9. Microsoft. Retrieved 9 February 2012. 
  7. Template:Cite news
  8. Hickey, Rich. "Clojure Bookshelf". Listmania!. Amazon.com. Retrieved 9 February 2012. 
  9. Template:Cite news
  10. "Declarative programming in Escher" (PDF). Retrieved 2015-10-07. 
  11. Template:Cite book
  12. Wechsung, Ingo. "The Frege Programming Language" (PDF). Retrieved 26 February 2014. 
  13. "Facebook Introduces 'Hack,' the Programming Language of the Future". WIRED. 20 March 2014. 
  14. "Idris, a dependently typed language". Retrieved 2014-10-26. 
  15. "LiveScript Inspiration". Retrieved 2014-02-04. 
  16. "Glossary of Terms and Jargon". Perl Foundation Perl 6 Wiki. The Perl Foundation. Retrieved 9 February 2012. 
  17. Kuchling, A. M. "Functional Programming HOWTO". Python v2.7.2 documentation. Python Software Foundation. Retrieved 9 February 2012. 
  18. "The Rust Reference: Appendix: Influences". Retrieved 2016-02-03. 
  19. Fogus, Michael (6 August 2010). "MartinOdersky take(5) toList". Send More Paramedics. Retrieved 9 February 2012. 
  20. Lattner, Chris (2014-06-03). "Chris Lattner's Homepage". Chris Lattner. Retrieved 2014-06-03. The Swift language is the product of tireless effort from a team of language experts, documentation gurus, compiler optimization ninjas, and an incredibly important internal dogfooding group who provided feedback to help refine and battle-test ideas. Of course, it also greatly benefited from the experiences hard-won by many other languages in the field, drawing ideas from Objective-C, Rust, Haskell, Ruby, Python, C#, CLU, and far too many others to list. 
  21. "Timber/History". Retrieved 2015-10-07. 
  22. 22.0 22.1 22.2 22.3 Peyton Jones, Simon, ed. (2003). Haskell 98 Language and Libraries: The Revised Report. Cambridge University Press. ISBN 0521826144.
  23. Hudak, Paul; Hughes, John; Peyton Jones, Simon; Wadler, Philip (2007). "A History of Haskell: Being Lazy with Class" (PDF). Proceedings of the third ACM SIGPLAN conference on History of programming languages (HOPL III): 12–1–55. doi:10.1145/1238844.1238856. ISBN 978-1-59593-766-7.
  24. "Haskell Wiki: Implementations"
  25. [1]
  26. C. Ryder and S. Thompson (2005). "Porting HaRe to the GHC API"
  27. Hudak, Paul; Hughes, John; Peyton Jones, Simon; Wadler, Philip (2007). "A History of Haskell: Being Lazy with Class" (PDF). Proceedings of the third ACM SIGPLAN conference on History of programming languages (HOPL III): 12–1–55. doi:10.1145/1238844.1238856. ISBN 978-1-59593-766-7.
  28. "the Haskell Cabal"
  29. "Linspire/Freespire Core OS Team and Haskell"
  30. [xmonad.org]
  31. 31.0 31.1 31.2 31.3 A formal proof of functional correctness was completed in 2009. Klein, Gerwin; Elphinstone, Kevin; Heiser, Gernot; Andronick, June; Cock, David; Derrin, Philip; Elkaduwe, Dhammika; Engelhardt, Kai; Kolanski, Rafal; Norrish, Michael; Sewell, Thomas; Tuch, Harvey; Winwood, Simon (October 2009). "seL4: Formal verification of an OS kernel" (PDF). 22nd ACM Symposium on Operating System Principles. Big Sky, MT, USA.
  32. – Haskell web frameworks
  33. "Snap Framework"
  34. "What are the main weaknesses of Haskell as a programming language?"