5 ms·
achieving anything practical using purely functional code remains extremely difficult ... Excel is pretty much a functional language (though it is a little dis
by wisty 16y ago
achieving anything practical using purely functional code remains extremely difficult ...
Excel is pretty much a functional language (though it is a little disabled), and people do amazing things in it.
The problem isn't that functional languages are hard. They are a bit different, but good code is often fairly functional anyway. The problem is that most of the community seems to be obsessed with showing that functional languages are both better, and more difficult, than mere procedural languages.
Take monads. The only way to "get" monads is to realize that they are just sections of the program that are imperative. But most Haskell programmers introduce them in the most incredibly obscure double-talk, just to avoid admitting that Haskell needs the ability to do imperative things in order to be useful.
- naradaellis 16y agoPerhaps the reason that Haskellers don't describe monads as "just sections of the program that are imperative" is because that statement is _not_ true. A monad is a very nice container abstraction - period. The IO part of Haskell just happens to leverage monads. One of the benefits of which is an explicit marking of impure methods in the type signature, but there are others. Monads are used in plenty of purely functional parts of Haskell. Disclosure: been programming Haskell for only a few months now, so someone pull me up if I'm wrong. However, I have used a lot of monads so far (and they're not hard, its just a higher, more convenient level of abstraction). edit: to address your post further. I honestly don't think that the community is the reason that Haskell isn't taking off. If you were to gather stats on the points at which would-be Haskellers give up, I think most people would leave 1) when they can't grok the syntax easily or 2) when they can't get tools or libraries going easily (it was a problem for me) and long before they get to the point of visiting the news groups and start running up against academic-type people.
- tkahn6 16y agoCan you give an example of where monads are not used to interact with stateful things? That would be helpful to me.
- jamii 16y agoPFP uses monads to represent probability distributions. http://web.engr.oregonstate.edu/~erwig/pfp/ http://web.engr.oregonstate.edu/~erwig/pfp/
- naradaellis 16y agoI don't know how familiar you are with Haskell... but anyway: Say you're working with the Maybe type, which is often used to represent operations that might fail, such as a map lookup, for example. data Maybe a = Just a | Nothing We're using two functions defined like so (feeling unimaginative at the moment, forgive me): x :: String -> Maybe String y :: String -> Maybe String We want to use them together. Someone who's not familiar with monads might write something like this: myFunction text = case x text of (Just newText) -> y n Nothing -> Nothing (If x works and returns a value, put that value into the y function. If x didn't work, just return Nothing) It works fine, but imagine you had 3 functions that returned Maybes, it would get tiresome and messy nesting all those case statements endlessly. [...] case x text of Just newText -> case y newText of [...] Not being satisfied with boilerplate, lets make an operation that will simplify this a bit: bind :: Maybe a -> (a -> Maybe b) -> Maybe b bind (Just x) f = f x bind Nothing _ = Nothing now we can define myFunction like so: myFunction text = (x text) `bind` y if we want to add another operation: myFunction text = (x text) `bind` y `bind` z Congratulations you've mostly made a monad. Bind is one of the monad operators (>>=), the other operators are extremely trivial to implement for the Maybe type. This is why we say a monad is just a container with some handy operators. Maybe is the container, and bind is a way to chain together operations (without explicitly taking the value out of the container) so the operators themselves don't have to know anything about the nature of what they're dealing with. I won't bang on anymore, this is a longer, better written tutorial[1] in the same vein as this short summary. [1]: http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
- tkahn6 16y agoI appreciate that. I am actually familiar with Haskell and the Maybe monad. Are there use cases for Maybe where you're not interacting with some sort of IO?
- jrockway 16y agoTake monads. The only way to "get" monads is to realize that they are just sections of the program that are imperative. Not really. Monadic function composition is just like regular composition, except that the programmer is given the ability to make "f of g of x" do something more than just pipe the result of g(x) into f. This can look like imperative programming, but it's still purely functional. If you're willing to call monads Kleisli arrows instead, then you can even the same syntax to chain monadic computations as "regular" computations. For example, write a function to add one to a number, then multiply by 4: f :: Num a => a -> a f = (*4) . (+1) That's a normal function, with the normal function composition operator. Now write a function to increment the state, in a stateful computation, by a number: inc :: Int -> State Int () inc x = put . (arr (+x)) . get Even though State is a monad or Kleisli arrow, you can treat the stateful computation as regular function composition, because it is just composition. There is no imperative programming anywhere to be seen. Although operating on some hidden state feels imperative, it's not. (Under the covers, it is a bit different than what you might be used to. Each stateful function is really a function from its arguments to another function from the current state to the result. We compose the "result" functions into one big function from state to result. This involves a bit of plumbing, but the actual implementation is only two lines of code. And it makes for a very useful abstraction in many cases. But I digress...) Monads are just a way to make similar things, chaining computations with an arbitrary combinator, look similar in your code. We did it with State above, and there are lots of other things that work similarly. Computations that can return zero or more results, computations that can fail, computations that operate on transactional memory, etc. We use "Monad" (or "Arrow") to provide the programmer with a common syntax for interacting with each. That's all a monad is. (IO is weird, and it is a monad, but it could also be an applicative functor, or comonad, or arrow, or a lazy list, or. Don't extrapolate your knowledge or fear of the IO monad onto monads in general.)
- bguthrie 16y agoI have no idea what a Kleisli arrow is, and a simple Google search points me right back in the direction of the HaskellWiki. They may be a perfectly simple concept, but if they are, then the term is not in widespread use. One of the major problems with explaining monads is that programmers who understand them frequently attempt to explain them by using terms even less well-understood than "monad". You get points for precision, but none for evangelism. It is of no help or use to those who do not understand monads that they could also be an applicative functor, or comonad, or whatever. You may be perfectly correct, but for someone who is not already part of your community, and conversant in its terms, it does not particularly help.
- ww520 16y agoIt's interesting to see Wisty's post and the replies immediately prove his point. BTW I like Haskell.
- BMeph 16y agoI disagree. His point is not merely that Haskell advocates cannot clearly explain simple interfaces like Monad (let's be honest here; this is more about Haskell folks being too researchy, and not being better skilled in the dog-and-pony-show environment of "practical" marketing), but that the lack of skill in clear explanation is due to a reluctance to admit that "Haskell needs the ability to do imperative things in order to be useful". The thing to "get" about Monads are that they are a means to describe imperative things going on, in a way that blends in with not necessarily imperative things. Which is part of why it's so tough to explain them - we're all talking past each other regarding what "the point" of using Monads are. The point to them in Haskell is mainly twofold: 1) Haskell users can use a Monad to describe net access, DB access, file access, and other "once done, the results are out of your control" effects in the same way as describing using (Writer) computations that keep a log of what's being done, (Error) exceptions, (Reader) environment variables, (List) functions with multiple - or no - results, and more. It's really easy...and kind of mind-blowingly complex, all at the same time.