Reputation: 196
I'm really quite new to Haskell and I need to return a function that "has modified" the inputted function.
I guess you cant copy and modify the original function (based on some condition) so you have to implement own behaviour directly and then call the original function?
This is my approach:
switchFirstEgg eggCarton = if eggCarton 1 == 0
then switchedCarton where switchedCarton position = if position == 1 then 2 else eggCarton position
else if eggCarton 1 == 1
then switchedCarton where switchedCarton position = if position == 1 then 0 else eggCarton position
else if eggCarton 1 == 2
then switchedCarton where switchedCarton position = if position == 1 then 1 else eggCarton position
else switchedCarton where switchedCarton position = eggCarton position
The error I get from the GHCI is
haskell/eggcartons.hs:42:54: parse error on input ‘where’
which points to the first word after the first where
.
(For reference: I also tried to set more brackets here http://pastebin.com/2wTqAqpm and I tried doing it with guards http://pastebin.com/RVm28Y7n, but that's only making it worse without thouroughly understanding that? At least guards worked for me here http://pastebin.com/uQeFwLU5)
I searched for returning functions in Haskell but I only got a few random info that I used with the where
things I have done.
Is my concept right? Is it only a minor mistake?
Any help on further reading regarding the syntax of returning functions is also much appreciated!
Upvotes: 1
Views: 409
Reputation: 120711
First let's make this somewhat readable...
switchFirstEgg ec
= if ec 1 == 0
then sc where sc pos = if pos == 1
then 2
else ec pos
else if ec 1 == 1
then sc where sc pos = if pos == 1
then 0
else ec pos
else if ec 1 == 2
then sc where sc pos = if position == 1
then 1
else ec pos
else sc where sc pos = ec pos
Now. where
can only be used once per definition, i.e. after you wrote switchFirstEgg _ = ...
you can follow a where
which is valid for everything after that =
. Or, you could more locally use a where after one of those definitions of sc
. But you can't stick it anywhere in the middle of your code, like in an if
branch.
The very similar let
construct does allow this, so the easiest translation of what you attempted would be
switchFirstEgg ec
= if ec 1 == 0
then let sc pos = if pos == 1 then 2
else ec pos
in sc
else if ec 1 == 1
then let sc pos = if pos == 1 then 0
else ec pos
in sc
else if ec 1 == 2
then let sc pos = if pos == 1 then 1
else ec pos
in sc
else let sc pos = ec pos
in sc
but that's clunky. You don't really need to define sc
with a name if it's used only once, immediately after the definition. That's a clear application for lambdas:
switchFirstEgg ec
= if ec 1 == 0
then \pos -> if pos == 1 then 2
else ec pos
else if ec 1 == 1
then \pos -> if pos == 1 then 0
else ec pos
else if ec 1 == 2
then \pos -> if pos == 1 then 1
else ec pos
else \pos -> ec pos
Better, but this chain of if
is obviously better expressed as a single collection of case
clauses.
switchFirstEgg ec = case ec 1 of
0 -> \pos -> if pos == 1 then 2
else ec pos
1 -> \pos -> if pos == 1 then 0
else ec pos
2 -> \pos -> if pos == 1 then 1
else ec pos
_ -> \pos -> ec pos
At this point it becomes clear that the pos
bindings are pretty uniform, so we can just move them all one level up:
switchFirstEgg ec pos = case ec 1 of
0 -> if pos == 1 then 2
else ec pos
1 -> if pos == 1 then 0
else ec pos
2 -> if pos == 1 then 1
else ec pos
_ -> ec pos
There we have if
s immediately following pattern matches. This is now a perfect fit for guards:
switchFirstEgg ec pos = case ec 1 of
0 | pos == 1 -> 2
1 | pos == 1 -> 0
2 | pos == 1 -> 1
_ -> ec pos
Alternatively, you can just match immediately on pos
, before even considering ec 1
:
switchFirstEgg ec 1 = case ec 1 of
0 -> 2
1 -> 0
2 -> 1
n -> n
switchFirstEgg ec pos = ec pos
Upvotes: 6
Reputation: 1447
See if this does what you want:
switchFirstEgg eggCarton =
switchedCarton
where switchedCarton = case (eggCarton 1) of
0 -> \position -> if position == 1
then 2
else eggCarton position
1 -> \position -> if position == 1
then 0
else eggCarton position
2 -> \position -> if position == 1
then 1
else eggCarton position
_ -> \position -> eggCarton position
You can only have one where
clause in a function definition (although function definitions within where
clauses can have their own where clauses).
Upvotes: 3