Create a new list with a difference from each value

I'm trying to make a function that does the following: it gets a list, for example [1,4,2,3]

, and returns a list [3,2,1]

.

Because 1 - 4 = 3

(abs value), 4 - 2 = 2

and 2 - 3 = 1

.

I thought this piece of code would do it except for the abs value.

function :: [a] -> [a]
function [] = []
function (x:xs) = [x - head(xs)] ++ function xs

      

but this is giving me errors and I haven't found any solution.

Respectfully,

EDIT:

Thanks guys, you learned a lot today. Indeed I am a beginner, I have a university course that gives me prologue, haskell, scala, python, aspectj and metaprogramming. Thus, we have for each program 2 lessons with 2 hours, and then some time to do some exercises.

Next Monday I have an exam and zipwith etc ... we have to write our own function. But thanks for the nice tutorial explained, learned so much. This is a working solution:

function :: Num a => [a] -> [a]
function (x:y:xs) = [abs(x - y)] ++ function (y:xs)
function _ = []

      

+3


source to share


5 answers


If you are still interested in a recursive solution .

No instance for (Num a)
  arising from a use of `-'
In the expression: x - head (xs)
In the first argument of `(++)', namely `[x - head (xs)]'
In the expression: [x - head (xs)] ++ function xs

      

The operator (-) :: Num a => a -> a -> a

requires its arguments to be Num

. Therefore, we can fix it with function :: Num a => [a] -> [a]

.

We now have another problem:

> function [1,4,2,3]
[-3,2,-1,*** Exception: Prelude.head: empty list

      

Therefore, we have to handle some cases:

function :: Num a => [a] -> [a]
function [] = []
function [_] = []
function (x:xs) = x - head xs : function xs

      

But this is still not what we actually expected:

> function [1,4,2,3]
[-3,2,-1]

      

So, we have to add a function abs

:

function :: Num a => [a] -> [a]
function [] = []
function [_] = []
function (x:xs) = abs ( x - head xs ) : function xs

      

Done



> function [1,4,2,3]
[3,2,1]

      


Also, you can do it very simply and with more readable code.

How can you tell the difference between the two lists? zipWith

looks really useful. For example:

> zipWith (-) [1,2,3,4] [1,1,1]
[0,1,2]

      

So the idea is the zipWith (-)

original list and tail

.

> let x = [1,2,3,4]
> zipWith (-) x (tail x)
[-1,-1,-1]

      

And you may like yours function

:

function :: Num a => [a] -> [a]
function x = map abs $ zipWith (-) x (tail x)

      

Done



> function [1,4,2,3]
[3,2,1]

      

+5


source


In general, it is a good idea to tell us what errors you get, rather than expecting us to inject your code and run it ourselves. But here's what I see right away:



  • function :: [a] -> [a]

    means it function

    works for any type of list. But you will say later x - head(xs)

    . Here we have x :: a

    and head(xs) :: a

    . You would expect the subtraction operator to accept any two values ​​as long as they are of the same type.

    But (-) :: Num a => a -> a -> a

    ; one type is not enough for these two values, this type must implement Num

    typeclass (which also provides addition, multiplication, absolute value, and several other functions).

    Fix: Replace type signature function :: Num a => [a] -> [a]

    .

  • The code should now compile, but when you run it, you will get an error with the title of an empty list.

    Let's walk through what happens when we run function [4]

    * :

    • The first equation has function []

      on the left, but [4]

      doesn't match []

      , so skip it.

    • The second equation has function (x:xs)

      the left side. [4]

      matches (x:xs)

      by giving us x = 4

      and xs = []

      , so we will continue with this equation and estimate [4 - head([])] ++ function []

      .

    • This includes a score [4 - head([])]

      that includes a score 4 - head([])

      that includes a score head([])

      , which is an error because an empty list has no head.

    Fix: Think about what we want here. When we match a pattern to a list, it's not enough to know that it has a head ( x

    ). We also need to know that it has a second item ( y

    ). Therefore, we replace the equations by

    function (x:y:xs) = [x - y] ++ function (y:xs)
    function _        = []
    
          

    _

    matches any value at all. The first equation is the same when the list contains two or more items, so the second equation will clean up the list of empty lists and single items.

    * : I am not saying that it really scores in that order. But this is clean code (and final data), so it doesn't matter what order we evaluate.

  • You really don't want to do explicit recursion yourself if you can help it, you want to use a higher-order function instead; partly because it means you don't have to write the recursion yourself (and risk getting it wrong), and partly because you can often dodge pattern matching with a higher-order function (avoiding, perhaps, that it's wrong ). So take the advice of sclv: use zipWith

    and drop 1

    (and ignore Daniel Fischer's this one time: you don't want to get used to having to worry about how safe to use head

    , for granted, when drop 1 []

    bringing []

    is useful).

    Other advantages of using a higher-order function instead of pattern matching and explicit recursion:

    • only one equation is required
    • easier to identify what the code is doing
    • more efficient code
+5


source


take a look at zipWith

and drop 1

...

+4


source


Dmitri's solution could be improved

function :: Num a => [a] -> [a]
function x = map abs $ zipWith (-) x (tail x)

      

We really want to get the result (-)

and "feed" it immediately to the function abs

, avoiding the extra step map

. Doing it with a lambda expression is pretty ugly:

function :: Num a => [a] -> [a]
function x = zipWith (\a b -> abs(a - b)) x (tail x)

      

The magic sauce is called "functional composition" and uses an operator (.)

. (f . g) x

means simple f(g x)

but cool that we can glue our functions together and provide an argument later . Using this we get:

function :: Num a => [a] -> [a]
function x = zipWith ((abs.).(-)) x (tail x)

      

(Corrected after is7s' note, this is a bit tricky since we have to deal with two arguments here)

0


source


I don't know if this suits all your needs, but it worked in ghci:

let func a = [ abs( fst x - snd x ) | x <- zip a (tail a)]

      

Performance: func [1,4,2,3]

Returns: [3,2,1]

As expected.

I'm still getting started, but I also want to help when I find out.

0


source







All Articles