Daniel Hollinrake
Daniel Hollinrake

Reputation: 1778

Reversing a list then adding new item

I am trying to learn F#, and I'm trying to create some simple functions as part of this learning.

I have created a function that adds an item to a list then reverses the result. This works very nicely in the F# interactive window in Visual Studio

let addThenReverse n list =
match list with
| [] -> []
| _ -> n::list |> List.rev

addThenReverse 0 [1;2;3]   //results in [3; 2; 1; 0]

But I'm having difficulty with writing a function that would reverse a list then add an item to it.

let reverseThenAdd n list =
    match list with
    | [] -> []
    | _ -> List.rev list |> n::list

reverseThenAdd 9 [1;2;3]  //desired result [3; 2; 1; 9]

EDIT The desired result for the above should be [9; 3; 2; 1]. Well done to those who spotted this!

This second function does not compile and I receive the warning 'This expression was expected to have type 'a list -> 'b list but here has type 'c list'

Any variants I try seem to result other compilation errors. I assume (but don't know how) that I need to use the new list created as a result of 'List.rev list', perhaps by assigning it to a variable.

Upvotes: 2

Views: 502

Answers (3)

Asti
Asti

Reputation: 12687

let reverseThenAdd n list = List.rev list @ [n]

Upvotes: 1

Rob Lyndon
Rob Lyndon

Reputation: 12681

I'm a little confused by your desired results. Luiso has a version of your code that will fix the compiler, but it won't fit your desired result. With

let reverseThenAdd n list =
    match list with
    | [] -> []
    | _ -> n :: (List.rev list)

reverseThenAdd 9 [1;2;3]  //desired result [3; 2; 1; 9]

the actual result will be [9; 3; 2; 1]. If the comment is a typo, and that is in fact your desired result, then Luiso's answer works. Otherwise, there is no material difference between addThenReverse and reverseThenAdd, because "add" means something different (appending and prepending) in each case.

Note that I think in both cases, the first case should be

| [] -> [n]

rather than

| [] -> []

In fact, I don't think you need the match statement at all. I think the mathematically correct formulation would be:

let addThenReverse n list = n::list |> List.rev
let reverseThenAdd n list = n::(list |> List.rev)

Then you would have

addThenReverse 0 [] // result: [0]
reverseThenAdd 0 [] // result: [0]
addThenReverse 9 [1; 2; 3] // result: [3; 2; 1; 9]
reverseThenAdd 9 [1; 2; 3] // result: [9; 3; 2; 1]

ADDENDUM

I'm a fan of expressive code. As elegant as F# is, it is still possible to write code that obscures what you're actually trying to do. The code above works, but you can make it more expressive, and learn a bit more about how the language works, by using the composition operator:

let add n list = n::list
let reverse = List.rev
let addThenReverse n = add n >> reverse
let reverseThenAdd n = reverse >> add n

This gives the same results as before, but it expresses what you're doing more clearly. True to the spirit of functional programming, you're telling the compiler what to do, rather than how to do it.

Upvotes: 4

Luiso
Luiso

Reputation: 4113

The issue is that you are passing the reversed list to a concatenation expression, and that throws off the compiler. You should do:

let reverseThenAdd n list =
    match list with
    | [] -> []
    | _ -> n :: (List.rev list)

reverseThenAdd 9 [1;2;3]  //desired result [3;2;1;9]

which means that you are adding n to the list resulting from (List.rev list)

Upvotes: 4

Related Questions