简体   繁体   中英

perform a function on first elements of list

In an attempt to write the Havel-Hakimi algorithm in Haskell, I wrote following function to subtract 1 from the first n elements of a list.

decrease_first :: Int -> [Int] -> [Int]
decrease_first 0 l = l
decrease_first n (x:xs) = (x-1):decrease_first (n-1) xs

This code works, but as I am trying to prepare for a Haskell-test and I was convinced this code is rather lame, I wanted to rewrite this function as follows:

decrease_first :: Int -> [Int] -> [Int]
decrease_first = map (subtract1) . take

I'm aware of the fact this does not do exactly the same, but I was just trying to understand partially applied functions etc. better and wanted to give this function a try. This turned out not to be the greatest of ideas, because I didn't get this compiled (type-definitions) and I am left with a massive mind-you-know-what, because next code does work, even though I considered it equivalent:

decrease_first n = map (subtract1) . take n 

and this code fails again:

decrease_first n l = map (subtract1) . take n l

Moreover I tried looking for some nice way to apply a function to the first elements of a list, but I couldn't find anything. The first way is probably the most efficient way to do it, but I was wondering whether there was some way to apply any function on the first elements of a list. My idea eventually was to do something like:

decrease_first n l = map (subtract 1) (take n l) ++ drop n l

It works like this, but it doesn't look as nice as I had it in mind. So if anyone could help me resolving my type-issue, I would be very grateful.

Thanks in advance

Your first point-free attempts don't work because . composes functions with one argument , while take takes two . What really happens is that code like

decrease_first = map (subtract1) . take

is equivalent to

decrease_first n = map (subtract1) (take n)

but now take n is not a list, hence a type error arises.

Instead, in

decrease_first n l = map (subtract1) . take n l

we have that take nl is a list, not a function. Here you need application, not function composition eg

decrease_first n l = map (subtract1) $ take n l

Your last attempt looks fine to me:

decrease_first n l = map (subtract 1) (take n l) ++ drop n l

As a variant, you can use splitAt to get take & drop together:

import Data.List
decrease_first n l = map (subtract 1) left ++ right
      where (left,right) = splitAt n l

or alternatively:

decrease_first n l = 
  (\(left, right) -> map (subtract 1) left ++ right) (splitAt n l)

which is not really better than the above ones.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM