8

How good is 'pure' functional programming for basic routine implementations, e.g. list sorting, string matching etc.?

It's common to implement such basic functions within the base interpreter of any functional language, which means that they will be written in an imperative language (c/c++). Although there are many exceptions..

At least, I wish to ask: How difficult is it to emulate imperative style while coding in 'pure' functional language?

Bubba88
  • 1,910
  • 20
  • 44
  • You're asking how difficult it is to emulate one style while writing in another? – ShreevatsaR Oct 11 '09 at 05:04
  • 3
    The assumption that a functional language will be implemented using an imperative one is suspect. OCaml is written in OCaml, and the most popular implementation of Haskell (GHC) is written in Haskell. – Chuck Oct 11 '09 at 07:00
  • @ShreevatsaR: Maybe I should rephrase, but it's what I'm asking. How difficult is it to write imperative programs while coding in pure functional language without special constructs like 'progn', 'do'... For example, It's a known trick that functional programs can emulate 'imperative' state with the use of closures. That's what I was asking about. – Bubba88 Oct 11 '09 at 07:32
  • The idea that functional and imperative are opposites needs to be dispelled. Haskell is purely functional, and it's also makes a very nice imperative programming language. – Apocalisp Oct 11 '09 at 17:09

6 Answers6

7

1) Good by what standard? What properties do you desire?

List sorting? Easy. Let's do Quicksort in Haskell:

sort [] = []
sort (x:xs) = sort (filter (< x) xs) ++ [x] ++ sort (filter (>= x) xs)

This code has the advantage of being extremely easy to understand. If the list is empty, it's sorted. Otherwise, call the first element x, find elements less than x and sort them, find elements greater than x and sort those. Then concatenate the sorted lists with x in the middle. Try making that look comprehensible in C++.

Of course, Mergesort is much faster for sorting linked lists, but the code is also 6 times longer.

2) It's extremely easy to implement imperative style while staying purely functional. The essence of imperative style is sequencing of actions. Actions are sequenced in a pure setting by using monads. The essence of monads is the binding function:

(Monad m) => (>>=) :: m a -> (a -> m b) -> m b

This function exists in C++, and it's called ;.

A sequence of actions in Haskell, for example, is written thusly:

putStrLn "What's your name?" >>=
  const (getLine >>= \name -> putStrLn ("Hello, " ++ name))

Some syntax sugar is available to make this look more imperative (but note that this is the exact same code):

do {
  putStrLn "What's your name?";
  name <- getLine;
  putStrLn ("Hello, " ++ name);
}
Apocalisp
  • 34,834
  • 8
  • 106
  • 155
  • 1
    I think for that quicksort, you wanted `filter` rather than `find`. For `sort [4, 1, 7, 0]`, the first `find` will return `Just 1` whereas `filter` would have returned `[1, 0]`. – Chuck Oct 11 '09 at 05:33
  • Your quick sort implementation is incorrect- Couldn't match expected type `[a]' against inferred type `Maybe a1'. – artagnon Oct 11 '09 at 05:56
  • Sorry, Artagnon. s/find/filter/g – Apocalisp Oct 11 '09 at 06:14
  • Good answer, but the essence of imperative programming is not about sequential execution of program, but more about manipulating state. Anyway, your `quicksort` example is just fine. – Bubba88 Oct 11 '09 at 07:49
  • Bubba88, imperative programming is about "do this, then do that". It's about imperatives. It just so happens that you can't "do" anything interesting without sequencing across some kind of state. – Apocalisp Oct 11 '09 at 15:46
  • `do { x <- [1,2]; y <- ['a','b']; return (x,y); }` -- This imperative program yields `[(1,'a'),(1,'b'),(2,'a'),(2,'b')]`. It's also a pure function. – Apocalisp Oct 11 '09 at 15:56
7

How good is 'pure' functional programming for basic routine implementations, e.g. list sorting, string matching etc.?

Very. I'll do your problems in Haskell, and I'll be slightly verbose about it. My aim is not to convince you that the problem can be done in 5 characters (it probably can in J!), but rather to give you an idea of the constructs.

import Data.List -- for `sort`
stdlistsorter :: (Ord a) => [a] -> [a]
stdlistsorter list = sort list

Sorting a list using the sort function from Data.List

import Data.List -- for `delete`
selectionsort :: (Ord a) => [a] -> [a]
selectionsort [] = []
selectionsort list = minimum list : (selectionsort . delete (minimum list) $ list)

Selection sort implementation.

quicksort :: (Ord a) => [a] -> [a]  
quicksort [] = []  
quicksort (x:xs) =   
    let smallerSorted = quicksort [a | a <- xs, a <= x]  
        biggerSorted = quicksort [a | a <- xs, a > x]
    in  smallerSorted ++ [x] ++ biggerSorted  

Quick sort implementation.

import Data.List -- for `isInfixOf`
stdstringmatch :: (Eq a) => [a] -> [a] -> Bool
stdstringmatch list1 list2 = list1 `isInfixOf` list2

String matching using isInfixOf function from Data.list

It's common to implement such basic functions within the base interpreter of any functional language, which means that they will be written in an imperative language (c/c++). Although there are many exceptions..

Depends. Some functions are more naturally expressed imperatively. However, I hope I have convinced you that some algorithms are also expressed naturally in a functional way.

At least, I wish to ask: How difficult is it to emulate imperative style while coding in 'pure' functional language?

It depends on how hard you find Monads in Haskell. Personally, I find it quite difficult to grasp.

artagnon
  • 3,609
  • 3
  • 23
  • 26
  • 1
    Yes. `minimum`, `delete`, and `filter` are all purely functional. – artagnon Oct 11 '09 at 08:13
  • About monads: see http://stackoverflow.com/questions/2366/can-anyone-explain-monads especially http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html . It is not necessary to understand what monads are *in general* to start using them, just understand specific monads you need — someday they will all click together and it will be apparent they are the "same", but until then it's not necessary :-) – ShreevatsaR Oct 11 '09 at 16:25
1

Nearly all functional programming languages have some construct to allow for imperative coding (like do in Haskell). There are many problem domains that can't be solved with "pure" functional programming. One of those is network protocols, for example where you need a series of commands in the right order. And such things don't lend themselves well to pure functional programming.

I have to agree with Lothar, though, that list sorting and string matching are not really examples you need to solve imperatively. There are well-known algorithms for such things and they can be implemented efficiently in functional languages already.

Community
  • 1
  • 1
Joey
  • 344,408
  • 85
  • 689
  • 683
  • I understand. I didn't want to mention the cases where the 'state' and the 'imperativeness' are needed by definition (like your example with networking protocols); just basic computational tasks, where the aim is to compute the function. So, current proposal is that we can easily write a pure functional algorithm for such things? – Bubba88 Oct 08 '09 at 06:18
  • You can, but you could write it (almost) purely imperative if you're inclined to do. My example simply highlighted something where imperative style is *absolutely needed* to make it work properly. Nothing prevents you from using the very same mechanisms for other things. – Joey Oct 08 '09 at 08:20
1

I think that 'algorithms' (e.g. method bodies and basic data structures) are where functional programming is best. Assuming nothing completely IO/state-dependent, functional programming excels are authoring algorithms and data structures, often resulting in shorter/simpler/cleaner code than you'd get with an imperative solution. (Don't emulate imperative style, FP style is better for most of these kinds of tasks.)

You want imperative stuff sometimes to deal with IO or low-level performance, and you want OOP for partitioning the high-level design and architecture of a large program, but "in the small" where you write most of your code, FP is a win.

See also

How does functional programming affect the structure of your code?

Brian
  • 117,631
  • 17
  • 236
  • 300
  • The article and the example in it weren't quite persuasive to me, but that's my opinion. Thanx for providing the reference, anyway. – Bubba88 Oct 08 '09 at 07:15
0

It works pretty well the other way round emulating functional with imperative style.

Remember that the internal of an interpreter or VM ware so close to metal and performance critical that you should even consider going to assember level and count the the clock cycles for each instruction (like Smalltalk Dophin is just doing it and the results are impressive). CPU's are imperative.

But there is no problem to do all the basic algorithm implementation - the one you mention are NOT low level - they are basics.

Lothar
  • 12,537
  • 6
  • 72
  • 121
0

I don't know about list sorting, but you'd be hard pressed to bootstrapp a language without some kind of string matching in the compiler or runtime. So you need that routine to create the language. As there isn't a great deal of point writing the same code twice, when you create the library for matching strings within the language, you call the code written earlier. The degree to which this happens in successive releases will depend on how self hosting the language is, but unless that's a strong design goal there won't be any reason to change it.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
  • Yes, i realize the need for many built-in functions; but my actual question was: do they all need to be written in C/C++ (which is imperative)? Sorry for correcting. – Bubba88 Oct 08 '09 at 09:19
  • No, you could write them in assembler, or anything else that the platform already supports. – Pete Kirkham Oct 08 '09 at 09:35