I have a simple program (it was the second question on CCC 2012) that takes a list of numbers and determines if there is any strictly increasing/decreasing/constant sequence going on. For example:
1 2 3 4 7 8 => Increasing
5 1 -2 -100 => Decreasing
9 9 9 9 9 9 => Constant
1 2 3 4 5 0 => Nothing
I was completely blown away by how smart Haskell was when I coded this. For some reason, when I typed in the numbers interactively into stdin, in was giving me the answer before I had even finished! I thought it was a bug, but then I foolishly realized that Haskell's laziness (I think?) was taking it upon itself to decide that, after I entered 1, 2, 3, 0, no matter what came after, the result would be Nothing, and so it happily outputted that.
Unfortunately, when I changed
let readings = map (read :: (Read a, Num a) => String -> a) $ lines input
to
let readings = parse $ lines input
with parse being a safer method of reading numerical input, implemented as
maybeRead :: (Read a) => String -> Maybe a
maybeRead = fmap fst . listToMaybe . filter (null . dropWhile isSpace . snd) . reads
parse :: (Read a) => [String] -> [a]
parse xs =
let entries = map maybeRead xs
in if all isJust entries
then map fromJust entries
else []
it no longer does this.
Why?
EDIT: More code
-- | Zip together adjacent list elements as pairs in a new list.
zipPairs :: [a] -> [(a, a)]
zipPairs xs = zip (init xs) (tail xs)
-- | Return True if all elements of a given list are equal.
constant :: (Eq a) => [a] -> Bool
constant xs = all (== head xs) (tail xs)
-- | Return the order that the elements of a list are sorted in, if they form
-- a strictly increasing (Just LT), decreasing (Just GT) or constant (Just EQ)
-- sequence. If there is no pattern, return Nothing.
order :: (Ord a) => [a] -> Maybe Ordering
order xs =
let orders = map (\(x, y) -> x `compare` y) (zipPairs xs)
in if constant orders then Just (head orders) else Nothing
and then in mainI have
let readings = parse $ lines input
putStrLn $ if null readings
then "bad input"
else case order readings of
Just EQ -> "Constant"
Just LT -> "Diving"
Just GT -> "Rising"
Nothing -> "Nothing"
If all entries are justs, all isJust entries checks the entire list of entries, which means that the entire list of entries needs to be read in before parse can return.
Okay, longer explanation of why orders is lazy -- all returns False as soon as it reaches a value for which the predicate returns False. Therefore, constant returns false as soon as it hits a value in the tail that isn't equal to the head. order returns as soon as constant returns, so order is lazy.
My first suggestion is stylistic -- look at the zipWith function when calculating orders. let orders = zipWith compare xs $ tail xs should work equally well.
As far as solving your actual problem is concerned, try
order xs = let orders = zipWith (liftM2 compare) xs $ tail xs
in if isJust (head orders) && constant orders
then head orders
else Nothing
Note that you need to import Data.Monad
liftM2 compare will return Just (compare x y) when passed Just x and Just y and Nothing if either or both of its arguments are Nothing.
orders is now a [Maybe Ordering]. If orders is constant (note: (==) works on Maybes) and the first element is a Just, return the first element (which is already a Maybe Ordering). Otherwise, just return Nothing. You could do without the isJust (head orders) call, but adding it should make it return as soon as it sees a Nothing (otherwise, if you give it a list of all Nothings, it will check if every one is Nothing).
You can probably use mapMaybe from Data.Maybe. That is, swap map read with mapMaybe maybeRead. What mapMaybe does is map the function over the list, filter out the Nothings and extract all the remaining values.
Related
I start in Fsharp and I have this question.
Assuming I have two lists a and b of the same length, I travel theses lists simultaneously and test a condition on a and b each step, with the result of a previous calculus. If this test fails there is no need to keep on.
I wrote this code :
let mutable (i : int) = 0
let mutable (good : bool) = true
let mutable (previous : int) = 0
while good && i < len do
good <- test a.[i] b.[i] previous
previous <- my_func a.[i] b.[i]
i <- i + 1
I saw this code which is much much better :
List.zip a b |> List.fold (fun (x, y) (a,b) -> (p && test a b y, my_func a b) (true, 0)
But, with my code, as soon as the test fails, the process finished, not with the second code.
Is there a way, using the design of the second code to stop the process ?
Thank you
I assume you are only interested in whether the final result is good.
As mentioned by Brian, you can use Seq.scan which behaves like Seq.fold but it returns all the intermediate states rather than just the final state. By using Seq instead of List you are also using a lazy sequence and so functions can terminate early. To do what you want, you can use Seq.scan together with Seq.forall, which will check that all values of a given sequence satisfy a certain condition - the nice thing here is that this can terminate early as soon as the condition is false.
Putting all this together, I get something like this:
Seq.zip a b
|> Seq.scan (fun (good, prev) (a, b) ->
test a b prev, my_func a b) (true, 0)
|> Seq.forall (fun (good, _) -> good)
Three ideas:
You could write your own variation of fold that stops when a flag is set to false. Personally, I think that would be cumbersome, though.
You could use Seq.scan to lazily accumulate all the results of my_func and then examine them, similar to this answer. Since Seq is lazy, the scan would short circuit the way you want. This is tricky to get right, though.
You could walk the lists recursively. IMHO, this is the simplest functional solution. Something like this:
let rec examine listA listB prev =
match listA, listB with
| headA :: tailA, headB :: tailB ->
if test headA headB prev then
let prev' = my_func headA headB
examine tailA tailB prev'
else false
| [], [] -> true
| _ -> false
examine listA listB 0
I am trying to convert the following normal-recursive code to tail-recursive in F#, but I am failing miserably.
let rec insert elem lst =
match lst with
| [] -> [elem]
| hd::tl -> if hd > elem then
elem::lst
else
hd::(insert elem tl)
let lst1 = []
let lst2 = [1;2;3;5]
printfn "\nInserting 4 in an empty list: %A" (insert 4 lst1)
printfn "\nInserting 4 in a sorted list: %A" (insert 4 lst2)
Can you guys help? Unfortunately I am a beginner in f#. Also, can anyone point me to a good tutorial to understand tail-recursion?
The point of tail recursion is the following: the last operation before returning from a function is a call to itself; this is called a tail call, and is where tail recursion gets its name from (the recursive call is in last, i.e. tail position).
Your function is not tail recursive because at least one of its branches has an operation after the recursive call (the list cons operator).
The usual way of converting a recursive function into a tail-recursive function is to add an argument to accumulate intermediate results (the accumulator). When it comes to lists, and when you realize that the only elementary list operation is prepending an element, this also means that after you are through with processing your list, it will be reversed, and thus the resulting accumulator will usually have to be reversed again.
With all these points in mind, and given that we do not want to change the function's public interface by adding a parameter that is superfluous from the caller's point of view, we move the real work to an internal subfunction. This particular function is slightly more complicated because after the element has been inserted, there is nothing else to do but concatenate the two partial lists again, one of which is now in reverse order while the other is not. We create a second internal function to handle that part, and so the whole function looks as follows:
let insert elm lst =
let rec iter acc = function
| [] -> List.rev (elm :: acc)
| (h :: t) as ls ->
if h > elm then finish (elm :: ls) acc
else iter (h :: acc) t
and finish acc = function
| [] -> acc
| h :: t -> finish (h :: acc) t
iter [] lst
For further studying, Scott Wlaschin's F# for Fun and Profit is a great resource, and tail recursion is handled in a larger chapter about recursive types and more: https://fsharpforfunandprofit.com/posts/recursive-types-and-folds
I want to create a function that removes any occurrence of a integer n and returns the list. I know how I want to do it but do not know the command to delete it.
Here is the data type
type alist =
A
| L of int * Alist
Here's how the data type looks:
let l = L(2, L(1, L(2, L(7, L(3, L(2, A))))))
remove 2 l;;
should return
l = L(1, L(7, L(3, A)))
Here is what I have so far:
let rec remove n l =
match (n, l) with
| (n, A) -> l
| (n, L(head,tail)) when (n = head) ->
I don't know how the how to get rid of a list or element.
You shouldn't be thinking in terms of "deleting" the list; you should instead think in terms of building a new list, without the element you want removed. I'll show you how to do that in a minute, but first I want to make a suggestion. In your match expression, you are re-using the name n in your patterns. That's a classic beginner's mistake, because it ends up confusing you. Once you know F# pretty well, that's a valid technique, but since you appear to be a beginner, I strongly suggest not doing that. Instead, use a name in your patterns that is different from the name of the thing you're matching against, because that will help teach you something. Let's rewrite your match expression with x as the name of the int in your patterns:
let rec remove n l =
match (n, l) with
| (x, A) -> l
| (x, L(head,tail)) when (x = head) ->
What each of these two patterns is doing is assigning the name x to represent the value of n if the rest of the pattern matches. Now we can more clearly see that the first pattern doesn't use the value of x at all, so it would be better to represent it by _ in that case (_ is the "wildcard" pattern, which means "I don't care about the value in this position). Thus, your match expression would become:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> // ... Still need to write this
Now let's think about what we want to do in that second match case. Here we have a node that is precisely the kind of node we want to remove from the list. So how do we go about building a list without that node in it? Well, as it happens, we already have such a list... and we've assigned it the name tail in that second match case. So at first, it might look like we could just do this:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> tail
This will return a list with the "head" node chopped off. But wait! What if the tail itself contained one or more nodes with the value we want removed? What we'd really like to return from this match case is tail, passed through a function that would remove all the nodes that match a certain value. But... wait a minute... aren't we writing a function like that right now? What if we could just call remove on the tail and have it do the rest of the work for us; wouldn't that be nice?
Well, it turns out that we can! All you have to do to remove the rest of the unwanted values from the tail list is to call remove on it! Like so:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> remove n tail
But we're not quite done yet, because there's one more possibility in your match statement. If you are using a good F# development environment (I recommend Visual Studio Code with the Ionide plugin), you should see a green wavy underline under the match keyword, and if you hover over it you should see a warning about an incomplete match expression. That's because there's one case we haven't accounted for: the case where l is a node that isn't A, but whose head value isn't equal to n. In other words, this match case:
| (x, L(head,tail)) when (x <> head) -> // What do we do here?
Well, for starters, let's simplify this match case a bit. If we put it into the complete match expression, we should see that the when guard is actually unnecessary. Match cases are checked from top to bottom, in order. Which means that if we get to the third match case, we already know that x must not be equal to head; otherwise the second match case would have been chosen! You may not be able to see why just yet, so let's put that match case into our match expression and take a look at it:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> remove n tail
| (x, L(head,tail)) when (x <> head) -> // What do we do here?
Now it's more obvious that this exactly like the previous match case, but with the opposite when guard. Which means that if we ever reach the third match case, the when expression must be true -- because if it was false, then that means that x is equal to head and so we would have gone down the second match case, not the third.
Therefore, we can actually remove the when guard from the third match case, which will now look like this:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> remove n tail
| (x, L(head,tail)) -> // What do we do here?
There's more simplification that can be done here, but it's time to look at what result we want to return. Here, we do NOT want to skip the first node of the list, but we'd still like to remove n from the tail. In fact, what we want as a result of this function is a list node containing the same head as our current list node, but with a tail that has had n removed from it. (If you don't understand that last sentence, take a minute and try to picture this in your head.) So how do we do this? Well, the simplest way is as follows:
let newTail = remove n tail
L(head, newTail)
Which can be simplified to:
L(head, remove n tail)
So the match function looks like this now:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> remove n tail
| (x, L(head,tail)) -> L(head, remove n tail)
Believe it or not, we're done! Well, almost: we have a working function now, but it's actually more complicated than it needs to be. Antoine de Saint-Exupéry is most well-known for writing The Little Prince, but he was also an aviator, who has a famous quote about design:
Il semble que la perfection soit atteinte non quand il n'y a plus rien à ajouter, mais quand il n'y a plus rien à retrancher.
In English, that's:
It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove.
So what can we remove from this function to pare it down to the absolute essentials? Well, let's start by looking at that last match case again:
| (x, L(head,tail)) -> L(head, remove n tail)
It looks like we don't use the value of x anywhere in this match case, so we don't actually need to assign a name to the int in this match case. We can just use the wildcard _ here. Once we do, our function looks like:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (x, L(head,tail)) when (x = head) -> remove n tail
| (_, L(head,tail)) -> L(head, remove n tail)
And at this point, you might think that we're really done, because we do use the value of x in the second match case, so we can't get rid of it. Or... can we? Let's look at the second match case more closely:
| (x, L(head,tail)) when (x = head) -> remove n tail
Now. The value of x here is the same as the value of n, because this match case is actually assigning the value of n to the name x by virtue of x being in the first tuple position. Right? So in the when guard, we could actually swap out x for n in the x = head check. This is legal: the checks that you do in a match case do NOT have to include only names that have appeared in the match pattern. They can be any names that your function has access to. So it's perfectly valid to swap x out for n and get the match case to look like this:
| (x, L(head,tail)) when (n = head) -> remove n tail
And now we see that we're not using the value of x in this match case either, just like in the third match case. So let's get rid of it:
| (_, L(head,tail)) when (n = head) -> remove n tail
Now let's put this match case back into our function and take a look at the function as a whole:
let rec remove n l =
match (n, l) with
| (_, A) -> l
| (_, L(head,tail)) when (n = head) -> remove n tail
| (_, L(head,tail)) -> L(head, remove n tail)
Huh. Would you look at that? The first tuple item has "I don't care" in every single spot in the match case. And yet, the function still compiles without warning about incomplete match patterns, and still runs and produces the correct values. (Try it!) So what does this tell us? It tells us that we don't actually need to have n in the value we're matching against, because we never need it in the match patterns. We need it in the when guards, but not in the match patterns themselves! So if we actually remove n from the value we're matching against, and from the match patterns, here's the result:
let rec remove n l =
match l with
| A -> l
| L(head,tail) when (n = head) -> remove n tail
| L(head,tail) -> L(head, remove n tail)
Try it. You'll see that this function also compiles, and still does exactly what you want it to do.
At this point, we really are done. Taking away anything else from this function would break it: either it wouldn't compile, or else it wouldn't return the right value. This may not be immediately obvious to you, but as your skill with F# grows, you'll learn to get a feel for when a function has been pared down to its bare essentials, and this one has.
And so there you go: after a lot of tweaking, we've gotten the remove function not just working, but working elegantly. This is the simplest you can possibly make this function, and there's a certain beauty in that. If you can see and appreciate that beauty, the beauty of a function that does exactly what it should and no more, you'll be well on your way to becoming a skilled F# programmer!
P.S. There is actually one more rewrite that we could do on this function, because it actually could be better. As it stands, this function is not always tail-recursive, which means that if you called it on a really large list, you could get a StackOverflowException. But if you haven't reached the point of studying tail recursion yet, then trying to explain how to fix this problem would be like to confuse you rather than help you understand things better. So I've deliberately chosen to end with this pared-down, elegant version of the function, rather than the version that does tail recursion "properly". Because making that improvement would produce a function that was actually more complicated and harder to understand. Once you're more experienced with F#, it'll be worth revisiting this question and asking "How do I make this function tail-recursive?". But for now, the non-tail-recursive version that we have here is the one that you should study. Once you understand how to write this function on your own, and can write other list-manipulation functions on your user-defined list data structure, then you'll have the knowledge needed to make that last improvement.
I hope this helps. Please leave a comment asking me about anything you don't understand in my explanation.
Good Morning everyone,
I must do an exercise of Programming, but i'm stuck!
Well, the exercise requires a function that given a list not empty of integers, return the first number with maximum number of occurrences.
For example:
mode [1;2;5;1;2;3;4;5;5;4:5;5] ==> 5
mode [2;1;2;1;1;2] ==> 2
mode [-1;2;1;2;5;-1;5;5;2] ==> 2
mode [7] ==> 7
Important: the exercise must be in functional programming
My idea is:
let rec occurences_counter xs i = match xs with
|[] -> failwith "Error"
|x :: xs when x = i -> 1 + occurences_counter xs i
|x :: xs -> occurences_counter xs i;;
In this function i'm stuck:
let rec mode (l : int list) : int = match l with
|[] -> failwith "Error"
|[x] -> x
|x::y::l when occurences_counter l x >= occurences_counter l y -> x :: mode l
|x::y::l when occurences_counter l y > occurences_counter l x -> y :: mode l;;
Thanks in advance, i'm newbie in programming and in stackoverflow
Sorry for my english
one solution : calculate first a list of couples (number , occurences).
hint : use List.assoc.
Then, loop over that list of couple to find the max occurrence and then return the number.
One suggestion:
your algorithm could be simplified if you sort the list before. This has O(N log(N)) complexity. Then measure the longest sequence of identical numbers.
This is a good strategy because you delegate the hard part of the work to a well known algorithm.
It is probably not the most beautiful code, but here is with what i came up (F#). At first i transform every element to an intermediate format. This format contains the element itself, the position of it occurrence and the amount it occurred.
type T<'a> = {
Element: 'a
Position: int
Occurred: int
}
The idea is that those Records can be added. So you can first transform every element, and then add them together. So a list like
[1;3]
will be first transformed to
[{Element=1;Position=0;Occurred=1}; {Element=3;Position=1;Occurred=1}]
By adding two together you only can add those with the same "Element". The Position with the lower number from both is taken, and Occurred is just added together. So if you for example have
{Element=3;Position=1;Occurred=2} {Element=3;Position=3;Occurred=2}
the result will be
{Element=3;Position=1;Occurred=4}
The idea that i had in mind was a Monoid. But in a real Monoid you had to come up that you also could add different Elements together. By trying some stuff out i feel that the restriction of just adding the same Element where way more easier. I created a small Module with the type. Including some helper functions for creating, adding and comparing.
module Occurred =
type T<'a> = {
Element: 'a
Position: int
Occurred: int
}
let create x pos occ = {Element=x; Position=pos; Occurred=occ}
let sameElements x y = x.Element = y.Element
let add x y =
if not <| sameElements x y then failwith "Cannot add two different Occurred"
create x.Element (min x.Position y.Position) (x.Occurred + y.Occurred)
let compareOccurredPosition x y =
let occ = compare x.Occurred y.Occurred
let pos = compare x.Position y.Position
match occ,pos with
| 0,x -> x * -1
| x,_ -> x
With this setup i now wrote two additional function. One aggregate function that first turns every element into a Occurred.T, group them by x.Element (the result is a list of list). And then it uses List.reduce on the inner list to add the Occurred with the same Element together. The result is a List that Contains only a single Occurred.T for every Element with the first Position and the amount of Occurred items.
let aggregate =
List.mapi (fun i x -> Occurred.create x i 1)
>> List.groupBy (fun occ -> occ.Element)
>> List.map (fun (x,occ) -> List.reduce Occurred.add occ)
You could use that aggregate function to now implement different aggregation logic. In your case you only wanted the one with the highest Occurrences and the lowest position. I wrote another function that did that.
let firstMostOccurred =
List.sortWith (fun x y -> (Occurred.compareOccurredPosition x y) * -1) >> List.head >> (fun x -> x.Element)
One note. Occurred.compareOccurredPosition is written that it sorts everything in ascending order. I think people expecting it in this order to go to the smallest to the biggest element by default. So by default the first element would be the element with the lowest occurrence and the biggest Position. By multiplying the result of it with -1 you turn that function into a descending sorting function. The reason why i did that is that i could use List.head. I also could use List.last to get the last element, but i felt that it would be better not to go through the whole list again just to get the last element. On top of it, you didn't wanted an Occurred.T you wanted the element itself, so i unwrap the Element to get the number.
Here is everything in action
let ll = [
[1;2;5;1;2;3;4;5;5;4;5;5]
[2;1;2;1;1;2]
[-1;2;1;2;5;-1;5;5;2]
[7]
]
ll
|> List.map aggregate
|> List.map firstMostOccurred
|> List.iter (printfn "%d")
This code will now print
5
2
2
7
It has still some rough edges like
Occurred.add throws an exception if you try to add Occurred with different Elements
List.head throws an exception for empty lists
And in both cases no code is written to handle those cases or making sure an exception will not raise.
You need to process you input list while maintaining a state, that stores the number of occurrences of each number. Basically, the state can be a map, where keys are in the domain of list elements, and values are in domain of natural numbers. If you will use Map the algorithm would be of O(NlogN) complexity. You can also use associative list (i.e., a list of type ('key,'value) list) to implement map. This will lead to quadratic complexity. Another approach is to use hash table or an array of the length equal to the size of the input domain. Both will give you a linear complexity.
After you collected the statistics, (i.e., a mapping from element to the number of its occurrences) you need to go through the set of winners, and choose the one, that was first on the list.
In OCaml the solution would look like this:
open Core_kernel.Std
let mode xs : int =
List.fold xs ~init:Int.Map.empty ~f:(fun stat x ->
Map.change stat x (function
| None -> Some 1
| Some n -> Some (n+1))) |>
Map.fold ~init:Int.Map.empty ~f:(fun ~key:x ~data:n modes ->
Map.add_multi modes ~key:n ~data:x) |>
Map.max_elt |> function
| None -> invalid_arg "mode: empty list"
| Some (_,ms) -> List.find_exn xs ~f:(List.mem ms)
The algorithm is the following:
Run through input and compute frequency of each element
Run through statistics and compute spectrum (i.e., a mapping from frequency to elements).
Get the set of elements that has the highest frequency, and find an element in the input list, that is in this set.
For example, if we take sample [1;2;5;1;2;3;4;5;5;4;5;5],
stats = {1 => 2; 2 => 2; 3 => 1; 4 => 2; 5 => 5}
mods = {1 => [3]; 2 => [1;2]; 5 => [5]}
You need to install core library to play with it. Use coretop to play with this function in the toplevel. Or corebuild to compile it, like this:
corebuild test.byte --
if the source code is stored in test.ml
The :: operator in F# always prepends elements to the list. Is there an operator that appends to the list? I'm guessing that using # operator
[1; 2; 3] # [4]
would be less efficient, than appending one element.
As others said, there is no such operator, because it wouldn't make much sense. I actually think that this is a good thing, because it makes it easier to realize that the operation will not be efficient. In practice, you shouldn't need the operator - there is usually a better way to write the same thing.
Typical scenario: I think that the typical scenario where you could think that you need to append elements to the end is so common that it may be useful to describe it.
Adding elements to the end seems necessary when you're writing a tail-recursive version of a function using the accumulator parameter. For example a (inefficient) implementation of filter function for lists would look like this:
let filter f l =
let rec filterUtil acc l =
match l with
| [] -> acc
| x::xs when f x -> filterUtil (acc # [x]) xs
| x::xs -> filterUtil acc xs
filterUtil [] l
In each step, we need to append one element to the accumulator (which stores elements to be returned as the result). This code can be easily modified to use the :: operator instead of appending elements to the end of the acc list:
let filter f l =
let rec filterUtil acc l =
match l with
| [] -> List.rev acc // (1)
| x::xs when f x -> filterUtil (x::acc) xs // (2)
| x::xs -> filterUtil acc xs
filterUtil [] l
In (2), we're now adding elements to the front of the accumulator and when the function is about to return the result, we reverse the list (1), which is a lot more efficient than appending elements one by one.
Lists in F# are singly-linked and immutable. This means consing onto the front is O(1) (create an element and have it point to an existing list), whereas snocing onto the back is O(N) (as the entire list must be replicated; you can't change the existing final pointer, you must create a whole new list).
If you do need to "append one element to the back", then e.g.
l # [42]
is the way to do it, but this is a code smell.
The cost of appending two standard lists is proportional to the length of the list on the left. In particular, the cost of
xs # [x]
is proportional to the length of xs—it is not a constant cost.
If you want a list-like abstraction with a constant-time append, you can use John Hughes's function representation, which I'll call hlist. I'll try to use OCaml syntax, which I hope is close enough to F#:
type 'a hlist = 'a list -> 'a list (* a John Hughes list *)
let empty : 'a hlist = let id xs = xs in id
let append xs ys = fun tail -> xs (ys tail)
let singleton x = fun tail -> x :: tail
let cons x xs = append (singleton x) xs
let snoc xs x = append xs (singleton x)
let to_list : 'a hlist -> 'a list = fun xs -> xs []
The idea is that you represent a list functionally as a function from "the rest of the elements" to "the final list". This works great if you are going to build up the whole list before you look at any of the elements. Otherwise you'll have to deal with the linear cost of append or use another data structure entirely.
I'm guessing that using # operator [...] would be less efficient, than appending one element.
If it is, it will be a negligible difference. Both appending a single item and concatenating a list to the end are O(n) operations. As a matter of fact I can't think of a single thing that # has to do, which a single-item append function wouldn't.
Maybe you want to use another data structure. We have double-ended queues (or short "Deques") in fsharpx. You can read more about them at http://jackfoxy.com/double-ended-queues-for-fsharp
The efficiency (or lack of) comes from iterating through the list to find the final element. So declaring a new list with [4] is going to be negligible for all but the most trivial scenarios.
Try using a double-ended queue instead of list. I recently added 4 versions of deques (Okasaki's spelling) to FSharpx.Core (Available through NuGet. Source code at FSharpx.Core.Datastructures). See my article about using dequeus Double-ended queues for F#
I've suggested to the F# team the cons operator, ::, and the active pattern discriminator be made available for other data structures with a head/tail signature.3