Haskell multiply index

  • A+
Category:Languages

If I wanted to returns a list whose elements are equal to the corresponding element of the input list multiplied by its location in the list, I could do something like the following:

ML :: [Int] -> [Int] ML [] = [] ML (x:xs) =  x * x-1 : ML xs  

But the corresponding list I got when I entered [6,3,5,1] gives the result of [35,8,24,0]
Is there a similar way I could get [0,3,10,3]

 


Your code, as written (assuming the function name is actually a valid function name like ml) was parsed as:

ml :: [Int] -> [Int] ml [] = [] ml (x:xs) = ((x * x)-1) : (ml xs) 

This is because (*) has higher fixity(precedence) than (+), which again has higher fixity than (:), and function application ml xs has the highest fixity.
That is you are changing each element to its square, and subtracting 1.

Now what you actually want is some way to know the index of the element.
This can be achieved by using an extra argument in the recursion.

ml :: Int -> [Int] -> [Int] ml _ [] = [] ml i (x:xs) = x*i : ml (i+1) xs 

But then notice that our function's signature changed, we are now accepting an extra Int parameter, and we are expecting the user to call as with ml 0 someList, but we don't want to rely on the user passing valid data, and we want the user to just pass the list. So we can rename this function to some other name, say ml_internal and have ml be the correct code

ml :: [Int] -> [Int] ml xs = ml_internal 0 xs  ml_internal :: Int -> [Int] -> [Int] ml_internal _ [] = [] ml_internal i (x:xs) = x*i : ml_internal (i+1) xs 

Now we don't want to expose ml_internal, we could do this by putting this code in a module and only exporting ml, but there's no reason to do that. We also might not want ml_internal to be available to other functions in the same module. So what we can do is put ml_internal in a where clause for ml:

ml :: [Int] -> [Int] ml xs = ml_internal 0 xs   where     ml_internal :: Int -> [Int] -> [Int]     ml_internal _ [] = []     ml_internal i (x:xs) = x*i : ml_internal (i+1) xs 

Now we can also omit ml_internal's type signature, since it can be inferred, and in some cases the compiler can't handle the explicit signature correctly without a language extension called ScopedTypeVariables enabled.
We can also rename ml_internal to go, which is a widely used name for such constructs, to get to the following code for ml:

ml :: [Int] -> [Int] ml xs = go 0 xs   where     go _ [] = []     go i (x:xs) = x*i : go (i+1) xs 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: