Quick sort:
-- First variant:
qsort :: (Ord a) => [a] -> [a]
qsort [] = []
qsort (x:xs) = left x ++ [x] ++ right x
where left n = qsort [m | m <- xs, m <= n]
right n = qsort [m | m <- xs, m > n]
-- λ: qsort [10,2,5,3,1,6,7,4,2,3,4,8,9]
-- [1,2,2,3,3,4,4,5,6,7,8,9,10]
I see the left and right functions are almost identical. Therefore I want to rewrite it shorter... Something like that:
-- Second variant:
qsort' :: (Ord a) => [a] -> [a]
qsort' [] = []
qsort' (x:xs) = (srt <=) ++ [x] ++ (srt >)
where srt f = qsort' [m | m <- xs, m f x]
But I get errors when I try to load this into ghci:
λ: :load temp
[1 of 1] Compiling Main ( temp.hs, interpreted )
temp.hs:34:18:
Couldn't match expected type `[a]'
with actual type `(t0 -> [a]) -> Bool'
Relevant bindings include
srt :: forall t. t -> [a] (bound at temp.hs:35:9)
xs :: [a] (bound at temp.hs:34:11)
x :: a (bound at temp.hs:34:9)
qsort' :: [a] -> [a] (bound at temp.hs:33:1)
In the first argument of `(++)', namely `(srt <=)'
In the expression: (srt <=) ++ [x] ++ (srt >)
In an equation for qsort':
qsort' (x : xs)
= (srt <=) ++ [x] ++ (srt >)
where
srt f = qsort' [m | m <- xs, m f x]
temp.hs:34:37:
Couldn't match expected type `[a]'
with actual type `(t1 -> [a]) -> Bool'
Relevant bindings include
srt :: forall t. t -> [a] (bound at temp.hs:35:9)
xs :: [a] (bound at temp.hs:34:11)
x :: a (bound at temp.hs:34:9)
qsort' :: [a] -> [a] (bound at temp.hs:33:1)
In the second argument of `(++)', namely `(srt >)'
In the second argument of `(++)', namely `[x] ++ (srt >)'
In the expression: (srt <=) ++ [x] ++ (srt >)
temp.hs:35:38:
Could not deduce (a ~ (t -> a -> Bool))
from the context (Ord a)
bound by the type signature for qsort' :: Ord a => [a] -> [a]
at temp.hs:32:11-31
`a' is a rigid type variable bound by
the type signature for qsort' :: Ord a => [a] -> [a]
at temp.hs:32:11
Relevant bindings include
m :: a (bound at temp.hs:35:29)
f :: t (bound at temp.hs:35:13)
srt :: t -> [a] (bound at temp.hs:35:9)
xs :: [a] (bound at temp.hs:34:11)
x :: a (bound at temp.hs:34:9)
qsort' :: [a] -> [a] (bound at temp.hs:33:1)
The function `m' is applied to two arguments,
but its type `a' has none
In the expression: m f x
In a stmt of a list comprehension: m f x
Failed, modules loaded: none.
λ:
I read the error message, but I don't understand the reason still...
You shouldn't use f as infix. You can solve it by putting f in front and representing the functions between brackets (<=):
-- third variant:
qsort' :: (Ord a) => [a] -> [a]
qsort' [] = []
qsort' (x:xs) = (srt (<=)) ++ [x] ++ (srt (>))
where srt f = qsort' [m | m <- xs, f m x]
This is mainly because what you basically want to do is call f on m and x. Now default lambda-calculus always evaluates first the function that is listed to the left.
Haskell only provides some syntactical sugar for operators: when you write a+b, what you basically write is (+) a b (behind the curtains). This is what Haskell likes best, but the compiler thus offers some functionality for programmer's convenience. Since writing a*b+c*d is way easier than writing (+) ((*) a b) ((*) c d), but the second is actually how to write such things in lambda-calculus.
In order to see operators as functions, you write them between brackets, so to get the function-variant of <=, you write (<=).
EDIT
As @Jubobs argues, you can also use the infix, but thus requires you to use backticks:
-- fourth variant:
qsort' :: (Ord a) => [a] -> [a]
qsort' [] = []
qsort' (x:xs) = (srt (<=)) ++ [x] ++ (srt (>))
where srt f = qsort' [m | m <- xs, m `f` x]
The problem is mainly you need to pass your functions through f, and <= and > aren't functions, (<=) and (>) are. Technically speaking, the story is a bit more complicated, but I guess this will suffice when learning the basics.
By using backticks, Haskell reads:
x `f` y
as:
f x y
(note that this is not completely true since operators have also a priority: * binds tighter than +, but these are more the "details" of the process).
Putting brackets over an operator is kind of the opposite effect:
x o y
is
(o) x y
with o an operator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With