recursion over tuples list in haskell - haskell

Is there a recursion way to do somethings like below?
updateOs2 :: [(Rotor, Int)] -> [(Rotor, Int)]
updateOs2 [(a,x),(b,y),(c,z)]
| x == 25 && y == 25 && z == 25 = [(a,0),(b,0),(c,0)]
| x == 25 && y == 25 = [(a,0),(b,0),(c,z+1)]
| x == 25 = [(a,0),(b,y+1),(c,z)]
| otherwise = [(a,x+1),(b,y),(c,z)]
I have tried to do recursion, but quite confused. Because once the last element z is passed the list comes to empty, can not go back to x anymore.

I think this should work
updateOs2 [] = []
updateOs2 ((a,x):xs)
| x == 25 = (a,0): (updateOs2 xs)
| otherwise = (a,x+1):xs

Related

Write a function that lists numbers from n to m by k number of steps. If the step size is negative list them in descending order

Implement the interval2 :: Int -> Int -> Int -> [Int] function,that lists numbers from the first parameter to the third parameter, the stepping's size is the second parameter. Using [n..m], [n,k..m] or [n..] is prohibited.
For example:
interval2 1 1 10 == [1,2..10]
interval2 10 1 0 == [10,11..0]
interval2 10 (-1) 0 == [10,9..0]
interval2 1 2 10 == [1,3..10]
interval2 10 2 0 == [10,12..0]
interval2 0 (-2) (-10) == [0,(-2)..(-10)]
interval2 1 (-1) 10 == [1,0..10]
interval2 0 (-10) (-1000) == [0,(-10)..(-1000)]
So far, I've managed to write some cases, but they didn't do the job very well.
interval2 x y z | x < z && y > 0 = [x] ++ interval2 (x+y) y z
| x < z && y < 0 = [x] ++ interval2 (x-y) y z
| x > z && y > 0 = [x] ++ interval2 (x-y) y z
| x > z && y < 0 = [x] ++ interval2 (x+y) y z
| x == z || x > z = [z]
There are basically two cases when you should emit a new value:
if x <= z and y > 0; and
if x >= z and y < 0.
In both cases that means the list contains x as first element and should recurse on the interval with x+y. In case none of these conditions are not met, then we have reached the end of the list.
This thus means that the function looks like:
interval2 x y z
| (x <= z && y > 0) || (x >= z && y < 0) = …
| otherwise = …
where I leave implementing … as an exercise.
Naming is important. When learning, naming is very important.
What is x? What is y? What is z? Are all of them the same, conceptually?
No, as the exercise describes it, it is
interval2 :: Int -> Int -> Int -> [Int]
interval2 from stepSize to =
this already gets you half way there towards the solution. Yes it does.
Or actually, you have a contradiction. According to the title of your post, it is
interval2b :: Int -> Int -> Int -> [Int]
interval2b from numSteps to =
But in any case, solving the first one first, you seem to get lost in the multitude of tests. Instead of doing all of them in one function, why not do a test to decide which of several functions to use to do the job; then write each of those functions being already able to assume certain things, namely those which we've tested for:
interval2 from stepSize to
| stepSize > 0 = increasing from
| stepSize < 0 = decreasing from
| otherwise = []
where
increasing from
| from
and now it is easy to see which test to perform here, isn't it?
> to = []
| otherwise = from : increasing ....
decreasing from
| from
and similarly here.
.........
..................
I hope this helps you manage this complexity so you'll be able to complete this code yourself.

Nested guards on Haskell [duplicate]

I'm writing a program on the classification of musical intervals. The conceptual structure is quite complicated and I would represent it as clearly as possible. The first few lines of code are a small extract that works properly. The second are the pseudo-code that would meet my needs of conciseness.
interval pt1 pt2
| gd == 0 && sd < (-2) = ("unison",show (abs sd) ++ "d")
| gd == 0 && sd == (-2) = ("unison","dd")
| gd == 0 && sd == (-1) = ("unison","d")
| gd == 0 && sd == 0 = ("unison","P")
| gd == 0 && sd == 1 = ("unison","A")
| gd == 0 && sd == 2 = ("unison","AA")
| gd == 0 && sd > 2 = ("unison",show sd ++ "A")
| gd == 1 && sd < (-1) = ("second",show (abs sd) ++ "d")
| gd == 1 && sd == (-1) = ("second","dd")
| gd == 1 && sd == 0 = ("second","d")
| gd == 1 && sd == 1 = ("second","m")
| gd == 1 && sd == 2 = ("second","M")
| gd == 1 && sd == 3 = ("second","A")
| gd == 1 && sd == 4 = ("second","AA")
| gd == 1 && sd > 4 = ("second",show (abs sd) ++ "A")
where
(bn1,acc1,oct1) = parsePitch pt1
(bn2,acc2,oct2) = parsePitch pt2
direction = signum sd
sd = displacementInSemitonesOfPitches pt1 pt2
gd = abs $ displacementBetweenTwoBaseNotes direction bn1 bn2
Is there a programming structure that could simplify the code like the following pseudo-code does?
interval pt1 pt2
| gd == 0 | sd < (-2) = ("unison",show (abs sd) ++ "d")
| sd == (-2) = ("unison","dd")
| sd == (-1) = ("unison","d")
| sd == 0 = ("unison","P")
| sd == 1 = ("unison","A")
| sd == 2 = ("unison","AA")
| sd > 2 = ("unison",show sd ++ "A")
| gd == 1 | sd < (-1) = ("second",show (abs sd) ++ "d")
| sd == (-1) = ("second","dd")
| sd == 0 = ("second","d")
| sd == 1 = ("second","m")
| sd == 2 = ("second","M")
| sd == 3 = ("second","A")
| sd == 4 = ("second","AA")
| sd > 4 = ("second",show (abs sd) ++ "A")
| gd == 2 | sd ... = ...
| sd ... = ...
...
| mod gd 7 == 1 | mod sd 12 == ...
| mod sd 12 == ...
...
| otherwise = ...
where
(bn1,acc1,oct1) = parsePitch pt1
(bn2,acc2,oct2) = parsePitch pt2
direction = signum sd
sd = displacementInSemitonesOfPitches pt1 pt2
gd = abs $ displacementBetweenTwoBaseNotes direction bn1 bn2
Thank you in advance for your suggestions.
Let me use a shorter example than the posted one:
original :: Int -> Int
original n
| n < 10 && n > 7 = 1 -- matches 8,9
| n < 12 && n > 5 = 2 -- matches 6,7,10,11
| n < 12 && n > 3 = 3 -- matches 4,5
| n < 13 && n > 0 = 4 -- matches 1,2,3,12
The code runs in GHCi as follows:
> map original [1..12]
[4,4,4,3,3,2,2,1,1,2,2,4]
Our aim is to "group" together the two branches requiring with n < 12, factoring this condition out. (This is not a huge gain in the original toy example, but it could be in more complex cases.)
We could naively think of splitting the code in two nested cases:
wrong1 :: Int -> Int
wrong1 n = case () of
_ | n < 10 && n > 7 -> 1
| n < 12 -> case () of
_ | n > 5 -> 2
| n > 3 -> 3
| n < 13 && n > 0 -> 4
Or, equivalently, using the MultiWayIf extension:
wrong2 :: Int -> Int
wrong2 n = if
| n < 10 && n > 7 -> 1
| n < 12 -> if | n > 5 -> 2
| n > 3 -> 3
| n < 13 && n > 0 -> 4
This however, leads to surprises:
> map wrong1 [1..12]
*** Exception: Non-exhaustive patterns in case
> map wrong2 [1..12]
*** Exception: Non-exhaustive guards in multi-way if
The issue is that when n is 1, the n < 12 branch is taken, the inner case is evaluated, and then no branch there considers 1. The original code simply tries the next branch, which handles it. However, wrong1,wrong2 are not backtracking to the outer case.
Please note that this is not a problem when you know that the outer case has non-overlapping conditions. In the code posted by the OP, this seems to be the case, so the wrong1,wrong2 approaches would work there (as shown by Jefffrey).
However, what about the general case, where there might be overlaps? Fortunately, Haskell is lazy, so it's easy to roll our own control structures. For this, we can exploit the Maybe monad as follows:
correct :: Int -> Int
correct n = fromJust $ msum
[ guard (n < 10 && n > 7) >> return 1
, guard (n < 12) >> msum
[ guard (n > 5) >> return 2
, guard (n > 3) >> return 3 ]
, guard (n < 13 && n > 0) >> return 4 ]
It is a bit more verbose, but not by much. Writing code in this style is easier than it might look: a simple multiway conditional is written as
foo n = fromJust $ msum
[ guard boolean1 >> return value1
, guard boolean2 >> return value2
, ...
]
and, if you want a "nested" case, just replace any of the return value with a msum [ ... ].
Doing this ensures that we get the wanted backtracking. Indeed:
> map correct [1..12]
[4,4,4,3,3,2,2,1,1,2,2,4]
The trick here is that when a guard fails, it generates a Nothing value. The library function msum simply selects the first non-Nothing value in the list. So, even if every element in the inner list is Nothing, the outer msum will consider the next item in the outer list -- backtracking, as wanted.
I'd recommend to group each nested condition in a function:
interval :: _ -> _ -> (String, String)
interval pt1 pt2
| gd == 0 = doSomethingA pt1 pt2
| gd == 1 = doSomethingB pt1 pt2
| gd == 2 = doSomethingC pt1 pt2
...
and then, for example:
doSomethingA :: _ -> _ -> (String, String)
doSomethingA pt1 pt2
| sd < (-2) = ("unison",show (abs sd) ++ "d")
| sd == (-2) = ("unison","dd")
| sd == (-1) = ("unison","d")
| sd == 0 = ("unison","P")
| sd == 1 = ("unison","A")
| sd == 2 = ("unison","AA")
| sd > 2 = ("unison",show sd ++ "A")
where sd = displacementInSemitonesOfPitches pt1 pt2
Alternatively you can use the MultiWayIf language extension:
interval pt1 pt2 =
if | gd == 0 -> if | sd < (-2) -> ("unison",show (abs sd) ++ "d")
| sd == (-2) -> ("unison","dd")
| sd == (-1) -> ("unison","d")
...
| gd == 1 -> if | sd < (-1) -> ("second",show (abs sd) ++ "d")
| sd == (-1) -> ("second","dd")
| sd == 0 -> ("second","d")
...
This isn't really an answer to the title question, but adresses your particular application. Similar approaches will work for many other problems where you might wish for such sub-guards.
First I'd recommend you start out less “stringly typed”:
interval' :: PitchSpec -> PitchSpec -> Interval
data Interval = Unison PureQuality
| Second IntvQuality
| Third IntvQuality
| Fourth PureQuality
| ...
data IntvQuality = Major | Minor | OtherQual IntvDistortion
type PureQuality = Maybe IntvDistortion
data IntvDistortion = Augm Int | Dimin Int -- should actually be Nat rather than Int
And regardless of that, your particular task can be done much more elegantly by “computing” the values, rather than comparing with a bunch of
hard-coded cases. Basically, what you need is this:
type RDegDiatonic = Int
type RDeg12edo = Rational -- we need quarter-tones for neutral thirds etc., which aren't in 12-edo tuning
courseInterval :: RDegDiatonic -> (Interval, RDeg12edo)
courseInterval 0 = ( Unison undefined, 0 )
courseInterval 1 = ( Second undefined, 1.5 )
courseInterval 2 = ( Third undefined, 3.5 )
courseInterval 3 = ( Fourth undefined, 5 )
...
You can then “fill in” those undefined interval qualities by comparing the 12edo-size with the one you've given, using1
class IntervalQuality q where
qualityFrom12edoDiff :: RDeg12edo -> q
instance IntervalQuality PureQuality where
qualityFrom12edoDiff n = case round n of
0 -> Nothing
n' | n'>0 -> Augm n
| otherwise -> Dimin n'
instance IntervalQuality IntvQuality where
qualityFrom12edoDiff n | n > 1 = OtherQual . Augm $ floor n
| n < -1 = OtherQual . Dimin $ ceil n
| n > 0 = Major
| otherwise = Minor
With that, you can implement your function thus:
interval pt1 pt2 = case gd of
0 -> Unison . qualityFrom12edoDiff $ sd - 0
1 -> Second . qualityFrom12edoDiff $ sd - 1.5
2 -> Third . qualityFrom12edoDiff $ sd - 3.5
3 -> Fourth . qualityFrom12edoDiff $ sd - 5
...
1You don't really need a type class here, I could as well have defined two diffently-named functions for pure and other intervals.

Implementing recursion in Haskell without input variable

So im still very new to programming and I'm struggling a lot with the Syntax of Haskell. I kind of know what I want to implement but im not really sure how to do it so I came here to ask.
So what I have is a "pile" of Numbers in no particular order that are defined by 3 different functions. An example for this would be:
lowestnumber = 4
highestnumber 5 = True
highestnumber _ = False
above 4 = 11
above 11 = 18
above 18 = 2
above 2 = 3
above 3 = 5
above 5 = error "highest Number"
above _ = error "Not part of the pile"
Now for one I want to write a function that checks if a certain number is part of this pile and a different function "sum' = " that sums up all the elements of the list without an input variable. First I solved these problems by defining a list and using listcommands in order to sum up and see if something is "elem" of that list but I am supposed to solve it without using lists.
So I have ideas of how to solve this but I have no idea of how to actually write it without receiving countless errors.
Some examples of what I've tried for the check function:
check x = if above x /= error "Not part of the stack" || lowestnumber == x then True else False
I also tried the checks with "_" like this but it wouldn't work either:
check x if above x == _ || lowestnumber == x then True else False
My idea for the sum function was this:
sum' = lowestnumber + above lowestnumber + above (above lowestnumber) + above (above (above lowestnumber))
or also something like
sum' = lowestnumber + (above sum')
Which I understand woul
and so on but I did not figure out how I could implement this using recursion which is apparently the way to go.
Well hopefully this question isnt too stupid! I hope you can help me :)
Edit: Ok, so these are the solutions to my 3 function-problems
sumup' a b
|highestNumber a == True = a+b
|otherwise = sumup' (above a) (a+b)
sumup = sumup' lowestNumber 0
check' a b
|a == b = True
|True == highestNumber a && a==b = True
|True == highestNumber a && a/=b = False
|check' (above a) (b) == True = True
|otherwise = False
check b = check' (lowestNumber) (b)
above' :: Integer -> Integer -> Bool
above' x y
| check x == False = False
| check y == False = False
| highestNumber y == True = False
| highestNumber x == True = True
| x==y = True
| above' x (above y) == True = True
| otherwise = False
If you want to do this without lists, keep a running total, and use recursion.
If you're at the highestnumber, just add that to your current total and stop,
otherwise, add the number to your total total + n and move on to the next one above n:
add n total |highestnumber n = total + n
|otherwise = add (above n) (total + n)
Then you can do
answer = add lowestnumber 0
You're supposed to do this without lists, well that's sad because it would be very much the idiomatic solution.
The nextmost idiomatic one would be something generic that is able to traverse your pile there. You basically want a fold over the numbers:
foldlMyPile :: (a -> Int -> a) -> a -> {- Pile -> -} a
foldlMyPile f = go lowestNumber
where go n accum
| highestNumber n = result
| otherwise = go (above n) result
where result = f accum n
Once you've got this, you can use it to define sum, element etc. much like they are defined on lists:
sumPile :: Int
sumPile = foldlMyPile (+) 0
elemPile :: Int -> Bool
elemPile n = foldlMyPile $ \alreadyFound n' -> alreadyFound || n==n'
Various higher order functions in Haskell capture various recursion (and corecursion†) patterns, like iterate, foldr, unfoldr, etc.
Here we can use until :: (a -> Bool) -> (a -> a) -> a -> a, where until p f x yields the result of iteratively applying f until p holds, starting with x:
sumPile = snd $
until (highestnumber . fst)
(\(a,b)->(above a, b + above a))
(lowestnumber, lowestnumber)
also,
inThePile p = p==until (\n-> highestnumber n || n==p) above lowestnumber
† basically, recursion with accumulator, building its result on the way forward from the starting case, whereas regular recursion builds its result on the way back from the base case.
About your three new functions.
sumup' a b
| highestNumber a == True = a+b
| otherwise = sumup' (above a) (a+b)
sumup = sumup' lowestNumber 0 -- sum up all numbers in the pile
this is almost exactly as in AndrewC'c answer. it is good, except == Temp is totally superfluous, not needed. sumup' also would usually be made an internal function, moved into a where clause. As such, it doesn't have to have a descriptive name. Some use (Scheme-inspired?) loop, some go (since do is a reserved syntax keyword). I personally started to use just g recently:
sumup = g lowestNumber 0 -- sum up all numbers in the pile
where
g n tot -- short, descriptive/suggestive var names
| highestNumber n = n + tot
| otherwise = g (above n) (n + tot)
check b = check' lowestNumber b -- don't need any parens here
check' a b
|a == b = True
|True == highestNumber a && a==b = True -- `True ==` not needed
|True == highestNumber a && a/=b = False -- `True ==` not needed
|check' (above a) (b) == True = True -- `== True` not needed
|otherwise = False
This usually would be written as
check' a b = (a == b) ||
(highestNumber a && a==b) ||
( not (highestNumber a && a/=b)
&& check' (above a) b )
in the 2nd test, if a==b were true, it'd already worked in the 1st rule, so we can assume that a/=b henceforth. so 2nd test is always false; and we get
check' a b = (a == b) ||
(not (highestNumber a) && check' (above a) b)
which is rather OK looking. It can be also written with guards again, as
check' a b | (a == b) = True
| highestNumber a = False
| otherwise = check' (above a) b
or, using short suggestive variable names, and with swapped order of arguments, for consistency,
check' n i | highestNumber i = i == n
| otherwise = i == n || check' n (above i)
which is rather similar to how the first, sumup code is structured.
Now, the third function. First of all, it can easily be defined in terms of check' too, just starting with the given low number instead of the lowest one:
higher top low = check low && not (highestNumber low)
&& check' top (above low)
("higher" is a more distinctive name, yes?). Your version:
higher :: Integer -> Integer -> Bool
higher x y
| check x == False = False -- not(check x == False) -- ==
| check y == False = False -- check x == True -- ==
| highestNumber y == True = False -- check x
| highestNumber x == True = True
| x==y = True
| higher x (above y) == True = True
| otherwise = False
again, simplifying,
higher x y = check x && check y
&& not (highestNumber y)
&& ( highestNumber x
|| x==y -- really?
|| higher x (above y) ) -- too strong
so this one seems buggy.
First I solved these problems by defining a list and using
listcommands in order to sum up and see if something is "elem" of that
list but I am supposed to solve it without using lists.
You can solve this by expanding elem, like so:
x `elem` [1,2,3]
is the same as
x == 1 || x == 2 || x == 3
And while your at it
sum' = 4 + 11 + 18 + 2 + 4 + 5
You could also construct a list of all your elements with something like
elements = takeUntil highestnumber (iterate above lowestnumber)
takeUntil p xs = foldr (\x r -> if p x then [x] else x:r) [] xs
This is the only way I see you can write your check and sum' functions without using constants.
we can't use takeWhile (not . highestnumber) because we'll miss the highest number. So, takeUntil must be defined this way to include the breaking element in its output.

How to check that I'm dealing with a list in Haskell?

I'm learning Haskell, and I'm trying to add preconditions to a (trivial, as an exercise) element_at function (code below). I've created a "helper" elem_at_r because otherwise, len x fails at some point (when x is a 'literal' rather than a list? - I still have trouble parsing ghci's error messages). elem_at now has all the error checking, and elem_at_r does the work. In elem_at, I'd like to add a check that x is indeed a list (and not a 'literal'). How can I do that?
len x = sum [ 1 | a <- x]
elem_at_r x n | n == 0 = head x
| 0 < n = elem_at_r (tail x) (n-1)
elem_at x n | x == [] = error "Need non-empty list"
| len x <= n = error "n too large " ++ show (len x)
| n < 0 = error "Need positive n"
| otherwise = elem_at_r x n
Thanks!
Frank
Due to Haskell's type system, elem_at can only take a list as its first argument (x); if you try to pass a non-list, GHC will detect this and give an error at compile time (or interpretation time in GHCi). I don't know why len would "fail"; could you post the error message that GHCi gives you?
It looks like you were getting errors because of the "x == []" line. The code below pattern matches for that condition and adds a few signatures. Otherwise it is the same. Hope it helps.
len x = sum [ 1 | a <- x]
elem_at_r :: [a] -> Int -> a
elem_at_r x n | n == 0 = head x
| 0 < n = elem_at_r (tail x) (n-1)
elem_at :: [a] -> Int -> a
elem_at [] _ = error "Need non-empty list"
elem_at x n | len x <= n = error ("n too large " ++ show (len x))
| n < 0 = error "Need positive n"
| otherwise = elem_at_r x n
You could also make your helper functions part of this function using a where clause:
elem_at :: [a] -> Int -> a
elem_at [] _ = error "Need non-empty list"
elem_at x n | len x <= n = error ("n too large " ++ show (len x))
| n < 0 = error "Need positive n"
| otherwise = elem_at_r x n
where
len :: [a] -> Int
len x = sum [ 1 | a <- x]
elem_at_r :: [a] -> Int -> a
elem_at_r x n | n == 0 = head x
| 0 < n = elem_at_r (tail x) (n-1)

Detecting cyclic behaviour in Haskell

I am doing yet another projecteuler question in Haskell, where I must find if the sum of the factorials of each digit in a number is equal to the original number. If not repeat the process until the original number is reached. The next part is to find the number of starting numbers below 1 million that have 60 non-repeating units. I got this far:
prob74 = length [ x | x <- [1..999999], 60 == ((length $ chain74 x)-1)]
factorial n = product [1..n]
factC x = sum $ map factorial (decToList x)
chain74 x | x == 0 = []
| x == 1 = [1]
| x /= factC x = x : chain74 (factC x)
But what I don't know how to do is to get it to stop once the value for x has become cyclic. How would I go about stopping chain74 when it gets back to the original number?
When you walk through the list that might contain a cycle your function needs to keep track of the already seen elements to be able to check for repetitions. Every new element is compared against the already seen elements. If the new element has already been seen, the cycle is complete, if it hasn't been seen the next element is inspected.
So this calculates the length of the non-cyclic part of a list:
uniqlength :: (Eq a) => [a] -> Int
uniqlength l = uniqlength_ l []
where uniqlength_ [] ls = length ls
uniqlength_ (x:xs) ls
| x `elem` ls = length ls
| otherwise = uniqlength_ xs (x:ls)
(Performance might be better when using a set instead of a list, but I haven't tried that.)
What about passing another argument (y for example) to the chain74 in the list comprehension.
Morning fail so EDIT:
[.. ((length $ chain74 x x False)-1)]
chain74 x y not_first | x == y && not_first = replace_with_stop_value_:-)
| x == 0 = []
| x == 1 = [1]
| x == 2 = [2]
| x /= factC x = x : chain74 (factC x) y True
I implemented a cycle-detection algorithm in Haskell on my blog. It should work for you, but there might be a more clever approach for this particular problem:
http://coder.bsimmons.name/blog/2009/04/cycle-detection/
Just change the return type from String to Bool.
EDIT: Here is a modified version of the algorithm I posted about:
cycling :: (Show a, Eq a) => Int -> [a] -> Bool
cycling k [] = False --not cycling
cycling k (a:as) = find 0 a 1 2 as
where find _ _ c _ [] = False
find i x c p (x':xs)
| c > k = False -- no cycles after k elements
| x == x' = True -- found a cycle
| c == p = find c x' (c+1) (p*2) xs
| otherwise = find i x (c+1) p xs
You can remove the 'k' if you know your list will either cycle or terminate soon.
EDIT2: You could change the following function to look something like:
prob74 = length [ x | x <- [1..999999], let chain = chain74 x, not$ cycling 999 chain, 60 == ((length chain)-1)]
Quite a fun problem. I've come up with a corecursive function that returns the list of the "factorial chains" for every number, stopping as soon as they would repeat themselves:
chains = [] : let f x = x : takeWhile (x /=) (chains !! factC x) in (map f [1..])
Giving:
take 4 chains == [[],[1],[2],[3,6,720,5043,151,122,5,120,4,24,26,722,5044,169,363601,1454]]
map head $ filter ((== 60) . length) (take 10000 chains)
is
[1479,1497,1749,1794,1947,1974,4079,4097,4179,4197,4709,4719,4790,4791,4907,4917
,4970,4971,7049,7094,7149,7194,7409,7419,7490,7491,7904,7914,7940,7941,9047,9074
,9147,9174,9407,9417,9470,9471,9704,9714,9740,9741]
It works by calculating the "factC" of its position in the list, then references that position in itself. This would generate an infinite list of infinite lists (using lazy evaluation), but using takeWhile the inner lists only continue until the element occurs again or the list ends (meaning a deeper element in the corecursion has repeated itself).
If you just want to remove cycles from a list you can use:
decycle :: Eq a => [a] -> [a]
decycle = dc []
where
dc _ [] = []
dc xh (x : xs) = if elem x xh then [] else x : dc (x : xh) xs
decycle [1, 2, 3, 4, 5, 3, 2] == [1, 2, 3, 4, 5]

Resources