A brief introduction to Haskell, and why it matters
github.com
github.com
I'd take it as far as to say that, if you're a developer of any sort, you should learn at least some Haskell at some point. It does things in such a completely different way from more mainstream languages that the sheer mind-opening effect of learning it is worthwhile.
EDIT: Thank you for the responses, I have bookmarked the relevant github page and feel like my question has been well-answered :) Also, even more interested by Haskell than I was before.
Static types, possibly more purity (depending on the lisp you've been writing), pervasive laziness, slightly awkward (but usually unnecessary) macros.
Are there things in haskel that would make you recommend it over lisps?
When you just want some parts that can be fitted together to get you what you want, dynamic programming is tough to beat.
Consider, how many extensible editors (or other applications) have been written in Haskel? Or, really, any static language.
Contrast that with how far emacs has managed to come. And, among the lisps, elisp is not highly regarded.
For that matter, consider how far javascript has managed to take web programming.
Also... I was not meaning to make an argument to the quality of the languages. If anything, my argument is admittedly about the ecosystems garnered by the different types of languages.
We are the only engineering discipline where there are a significant number of people who actually think extensibility is more important than stability or robustness. Imagine a civil engineer pooh-poohing the stability of the bridge he's building, pointing instead to how easy it is to add additional lanes. Imagine a mechanical engineer decrying running a formal analysis of a new design for a car, saying "forget about that, look at how easily customers can plug in custom dashboard attachments!" This is lunacy, plain and simple.
I will not claim that extensibility is the be all end all attribute. I will claim that it is a valuable attribute. More so for some applications than others.
Similarly, I will make the same claim for formal checked programs. In some fields/industries, why wouldn't this be the norm?
So, if the claim is that static typing can make for a more completely specified application and that we should demand that for some fields. I agree.
If the claim is that static programming is superior to dynamic, I take issue.
I think this would benefit from a little more clarity about what you mean when you say "static programming" versus "dynamic programming" - I'm sure you don't mean "Dynamic Programming".
If you mean static types, then I think that they are a tremendous win wherever they apply, and I think that sufficiently sophisticated type systems exist that they can apply most places. Trying to express meaningful constraints in a brain dead type system is awkward and you wind up moving between over- and under-constraining yourself - though I've been surprised at what I can express in C (with zero runtime overhead) with a little creativity.
If "static programming" is taken to mean "compiled, with runtime compilation of additional code made difficult to impossible", which often correlates with "statically typed" in existing languages but is technologically orthogonal, then I agree that this kind of "static programming" is not uniformly superior.
If you have any examples that show how this is technically orthogonal, I'm all ears. Hence my request for examples of things that are as extensible as emacs.
And to be clear, my understanding is that ghc is actually fairly extensible. I would love if there were more examples. Preferably in more approachable domains than compilers.
No worries - as I said, I'd understood that didn't mean "dynamic programming".
"If you have any examples that show how this is technically orthogonal, I'm all ears. Hence my request for examples of things that are as extensible as emacs."
Well, Typed Racket would presumably be one example. More generally, as a theoretical proof, one could bundle the entire compiler into the runtime and link in arbitrary new code.
"And to be clear, my understanding is that ghc is actually fairly extensible. I would love if there were more examples. Preferably in more approachable domains than compilers."
I'm not aware of it being exceptionally easy to write plugins for GHC compared to other compilers - it has incorporated a lot of extensions to the Haskell language but that's not the same as a plugin ecosystem (which might itself exist - just "I'm not aware"). It certainly has a plugin interface, but so does GCC. As GHC it itself implemented in Haskell, a lot of pieces of it are also available as libraries.
ಠ_ಠ
Edited to add: Also, since you asked specifically about extensible editors: http://www.haskell.org/haskellwiki/Yi
Anyhow, you don't have to take an all-or-nothing approach. It's pretty common to write game engines in C++ and then use a dynamic language to provide game-specific scripting on top (e.g. World of Warcraft uses Lua for the UI, Civilization V uses Python for most of the non-engine stuff). Also, Photoshop has javascript builtin.
Take a look at skewer-mode for emacs sometime, and realize that is less than 1.5k lines of javascript and elisp.
I was also avoiding the approach of bundling in specially crafted hooks for extensions. If anything, that really just kind of makes my point. That for some things there is a highly perceived benefit to dynamic languages. (And yes, the converse is true.)
I can say that finally going through SICP has been borderline mind blowing. It is hilarious/sad/crazy to see how many hot topics today were covered in a bloody introduction textbook from the 90s.
Even casually skimming through the GetOpts implementation in Cabal should give you and idea of what I mean:
https://github.com/haskell/cabal/blob/master/Cabal/Distribut...
The biggest thing I notice is that type specifiers have comments next to them akin to variable names describing what they are for.
This worries me. Comments are just so awful compared to clear meaningful variable/function naming that propagate through the code when used. Does Haskell discourage and even prevent clear naming or am I missing something? It would be a tradeoff I couldn't accept.
It's also worth mentioning that the "-- ^ comment" syntax is so that Haddock, Haskell's automatic documentation generator, can display the comments in the HTML documentation. Example: http://hackage.haskell.org/package/Cabal-1.18.1.2/docs/Distr...
exp :: Double -> Double -> Double
You don't inherently know from the type which argument is the base and which is the exponent. Double is not a name that you have control over, so we write a comment for it that will automatically show up in the API documentation. They only get names in the implementation. exp base exponent = ...
But these names are for the programmer, not the API documentation. You actually want these names to be separate from what is shown in the API docs. Consider this function: map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
This code is very concise and easy to read. It is easy to read because the names are small and the important thing is the pattern, not the actual meaning of the names. This function is also extremely general, which means that there's not much use in names. Position in the function means more than a name. Here's what it would look at written with "clear" OO-style names: map :: (a -> b) -> [a] -> [b]
map function [] = []
map function (firstElement:restOfList) = function firstElement : map function restOfList
First of all, we see that sometimes we want to pattern match instead of using a name. GHC would actually give a warning with this code saying that the name "function" in the first case is never used. This is actually a very useful warning that has helped me catch bugs on multiple occasions. Secondly, the "clear" names here completely obscure our ability to understand the code. It's just too much noise. Now, I'm not trying to get into the whole naming debate here. The point I want to make is that there can be good reasons to not show the parameter names in the API documentation, which is why you'll see comments on type signatures for the purpose of auto-generated documentation.For map in particular what are you going to rename? You can name unbound parameters without a newtype:
map :: (input -> output) -> [input] -> [output]
might add a bit; map :: MapFunction a b -> [a] -> [b]
takes more away than it adds I think. Double exp(Double base, Double exponent)
while the Haskell syntax for types doesn't provide a place to write down names for arguments. Perhaps a nice fix would be to add Agda-style syntax for arrow-types, like exp :: (base : Double) -> (exponent : Double) -> Double
At some point we will want to add dependent types anyway. :)it's not that it's more declarative (tho that becomes a side effect), but that thinking about the type forces you to model your problem domain in a formal way, which brings to the forefront all of the problems that would otherwise have been hidden away as undeclared assumptions.
E.g. in java or C++, the states that a class can be in is often invalid, but is only enforced procedurally via programmer checks, where as in haskell, you often have to holistically model the problem as a type, and all values that the types can take up must be accounted for. Thus, you hit the edge cases right up front, instead of finding out later (as bugs).
EDIT: ...Did I just accidentally paraphrase what ESR used to say about Lisp?
Common Lisp encourages all sorts of theory derived ideas. The community favors good looking code. But functions that start with 'n' as in "No" and the ability to redefine symbols linked to atomic values are always there for chainsaw juggling foo.
#lang racket
is just a corner of the Racket ecosystem. If anything underpins it, it's the idea of teaching computer programming and computer science research. For elegance it #:extra-constructor-name for (struct...); contracts, units, modules, collections, objects, mixins and packages (two types); and two syntaxes for Regex.That's of course not to say that the Racketeer ethic doesn't favor elegant code. Only that language design is not ideologically bound to it.
Haskell being statically typed will outlaw a large-ish number of direct lispisms until you provide the compiler sufficient type-based justification that the operation is OK. For instance, new lisp->haskell programmers often want to make arbitrary nested lists
[[1,2,3],4,[[5,6],7]]
which is not well-typed so the compiler complains. Honestly, what you need is a different type than the strict Haskell list called a Rose Tree data Rose a = Leaf a | Branch [Rose a]
which tells the compiler that you explicitly want arbitrary nesting.---
Laziness
All of Haskell has default laziness and this means that your environment is fully tilted toward laziness. Generally this means that a thing called equational reasoning holds nicely and this forms a MAJOR component of your ability to reason about Haskell code. In particular, given any repeated substatement, you can "lift" it up with a let
... e ... e ... e ...
==
let x = e
in ... x ... x ... x ...
Lazy Racket gives this to you too, but having it everywhere is a new thing. You also are able to rely on control structures as combinators much more so that something like fold x c . map f . map g
is very common in Haskell since laziness will automatically fuse each step, while in (strict) Racket you'd want to manually fuse them together fold (c . f . g) x
reducing composability.---
Purity
You can get pretty close to pure in Racket, but Haskell takes this concept much further. Purity and laziness are a driving force which leads to the need for things like Monads... and strong types allow the boundaries of various semantic segments to be very sharp. As an example, the STM libraries in Haskell are remarkably nice due to a combination of strong types and purity. In particular, you tend to build up computations of types like
STM a, STM b, STM (a -> b -> c)
where the STM marks that these computations only make use of transactionally safe memory and are allowed to be re-run as many times as needed to ensure linearity. Then you use atomically :: STM a -> IO a
which "upgrades" STM to IO allowing now the entire set of side-effects by interpreting the STM computation as IO... and thus choosing to run and re-run it until it linearizes.---
In each of these cases, Racket, being the flexible language it is, has methods of nicely including the feature—typed racket, lazy racket, base racket without ambient state or io—but Haskell goes fully and confidently into these three choices and that subsequently leads to very interesting combination effects and a community and ecosystem designed in a particular, interesting style.
In other words, I believe that even if you're intimately familiar with each of those things in isolation, Haskell may be the first time you've ever seen them together... and that changes everything.
[ R 0 , [ R 1 , R 2 ] ]Second, expressivity and modularity. I find that Haskell programs tend to have two types of functions: very short functions (a few lines long at most) implementing the logic of one particular operation (heavily composed of other such functions), and long but extremely simple functions expressing high-level program flow. Good Haskell style encourages writing functions with the most general type they can work with, which results in many functions becoming very general, reusable helpers. As a result, I rarely find myself staring at a half-dozen functions at once trying to figure out what one does and how logic and state get threaded through all of them; each individual piece makes sense in isolation. That's also quite nice when trying to refactor a function.
Haskell is pure: there's no mutable values in the core language (though IORef's can be used for that), so you can be sure that a function does not call `set!` and all data structures are persistent and immutable unless mutability is specifically emulated.
Haskell uses some deeply abstract and powerful concepts like monads, arrows and functors that give a great insight into programming languages theory.
Haskell lacks Lisp-way macros but gets by surprisingly well with its type system magic, laziness + combinators can get you ~90% of macro power.
Haskell enables you to reason about code formally, making invariants (code properties that must be preserved during its execution) in your code explicit. This makes programs much more safer and predictable.
On the other hand, its core is very close to the lambda calculus (that Lisps are also so close to), so with Haskell you basically get the power of Lisp + a solid and powerful layer of type system that verifies your code + nice, clean and consistent syntax.
You can get 90% of the rest with Template Haskell, at the cost of some compile time and (arguably) some prettiness.
Haskell is lazy and always pure, so writing hybrid code takes great effort. This improves code quality by making the path of least effort the best one.
Whether writing pure functional code is the goal is an interesting debate, but Haskell is certainly the better language to learn that in.
That's a key point right there. If you are an OOP guy trying to learn FP, Scala makes it too easy to stick to what you already know. I find that Scala's OO features get in the way of learning functional programming, because like you said, it requires discipline to do things in a functional way. With Haskell, you don't have a choice.
How so? I was under the impression you had to explicitly go out of your way to break functional purity/ use mutable state in Clojure, just like Haskell.
Is it easier/harder/more-unwieldy to maintain functional purity in one of them over the other?
Do you mean nothing in the main Clojure distribution? Or nothing, period?
Don't get me wrong, I think so too, it's just that I've begun doubting myself. I've always thought it worthwhile to learn very different languages for the mind-opening effects of their paradigms. But it's become clearer to me that beyond the warm and fuzzy feeling of understanding ways to package and handle state in pure FP languages, I lack any specific evidence that learning Haskell helped my programming style or effectiveness in mainstream languages.
How would I go about finding such evidence?
To put it in a brutally reductive form: I looked at my C++ code before and after I learned Haskell and played with it a fair amount. I didn't see much difference, though maybe I didn't look at the right things?
> My pragmatic summary: A large fraction of the flaws in software development are due to programmers not fully understanding all the possible states their code may execute in. In a multithreaded environment, the lack of understanding and the resulting problems are greatly amplified, almost to the point of panic if you are paying attention. Programming in a functional style makes the state presented to your code explicit, which makes it much easier to reason about, and, in a completely pure system, makes thread race conditions impossible.
> I do believe that there is real value in pursuing functional programming, but it would be irresponsible to exhort everyone to abandon their C++ compilers and start coding in Lisp, Haskell, or, to be blunt, any other fringe language. To the eternal chagrin of language designers, there are plenty of externalities that can overwhelm the benefits of a language, and game development has more than most fields. We have cross platform issues, proprietary tool chains, certification gates, licensed technologies, and stringent performance requirements on top of the issues with legacy codebases and workforce availability that everyone faces.
> If you are in circumstances where you can undertake significant development work in a non-mainstream language, I’ll cheer you on, but be prepared to take some hits in the name of progress. For everyone else: No matter what language you work in, programming in a functional style provides benefits. You should do it whenever it is convenient, and you should think hard about the decision when it isn’t convenient.
-- John Carmack (http://www.altdevblogaday.com/2012/04/26/functional-programm...)
For example, garbage collection can be thought as a "big C function implemented as a library." C++'s smart pointers and templates can be thought as libraries, but that doesn't detract from their value as programming language features.
Your argument is a derivative of "in the end everything is glorified assembly."
So I go to Hoogle, and search for "[a] -> [b] -> [(a, b)]". First result is "zip".
Or I want to get only the things in a list that satisfy a predicate, but I'm suffering from nominal amnesia. I type in "(a -> Bool) -> [a] -> [a]" and Hoogle lets me know that I meant to write "filter".
[1] http://www.haskell.org/hoogle/?hoogle=%28a+-%3E+Bool%29+-%3E...
So, for example you can type: 'hello'. 'HELLO' and it finds you 'asUppercase' method of String object.
This is a very useful function of Squeak and I presume Pharo Smalltalk but I think users of it should have some awareness that it has limitations and not to simply assume that because a result is not found that it does not exist.
In short, find some tasks for which I would use Perl|Python|Ruby and solve them with Haskell.
If you're interested in learning the language, I suggest starting with Learn You a Haskell For Great Good[1] (first programming book I've ever considered to be a page-turner), then following it up with Real World Haskell[2] (going through that one now myself)
Of course parsing is something thats very important if you are making your own DSL. And this is another application where Haskell really shines. This is why the guys who do programming language research produce papers with code in Haskell. Its orders of magnitude easier to make your toy language for exploring evaluation order in Haskell than it is to do the same in Java.
Its easier to learn a language if you're building something you're interested in though. Personally, I learnt a lot of Haskell implementing a web app with Yesod[2].
Good luck.
[1] http://book.realworldhaskell.org/read/using-parsec.html [2] http://www.yesodweb.com/
Python, at least, has the PLY library, which makes parsing (IMO) easier than with Parsec.
Other languages, like OCaml, also make writing parsers very easy.
Haskell with Parsec might beat C with lex/yacc, but I don't think it's that great compared to what else is available.
I think my main contention was the "orders of magnitude" claim in the comment I replied to. Parsec is nice, but it's not "orders of magnitude" better than PLY or camlp4 or other parsing tools in other languages.
Whoever is maintaining my PLY mess now might get a handle on it faster than they could learn Haskell, but probably not by much.
I feel like I see a lot more cases where the research language is built as an extension of Haskell or its syntax tree is written up as a (G)ADT possibly with the derived `read' as the "parser" (but possibly just constructing and interpreting ASTs within a Haskell program).
Structural pattern matching is also a nice thing to have when writing interpreters.
Writing a DSL was my original motivation for learning Haskell beyond it being just a toy. About a day after I really got going on my parser I decided to abandon the idea of a DSL and just write it as a monad.
[1] http://book.realworldhaskell.org/ (free to read online)
[2] http://learnyouahaskell.com/ (free to read online)
In particular, for interacting with MySQL, check out the chapter on that in RWH [2], and for reading lines and operating on them, see [3].
However, you should start from the beginning, as those kind of operations (for better or worse), require a firm grounding in Haskell concepts like types, monads, etc.
[1]: http://book.realworldhaskell.org/read/
[2]: http://book.realworldhaskell.org/read/using-databases.html
But, if you're already a very experienced programmer, you can probably learn how to write practical programs in Haskell by just reading the IO chapter (http://book.realworldhaskell.org/read/io.html) and the Systems Programming chapter (http://book.realworldhaskell.org/read/systems-programming-in...) from RWH. These will help you understand how IO actually works in Haskell. The rest is just libraries and learning the language itself.
On a related note: I've found that starting with the main IO function is a good way to start writing any large program in Haskell. Most people I know who complain about Haskell being a mess in impure environments tend to write pure functions first, then build their IO functions on top of that, instead of the other way around. I'm not sure whether this applies for everyone, and of course this approach works well in domains that have little to do with IO (e.g. mathematical programming), but it's something to keep in mind.
Assuming we have
doSomething :: Maybe String -> IO ()
which turns some optional string into an action to perform, you could say: mapM_ (doSomething . listToMaybe . drop 2 . words) . lines =<< readFile filename
The IO action readFile produces a (lazy) String, lines chops it into a (lazy) list of Strings - on each of those we break it into columns, get rid of two of them, get Just the head if it exists (otherwise, Nothing), turn those into the actions we want with doSomething, and sequences those actions. The result is a new action."Also, how can I talk to MySql or Sqlite?"
And processing a logfile http://gaiustech.wordpress.com/2010/09/13/analyzing-logfiles...
http://rosettacode.org/wiki/CSV_data_manipulation#Haskell
(early Google search result for 'rosetta code csv')
edit: Looking at the python code, I would call the approach esoteric, but I guess that's just an opinion (I would use the csv module without giving any consideration to the quality of the structured file). So who knows how idiomatic the code is.
import Control.Monad (forM_)
import Data.List.Split (splitOn)
import Data.List (transpose)
import System.IO
main :: IO ()
main = do
withFile "file.file" ReadMode $ \handle ->
contents <- hGetContents handle
let clines = lines contents
ccols = transpose (map (splitOn ",") lines)
forM_ (ccols !! 3) $ \cell -> do
putStrLn cell
Then take a look at the following packages http://hackage.haskell.org/package/split
http://hackage.haskell.org/package/mysql-simple
http://hackage.haskell.org/package/sqlite-simple import Control.Monad (forM_)
import Data.List.Split (splitOn)
import Data.List (transpose)
import System.IO
main :: IO ()
main = do
withFile "tel.csv" ReadMode $ \handle -> do
contents <- hGetContents handle
let clines = lines contents
ccols = transpose (map (splitOn ",") clines)
forM_ (ccols !! 3) $ \cell -> do
putStrLn cell import Data.Char
changeThird (a:b:c:rest) = a : b : map toUpper c : rest
main = do
contents <- readFile "foo.txt"
let ls = lines contents
ws = map (changeThird . words) ls
writeFile "foo2.txt" (unlines $ map unwords ws)
But like others said, I think you're going to have a harder time if you try to learn Haskell by starting this way. Anyone learning Haskell will be coming in with no exposure to any other pure language, and that has big implications. There is a fundamental difference between the "contents <- readFile ..." line above and the next two lines that you have never encountered before in any other language. You'll probably have a pretty difficult time with it if you don't understand a little more about how the readFile function is different from the lines function and what that means for how you can use them. You can't just mindlessly copy examples from small day to day tasks like you can with other languages because Haskell is unlike any other language you know.Please don't read the above paragraph to mean that Haskell is not suitable for these kinds of small tasks. I actually think that Haskell makes a fantastic scripting language. I'm just saying that you can't learn it like you learn other scripting languages. You need to get a bigger understanding of what's going on otherwise you'll end up frustrated about why things don't work the way you expect.
All that being said, I still HIGHLY recommend learning Haskell.
For example, if you want to print the id and name of each user from a file in the /etc/passwd format:
-- display all users: ids and names from /etc/passwd
import Data.List.Split (splitOn)
eachLine :: (String -> String) -> (String -> String)
eachLine f = unlines . map f . lines
showUser :: String -> String
showUser line = fields !! 0 ++ "\t" ++ fields !! 4
where fields = splitOn ":" line
main = interact (eachLine showUser)
This can be run, like (assuming the program is saved in list-users.hs): $ runhaskell list-users.hs < /etc/passwd
I am very new to Haskell, and I am sure there are other, perhaps better ways to do this.If I was feeling fancy, that `unlines . map f . lines` looks like an isomorphism that we could do something awesome with the lens library. Anyone who knows it better care to show me how to do that?
Janrain (http://janrain.com/)
Standard Chartered Bank (https://www.sc.com/en/index.html)
Karamaan Group (http://karamaan.com/)
Silk (http://www.silk.co/)
Skedge.me (http://skedge.me/)
Soostone (http://www.soostone.com/)
Erudify (http://www.erudify.com/)
Facebook (http://www.haskellcast.com/episode/004-simon-marlow-on-paral...)
Whereabouts are you?
In addition to mightybyte's list there's also
Barclays Capital
Tsuru
http://functionaljobs.com/jobs/8684-platform-engineer-at-sig...
Disclaimer: I'm a cofounder of the company which spun-out Signal Vine.
Recently I tried to get into Haskell. I've installed EclipseFP and the first sessions looked nice. But when I started to use external cabal modules I always ran into serious trouble with versioning. Even recompilation doesn't help a lot because there is always a complaining module.
Do I something wrong? I am thankful for advice.
I hope this is a hierarchical solution so that I won't need to download the whole cabal stack for any new project.
http://yannesposito.com/Scratch/en/blog/Holy-Haskell-Starter...
http://haskell-news.blogspot.com/2008/01/top-10-most-popular...
Here's a GitHub search. Mostly libraries, but a few end-user programs:
https://github.com/search?p=1&q=language%3Ahaskell+stars%3A%...
I didn't realize Pandoc was written in Haskell. Darcs of course, and xmonad window manager are the ones that come to my mind.
"Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot."
Is that right? As Haskell seems to be far less intimidating to approach than Lisp, I may actually end up doing some. I fondly remember my junior level programming languages class and doing assignments in Standard ML. Haskell looks similar.
Out of curiosity, how difficult did you find this to complete?
http://www.amazon.com/Beginning-Haskell-A-Project-Based-Appr...
http://www.haskell.org/haskellwiki/Partial_application
I'm not sure if it's unique to Haskell, but it's such a great feature that I've wished for in other languages since learning about it. You can replicate it by manually writing curried functions, but having the language do that for you is incredibly useful.
main :: IO ()
main = putStr "Hello world!!"
A side-effect in the very first program. I'm disappointed!What are some good things to build when getting into a new language? Data structures? Chat server?
Erlang: much much easier to learn. Within a week I felt I could probably have built pretty much whatever I wanted. A few pitfalls, but it's predictable, and with very few difficult to understand parts. Also the OTP is almost CPAN-like in its ability to get you solving problems very quickly. HOWEVER: until the next time I need to build a telephony switch or any kind of massive message handler (chat application, messaging queue, WhatsApp competitor etc), I just have no use for it.
Haskell ... I had some basics in a week. After some months of dabbling here and there, I finally get Monads, but haven't done anything productive yet. I feel like I have become a significantly stronger developer in the other languages I use, have a much deeper understanding of some basics of CompSci, and have had a lot of fun. I think in another few months, it might start being my goto language for solving problems.
Research: generate ideas
Applied: deploy to thousands or millions of users
(not (comfortable everyone LISP-syntax))
(not (everyone comfortable LISP-syntax))
I'm nitpicking, of course... just taking the opportunity to think lispy.
I guess it's not getting enough uptake organically, so once more to HN for the throat-shoving.