Reputation: 111
I tried to make a very short code, because we have a reglementation that favors the shortest code.
We have to create a function that turns a list into a new list of ascending and descending lists in the same order: For example. [1,6,2,1,7,3,2,8,4]
, becomes [[1,6],[2,1],[7],[3,2],[8],[4]]
So i tried to do the following:
func :: Ord a => [a] -> [[a]]
func xs = f1 d [a]
f1 [] ys = [c]
f1 xs ys | a >= b = d `f1` a:ys
| otherwise = c: d `f2` [a]
f2 [] ys = [c]
f2 xs ys | a < b = d `f2` a:ys
| otherwise = c : d `f1` [a]
where a = head xs
b = head ys
c = reverse ys
d = tail xs
But i get
parse error on input '='
on the line "b = head ys"
.
I thought it is possible to define multiple functions in the where block?
Other indentations created errors like a lot of
not in scope 'a'
not in scope 'b'
not in scope 'c'
not in scope 'd'
or
parse error on input 'b'
I have to make it that way to save some tokens/ have shorter code.
Upvotes: 2
Views: 168
Reputation: 32455
Your error messages are because you're mixing tabs and spaces. It's best to just use spaces.
Now, if you're writing
a = head xs
b = head ys
c = reverse ys
d = tail xs
then
xs = (a:ds)
ys = (b:es)
Let's rewrite your function with pattern matching:
func :: Ord a => [a] -> [[a]]
func [] = []
func (a:ds) = f1 ds [a]
f1 [] ys = [reverse ys]
f1 (a:ds) (b:es) | a >= b = ds `f1` (a:b:es)
| otherwise = reverse (b:es): ds `f2` [a]
f2 [] ys = [reverse ys]
f2 (a:ds) (b:es) | a < b = ds `f2` (a:b:es)
| otherwise = reverse (b:es) : ds `f1` [a]
I know this is longer, but bear with me. f1
is really the same as f2
, but with the comparison changed. Let's get a function no
to negate a comparison, so that (no (>=)) x y = not (x >= y)
:
no cmp x y = not (cmp x y)
In fact, we can write this as
no = ((not.).)
r = reverse
func' (a:ds) = f (>=) ds [a]
f :: Ord a => (a -> a -> Bool) -> [a] -> [a] -> [[a]]
f _ [] ys = [r ys]
f cp (a:ds) ys@(b:es) | cp a b = f cp ds (a:ys)
| True = r ys : f (no cp) ds [a]
Now that is shorter.
Upvotes: 0
Reputation: 68152
You have a more fundamental problem than indentation: a where
block is local to a single function case. You're trying to use your where
block to provide bindings (e.g. a
, b
, c
, d
) to a whole bunch of functions. This won't work.
To clarify, this correctly indented code won't work:
foo :: Int -> Int
foo 0 = a
foo 1 = b
where a = 2
b = 3
You'll get an error like Not in scope: `a'
. This is because the where
only extends over the foo 1
case; it doesn't even go to the foo 0
case, much less any other function.
Your code, on the other hand, seems to expect the where
block to work for all your functions. To have bindings that can be seen by different functions, you have to put them at the same level of scope as the functions themselves.
Also, Haskell indentation is a little finnicky. You really should avoid tabs; it also really helps to have an editor that understands Haskell properly. I've found Emacs is very good here--I never have to worry about Haskell indentation with Emacs.
Emacs might have a bit of a learning curve (you should do the tutorial), but I think it's well worth it. You'll also have to install the Haskell mode. If you get the newest version of Emacs, you should be able to do this using the package manager.
Upvotes: 2
Reputation: 183878
That's how it looks to the compiler:
func :: Ord a => [a] -> [[a]]
func xs = f1 d [a]
f1 [] ys = [c]
f1 xs ys | a >= b = d `f1` a:ys
| otherwise = c: d `f2` [a]
f2 [] ys = [c]
f2 xs ys | a < b = d `f2` a:ys
| otherwise = c : d `f1` [a]
where a = head xs
b = head ys
c = reverse ys
d = tail xs
So for the compiler, the lines in the where clause after the first look like continuations of that line, and of course you can't have multiple =
without an intervening semicolon on one line.
You should never mix tabs and spaces (you shouldn't ever use tabs, actually). And if you use tabs, configure your editor to interpret them as eight spaces.
And, the where
clause only scopes over the last equation, so there are no a, b, c, d
in scope in the first four equations for func
.
Upvotes: 2