I have been working on a separate function that returns a list that inserts element x after each k elements of list l (counting from the end of the list). For example, separate (1, 0, [1,2,3,4]) should return [1,0,2,0,3,0,4]. I finished the function and have it working as follows:
fun separate (k: int, x: 'a, l: 'a list) : 'a list =
let
fun kinsert [] _ = []
| kinsert ls 0 = x::(kinsert ls k)
| kinsert (l::ls) i = l::(kinsert ls (i-1))
in
List.rev (kinsert (List.rev l) k)
end
Im now trying to simplify the function using foldl/foldr without any recursion, but I cant seem to get it working right. Any tips/suggestions on how to approach this? Thank You!
These are more or less the thoughts I had when trying to write the function using
foldl/foldr:foldl/foldrabstracts away the list recursion from the logic that composes the end result.Start by sketching out a function that has a much similar structure to your original program, but where
foldris used andkinsertinstead of being a recursive function is the function given tofoldr:This isn't strictly necessary;
kinsertmight as well be anonymous.You're using an inner helper function
kinsertbecause you need a copy ofk(i) that you gradually decrement and reset tokevery time it reaches 0. So while the list thatkinsertspits out is equivalent to the fold's accumulated variable,iis temporarily accumulated (and occasionally reset) in much the same way.Change
kinsert's accumulating variable to make room fori:Now the result of the fold becomes
'a * 'a list, which causes two problems: 1) We only really wanted to accumulateitemporarily, but it's part of the final result. This can be circumvented by discarding it using#2 (foldr ...). 2) If the result is now a tuple, I'm not sure what to put as the firstiin place of?.Since
kinsertis a separate function declaration, you can use pattern matching and multiple function bodies:Your original
kinsertdeviates from the recursion pattern that a fold performs in one way: In the middle pattern, whenimatches0, you're not chopping an element offls, which a fold would otherwise force you to. So your0case will look slightly different from the original; you'll probably run into an off-by-one error.Remember that
foldractually visits the last element in the list first, at which pointiwill have its initial value, where with the originalkinsert, the initial value foriwill be when you're at the first element.Depending on whether you use
foldlorfoldryou'll run into different problems:foldlwill reverse your list, but address items in the right order.foldrwill keep the list order correct, but create a different result whenkdoes not divide the length ofL...At this point, consider using
foldland reverse the list instead:Otherwise you'll start to notice that
separate (2, 0, [1,2,3,4,5])should probably give[1,2,0,3,4,0,5]and not[1,0,2,3,0,5].