I am pretty new to F# and I wanted to implement a solution to the following problem:
From a sequence of disk paths discovered in random order (e.g. "C:\Hello\foo" "C:" , "C:\Hello\bar" etc....) how to build (efficiently) the tree.
Assumption: the sequence is valid, which means the tree can be effectively created.
So I tried to implement with a recursive function ("mergeInto" in the following) which merges the tree "in place" with a list of string (the splitted path called "branch")
Here is my implementation, the immutability prevents side effects on the input tree, so I tried to use a ref cell for the input Tree but I encounter difficulty with the recursion. Any solution ?
open Microsoft.VisualStudio.TestTools.UnitTesting
type Tree =
|Node of string*list<Tree>
|Empty
let rec branchToTree (inputList:list<string>) =
match inputList with
| [] -> Tree.Empty
| head::tail -> Tree.Node (head, [branchToTree tail])
//branch cannot be empty list
let rec mergeInto (tree:Tree ref) (branch:list<string>) =
match !tree,branch with
| Node (value,_), head::tail when String.op_Inequality(value, head) -> raise (ApplicationException("Oops invariant loop broken"))
| Node (value,_), [_] -> ignore() //the branch is singleton and by loop invariant its head is the current Tree node -> nothing to do.
| Node (value,children), _ ->
let nextBranchValue = branch.Tail.Head //valid because of previous match
//broken attempt to retrieve a ref to the proper child
let targetChild = children
|> List.map (fun(child) -> ref child)
|> List.tryFind (fun(child) -> match !child with
|Empty -> false
|Node (value,_) -> value = nextBranchValue)
match targetChild with
|Some x -> mergeInto x branch.Tail //a valid child match then go deeper. NB: branch.Tail cannot be empty here
|None -> tree := Node(value, (Node (nextBranchValue,[])) :: children)//attach the next branch value to the children
| Empty,_ -> tree := branchToTree branch
[<TestClass>]
type TreeTests () =
[<TestMethod>]
member this.BuildTree () =
let initialTree = ref Tree.Empty
let branch1 = ["a";"b";"c"]
let branch2 = ["a";"b";"d"]
do mergeInto initialTree branch1
//-> my tree is ok
do mergeInto initialTree branch2
//->not ok, expected a
// |
// b
// / \
// d c
You can't make a ref to an element in a list, change the ref and then expect the item in the list to change. If you really want to do that then you should put the references into your Tree type.
type Tree =
|Node of string*list<Tree ref>
|Empty
let rec branchToTree (inputList:list<string>) =
match inputList with
| [] -> Tree.Empty
| head::tail -> Tree.Node(head, [ref (branchToTree tail)])
If you do that, remove the List.map (fun(child) -> ref child) part then your code works.
You might be interested in zippers which allow you to do something similar but without mutation.
Related
I am trying to write a 'remove' function that can delete a tree type based on the value of a given string list but I am not getting something right when I use the function, example:
Code:
type Tree = Leaf of string | Branch of (string * Tree) list
let rec remove (p :string list) (tree: Tree) :Tree =
match p, tree with
| a::b, y ->
match y with
| Leaf(n) when a = n -> Leaf("")
| Branch[(x, p)] when a = x -> Branch[("", remove b p)]
| _ -> remove b y
| [], y -> tree
Test:
remove ["1"; "2"; "3"; "4"]
(Branch [("6", Branch [("1", Branch [("2", Branch [("13", Leaf "4")])])])])
gives the answer
Branch [("6", Branch [("1", Branch [("2", Branch [("13", Leaf "4")])])])]
instead of
(Branch [("6", Branch [(" ", Branch [(" ", Branch [("13", Leaf " ")])])])])
If anyone can help advise me it would be great because I cannot understand what I am doing wrong.
The way you are doing this is that you are iterating over the list and the tree at the same time. This means that your code can only work if the numbers appear in the tree in the same order in which they appear in the list of items to be removed.
If this is what you actually want, you can add one case to your function to make it work:
let rec remove (p :string list) (tree: Tree) :Tree =
match p, tree with
| a::b, y ->
match y with
| Leaf(n) when a = n -> Leaf("")
| Branch[(x, p)] when a = x -> Branch[("", remove b p)]
| Branch[(x, p)] -> Branch[(x, remove (a::b) p)] // Added this line!
| _ -> remove b y
| [], y -> tree
The added line handles the case when you find a branch that has a number not at the beginning of the list - so we keep the branch as is and continue removing numbers from the sub-tree.
That said, I imagine you probably want to remove the nodes regardless of the order of the elements in the list. You can do this by using something like List.contains to check if a branch should be removed:
let rec remove (p :string list) (tree: Tree) :Tree =
match tree with
| Leaf(n) when List.contains n p -> Leaf("")
| Branch[(x, sub)] when List.contains x p -> Branch[("", remove p sub)]
| Branch[(x, sub)] -> Branch[(x, remove p sub)]
Note that this code is still missing a case for branch with multiple sub-trees, so this is something you'll need to add, but hopefully, the example points you in the right direction!
I have some state that is represented as a tree
type Tree state
= Branch (List (Tree state))
| Leaf state
and I have a function to update the individual leaves given some action
updateLeaf : action -> state -> state
I would like a way to represent actions in some structure
type Structure action = ...
which carries an action and some means to know precisely which leaf in the tree to update.
For example, suppose I have the following tree:
Branch
[ Leaf "foo"
, Leaf "bar"
, Branch
[ Leaf "baz"
, Branch []
, Leaf "qux"
]
]
and I get some action say, "hello" and I would like it to apply my updateLeaf function only on "baz" in such a way that I end up with
Branch
[ Leaf "foo"
, Leaf "bar"
, Branch
[ Leaf "bazhello"
, Branch []
, Leaf "qux"
]
]
assuming my updateLeaf function is just string concatenation or (++). Furthermore, I would need this to pretty generic as in the structure would somehow track the position in the tree of the leaf it wishes to update.
In essence what I am looking for is for the following function:
updateTree
: (action -> state -> state)
-> Structure action
-> Tree state
-> Tree state
which will figure out which leaf in the tree to apply the given update function.
Finally, I also need it to work with address forwarding. Suppose the each leaf of the tree is represented as a button
viewLeaf : Address action -> state -> Html
viewLeaf address state =
button
[ onClick address ... ]
[ ... ]
and further suppose that the actions sent by the button on click are the ones that will update the state.
I would like to be able to define the following function
viewTree
: (Address action -> state -> Html)
-> Address (Structure action)
-> Tree state
-> Html
such that I can view all those buttons and the addresses are forwarded accordingly such that each button only affects itself. (I'm only interested in the forwarding aspect, not the visuals).
Thanks a lot for your help
A zipper is a way to navigate and modify a data structure. Suppose you have a tree, and you walk down the tree by choosing a branch. After 3 steps you encounter a leaf and you with to modify it. Now you want to return the modified tree, but you're 3 levels deep, how do you step back? Suppose that every time you go down a level in a tree, you leave a trail of breadcrumbs, so that you can reverse a step and reconstruct the tree. In other words, instead of just a tree you have a tuple (tree, breadcrumbs).
type Tree state = Branch (List (Tree state)) | Leaf state
-- Crumb contains 2 lists:
-- leafs/branches to the left of your focus
-- leafs/branches to the right of your focus
type Crumb state = Crumb (List (Tree state)) (List (Tree state))
type alias Zipper state = (Tree state, List (Crumb state))
tree : Tree String
tree = Branch [Leaf "foo",Leaf "bar",Branch [Leaf "baz",Branch [],Leaf "qux"]]
Every time you choose a branch, you cons the parent node and all other branches you didn't choose into breadcrumbs. Then you choose a new branch, so you cons its parent mode and all new branches you didn't choose in breadcrumbs. Therefore breadcrumbs contain all relevant information to reconstruct the previous step in reverse order. Let's implement going up and going to a leaf by name in a tree:
import Graphics.Element exposing (show)
break : (a -> Bool) -> List a -> (List a, List a)
break p xs = case (List.head xs, List.tail xs) of
(Nothing, Nothing) -> ([], [])
(Just x, Just xs') -> if p x
then ([], xs)
else let (ys,zs) = break p xs'
in (x::ys,zs)
treeInit : Tree state -> Zipper state
treeInit t = (t, [])
treeUp : Zipper state -> Zipper state
treeUp (subtree, Crumb l r::bs) = (Branch <| l++[subtree]++r, bs)
treeTo : state -> Zipper state -> Zipper state
treeTo name (Branch subtrees, bs) =
let (l, x::r) = break (\(Leaf name') -> name == name') subtrees
in (x, Crumb l r::bs)
main = tree |> treeInit |> treeTo "foo" |> show
But this doesn't allow to move focus from root to Leaf "baz" and doesn't allow to modify it, so let's add more functions (note that all our zipper functions can crash, we'll change this soon):
(!!) : List a -> Int -> a
xs !! i = case List.tail xs of
Nothing -> Debug.crash "index out of bounds"
Just xs' -> if i == 0
then case List.head xs of Just x -> x
else xs' !! (i-1)
treeToIndex : Int -> Zipper state -> Zipper state
treeToIndex i (Branch subtrees, bs) =
(subtrees!!i, Crumb (List.take i subtrees) (List.drop (i+1) subtrees)::bs)
treeReplace : state -> Zipper state -> Zipper state
treeReplace new (Leaf old, bs) = (Leaf new, bs)
main = tree |> treeInit |> treeToIndex 2 |> treeTo "baz" |> treeReplace "xyzzy" |> show
This whole chain of functions can crash easily if there is an index bigger than the branch size, or you try to go up from the root, and so on. Instead we should wrap the results in Maybe, so that instead of a crash, Nothing is returned. But how do we chain functions, now that they return Maybe (Zipper state), while they still accept Zipper state? This is where you use andThen, which has the type Maybe a -> (a -> Maybe b) -> Maybe b. Full code of your zipper below:
import Graphics.Element exposing (show)
import Maybe exposing (andThen)
type Tree state = Branch (List (Tree state)) | Leaf state
-- Crumb contains 2 lists:
-- leafs/branches to the left of your focus
-- leafs/branches to the right of your focus
type Crumb state = Crumb (List (Tree state)) (List (Tree state))
type alias Zipper state = (Tree state, List (Crumb state))
tree : Tree String
tree = Branch [Leaf "foo",Leaf "bar",Branch [Leaf "baz",Branch [],Leaf "qux"]]
break : (a -> Bool) -> List a -> (List a, List a)
break p xs = case (List.head xs, List.tail xs) of
(Nothing, Nothing) -> ([], [])
(Just x, Just xs') -> if p x
then ([], xs)
else let (ys,zs) = break p xs'
in (x::ys,zs)
treeInit : Tree state -> Zipper state
treeInit t = (t, [])
treeUp : Zipper state -> Maybe (Zipper state)
treeUp (subtree, bs) = case bs of
[] -> Nothing
Crumb l r::bs' -> Just (Branch <| l++[subtree]++r, bs')
treeTo : state -> Zipper state -> Maybe (Zipper state)
treeTo name node = case node of
(Branch subtrees, bs) ->
let (l, x::r) = break (\(Leaf name') -> name == name') subtrees
in Just (x, Crumb l r::bs)
_ -> Nothing
(!!) : List a -> Int -> Maybe a
xs !! i = case List.tail xs of
Nothing -> Nothing
Just xs' -> if i == 0
then List.head xs
else xs' !! (i-1)
treeToIndex : Int -> Zipper state -> Maybe (Zipper state)
treeToIndex i (Branch subtrees, bs) =
let newTree = subtrees!!i
in case newTree of
Nothing -> Nothing
Just newTree ->
let newCrumb = Crumb (List.take i subtrees) (List.drop (i+1) subtrees)
in Just (newTree, newCrumb::bs)
treeReplace : state -> Zipper state -> Maybe (Zipper state)
treeReplace new node = case node of
(Leaf old, bs) -> Just (Leaf new, bs)
_ -> Nothing
-- the function you're interested in most likely
treeUpdate : (state -> state) -> Zipper state -> Maybe (Zipper state)
treeUpdate f node = case node of
(Leaf name, bs) -> Just (Leaf (f name), bs)
_ -> Nothing
main = (tree |> treeInit |> treeToIndex 2)
`andThen` treeTo "baz" `andThen` treeReplace "xyzzy"
`andThen` treeUp `andThen` treeUp |> show
(Feel absolutely free to ask questions and clarifications, and I will update and improve this answer)
What you want is a zipper. Does everything you ask for in terms of
specifying a unique location in the tree
allowing modifications to the focus while preserving the rest.
easy reassembly of the tree.
If you want to bundle modifications with the precise location, then you just have to build a type which includes the zipper and the action.
There's a good section on zippers in Learn You a Haskell.
Once you understand the concept, it's easily applicable to many other datastructures.
It turns out that zippers allow one to achieve this. I will walkthrough the solution.
Using the following zipper
type alias Crumb a =
{ left : List (Tree a)
, right : List (Tree a)
}
type alias Zipper a = (Tree a, List (Crumb a))
One merely needs to implement the following functions
zipperMap : (Zipper a -> a -> b) -> Tree a -> Tree b
zipperUpdate : Zipper a -> (a -> a) -> Tree a -> Tree a
These can be implemented as follows
zipperMap : (Zipper a -> a -> b) -> Tree a -> Tree b
zipperMap f tree =
let
applyZipper ((subtree, crumbs) as zipper) =
case subtree of
Leaf a ->
Leaf (f zipper a)
Branch subtrees ->
subtrees
|> List.indexedMap (\index _ -> gotoIndex index zipper |> Maybe.map applyZipper)
|> keepJusts
|> Branch
in
applyZipper (fromTree tree)
zipperUpdate : Zipper a -> (a -> a) -> Tree a -> Tree a
zipperUpdate zipper f tree =
zipperMap (\z a -> if z == zipper then f a else a) tree
Where keepJusts is filters out the nothings from a list of maybes
keepJusts : List (Maybe a) -> List a
and gotoIndex goes to the nth subtree in a zipper
gotoIndex : Int -> Zipper a -> Maybe (Zipper a)
gotoIndex index (tree, bs) =
case tree of
Leaf _ ->
Nothing
Branch subtrees ->
case nth index subtrees of
Nothing ->
Nothing
Just newTree ->
let
newCrumb =
{ left = List.take index subtrees
, right = List.drop (index + 1) subtrees
}
in
Just (newTree, newCrumb :: bs)
Now, given the functions zipperMap and zipperUpdate we can apply these on our state.
Let us assume that the actions on the trees are represented as follows
type Action action state
= ChildAction (Zipper state) action
We can implement our update function as follows
update : (action -> state -> state)
-> Action action state
-> Tree state
-> Tree state
update updateChild action state =
case action of
ChildAction zipper childAction ->
zipperUpdate zipper (updateChild childAction) state
And we can implement our view function as follows
view : (Address action -> state -> Html)
-> Address (Action action state)
-> Tree state
-> Html
view viewChild address state =
let
viewZ zipper child =
let
childAddress =
Signal.forwardTo address (ChildAction zipper)
in
viewChild childAddress child
in
state
|> zipperMap viewZ
|> toList
|> div []
Where toList converts a tree to a list. While this is just an example, it helps illustrate how one can work with such things.
For more detail, you can see a fully functioning example here
Ok, I have written a binary search tree in OCaml.
type 'a bstree =
|Node of 'a * 'a bstree * 'a bstree
|Leaf
let rec insert x = function
|Leaf -> Node (x, Leaf, Leaf)
|Node (y, left, right) as node ->
if x < y then
Node (y, insert x left, right)
else if x > y then
Node (y, left, insert x right)
else
node
I guess the above code does not have problems.
When using it, I write
let root = insert 4 Leaf
let root = insert 5 root
...
Is this the correct way to use/insert to the tree?
I mean, I guess I shouldn't declare the root and every time I again change the variable root's value, right?
If so, how can I always keep a root and can insert a value into the tree at any time?
This looks like good functional code for inserting into a tree. It doesn't mutate the tree during insertion, but instead it creates a new tree containing the value. The basic idea of immutable data is that you don't "keep" things. You calculate values and pass them along to new functions. For example, here's a function that creates a tree from a list:
let tree_of_list l = List.fold_right insert l Leaf
It works by passing the current tree along to each new call to insert.
It's worth learning to think this way, as many of the benefits of FP derive from the use of immutable data. However, OCaml is a mixed-paradigm language. If you want to, you can use a reference (or mutable record field) to "keep" a tree as it changes value, just as in ordinary imperative programming.
Edit:
You might think the following session shows a modification of a variable x:
# let x = 2;;
val x : int = 2
# let x = 3;;
val x : int = 3
#
However, the way to look at this is that these are two different values that happen to both be named x. Because the names are the same, the old value of x is hidden. But if you had another way to access the old value, it would still be there. Maybe the following will show how things work:
# let x = 2;;
val x : int = 2
# let f () = x + 5;;
val f : unit -> int = <fun>
# f ();;
- : int = 7
# let x = 8;;
val x : int = 8
# f ();;
- : int = 7
#
Creating a new thing named x with the value 8 doesn't affect what f does. It's still using the same old x that existed when it was defined.
Edit 2:
Removing a value from a tree immutably is analogous to adding a value. I.e., you don't actually modify an existing tree. You create a new tree without the value that you don't want. Just as inserting doesn't copy the whole tree (it re-uses large parts of the previous tree), so deleting won't copy the whole tree either. Any parts of the tree that aren't changed can be re-used in the new tree.
Edit 3
Here's some code to remove a value from a tree. It uses a helper function that adjoins two trees that are known to be disjoint (furthermore all values in a are less than all values in b):
let rec adjoin a b =
match a, b with
| Leaf, _ -> b
| _, Leaf -> a
| Node (v, al, ar), _ -> Node (v, al, adjoin ar b)
let rec delete x = function
| Leaf -> Leaf
| Node (v, l, r) ->
if x = v then adjoin l r
else if x < v then Node (v, delete x l, r)
else Node (v, l, delete x r)
(Hope I didn't just spoil your homework!)
I've run into a small problem here. I wrote the Tortoise and Hare cycle detection algorithm.
type Node =
| DataNode of int * Node
| LastNode of int
let next node =
match node with
|DataNode(_,n) -> n
|LastNode(_) -> failwith "Error"
let findCycle(first) =
try
let rec fc slow fast =
match (slow,fast) with
| LastNode(a),LastNode(b) when a=b -> true
| DataNode(_,a), DataNode(_,b) when a=b -> true
| _ -> fc (next slow) (next <| next fast)
fc first <| next first
with
| _ -> false
This is working great for
let first = DataNode(1, DataNode(2, DataNode(3, DataNode(4, LastNode(5)))))
findCycle(first)
It shows false. Right. Now when try to test it for a cycle, I'm unable to create a loop!
Obviously this would never work:
let first = DataNode(1, DataNode(2, DataNode(3, DataNode(4, first))))
But I need something of that kind! Can you tell me how to create one?
You can't do this with your type as you've defined it. See How to create a recursive data structure value in (functional) F#? for some alternative approaches which would work.
As an alternative to Brian's solution, you might try something like:
type Node =
| DataNode of int * NodeRec
| LastNode of int
and NodeRec = { node : Node }
let rec cycle = DataNode(1, { node =
DataNode(2, { node =
DataNode(3, { node =
DataNode(4, { node = cycle}) }) }) })
Here is one way:
type Node =
| DataNode of int * Lazy<Node>
| LastNode of int
let next node = match node with |DataNode(_,n) -> n.Value |LastNode(_) -> failwith "Error"
let findCycle(first) =
try
let rec fc slow fast =
match (slow,fast) with
| LastNode(a),LastNode(b) when a=b->true
| DataNode(a,_), DataNode(b,_) when a=b -> true
| _ -> fc (next slow) (next <| next fast)
fc first <| next first
with
| _ -> false
let first = DataNode(1, lazy DataNode(2, lazy DataNode(3, lazy DataNode(4, lazy LastNode(5)))))
printfn "%A" (findCycle(first))
let rec first2 = lazy DataNode(1, lazy DataNode(2, lazy DataNode(3, lazy DataNode(4, first2))))
printfn "%A" (findCycle(first2.Value))
Even though both Brian and kvb posted answers that work, I still felt I needed to see if it was possible to achieve the same thing in a different way. This code will give you a cyclic structure wrapped as a Seq<'a>
type Node<'a> = Empty | Node of 'a * Node<'a>
let cyclic (n:Node<_>) : _ =
let rn = ref n
let rec next _ =
match !rn with
| Empty -> rn := n; next Unchecked.defaultof<_>
| Node(v, x) -> rn := x; v
Seq.initInfinite next
let nodes = Node(1, Node(2, Node(3, Empty)))
cyclic <| nodes |> Seq.take 40 // val it : seq<int> = seq [1; 2; 3; 1; ...]
The structure itself is not cyclic, but it looks like it from the outside.
Or you could do this:
//removes warning about x being recursive
#nowarn "40"
type Node<'a> = Empty | Node of 'a * Lazy<Node<'a>>
let rec x = Node(1, lazy Node(2, lazy x))
let first =
match x with
| Node(1, Lazy(Node(2,first))) -> first.Value
| _ -> Empty
Can you tell me how to create one?
There are various hacks to get a directly cyclic value in F# (as Brian and kvb have shown) but I'd note that this is rarely what you actually want. Directly cyclic data structures are a pig to debug and are usually used for performance and, therefore, made mutable.
For example, your cyclic graph might be represented as:
> Map[1, 2; 2, 3; 3, 4; 4, 1];;
val it : Map<int,int> = map [(1, 2); (2, 3); (3, 4); (4, 1)]
The idiomatic way to represent a graph in F# is to store a dictionary that maps from handles to vertices and, if necessary, another for edges. This approach is much easier to debug because you traverse indirect recursion via lookup tables that are comprehensible as opposed to trying to decipher a graph in the heap. However, if you want to have the GC collect unreachable subgraphs for you then a purely functional alternative to a weak hash map is apparently an unsolved problem in computer science.
How should I go about removing a given element from a list? As an example, say I have list ['A'; 'B'; 'C'; 'D'; 'E'] and want to remove the element at index 2 to produce the list ['A'; 'B'; 'D'; 'E']? I've already written the following code which accomplishes the task, but it seems rather inefficient to traverse the start of the list when I already know the index.
let remove lst i =
let rec remove lst lst' =
match lst with
| [] -> lst'
| h::t -> if List.length lst = i then
lst' # t
else
remove t (lst' # [h])
remove lst []
let myList = ['A'; 'B'; 'C'; 'D'; 'E']
let newList = remove myList 2
Alternatively, how should I insert an element at a given position? My code is similar to the above approach and most likely inefficient as well.
let insert lst i x =
let rec insert lst lst' =
match lst with
| [] -> lst'
| h::t -> if List.length lst = i then
lst' # [x] # lst
else
insert t (lst' # [h])
insert lst []
let myList = ['A'; 'B'; 'D'; 'E']
let newList = insert myList 2 'C'
Removing element at the specified index isn't a typical operation in functional programming - that's why it seems difficult to find the right implementation of these operations. In functional programming, you'll usually process the list element-by-element using recursion, or implement the processing in terms of higher-level declarative operations. Perhaps if you could clarfiy what is your motivation, we can give a better answer.
Anyway, to implement the two operations you wanted, you can use existing higher-order functions (that traverse the entire list a few times, because there is really no good way of doing this without traversing the list):
let removeAt index input =
input
// Associate each element with a boolean flag specifying whether
// we want to keep the element in the resulting list
|> List.mapi (fun i el -> (i <> index, el))
// Remove elements for which the flag is 'false' and drop the flags
|> List.filter fst |> List.map snd
To insert element to the specified index, you could write:
let insertAt index newEl input =
// For each element, we generate a list of elements that should
// replace the original one - either singleton list or two elements
// for the specified index
input |> List.mapi (fun i el -> if i = index then [newEl; el] else [el])
|> List.concat
However, as noted earlier - unless you have a very good reasons for using these functions, you should probably consider describing your goals more broadly and use an alternative (more functional) solution.
Seems the most idiomatic (not tail recursive):
let rec insert v i l =
match i, l with
| 0, xs -> v::xs
| i, x::xs -> x::insert v (i - 1) xs
| i, [] -> failwith "index out of range"
let rec remove i l =
match i, l with
| 0, x::xs -> xs
| i, x::xs -> x::remove (i - 1) xs
| i, [] -> failwith "index out of range"
it seems rather inefficient to
traverse the start of the list when I
already know the index.
F# lists are singly-linked lists, so you don't have indexed access to them. But most of the time, you don't need it. The majority of indexed operations on arrays are iteration from front to end, which is exactly the most common operation on immutable lists. Its also pretty common to add items to the end of an array, which isn't really the most efficient operation on singly linked lists, but most of the time you can use the "cons and reverse" idiom or use an immutable queue to get the same result.
Arrays and ResizeArrays are really the best choice if you need indexed access, but they aren't immutable. A handful of immutable data structures like VLists allow you to create list-like data structures supporting O(1) cons and O(log n) indexed random access if you really need it.
If you need random access in a list, consider using System.Collections.Generic.List<T> or System.Collections.Generic.LinkedList<T> instead of a F# list.
I know this has been here for a while now, but just had to do something like this recently and I came up with this solution, maybe it isn't the most efficient, but it surely is the shortest idiomatic code I found for it
let removeAt index list =
list |> List.indexed |> List.filter (fun (i, _) -> i <> index) |> List.map snd
The List.Indexed returns a list of tuples which are the index in the list and the actual item in that position after that all it takes is to filter the one tuple matching the inputted index and get the actual item afterwards.
I hope this helps someone who's not extremely concerned with efficiency and wants brief code
The following includes a bit of error checking as well
let removeAt index = function
| xs when index >= 0 && index < List.length xs ->
xs
|> List.splitAt index
|> fun (x,y) -> y |> List.skip 1 |> List.append x
| ys -> ys
Lets go thru it and explain the code
// use the function syntax
let removeAt index = function
// then check if index is within the size of the list
| xs when index >= 0 && index < List.length xs ->
xs
// split the list before the given index
// splitAt : int -> 'T list -> ('T list * 'T list)
// this gives us a tuple of the the list with 2 sublists
|> List.splitAt index
// define a function which
// first drops the element on the snd tuple element
// then appends the remainder of that sublist to the fst tuple element
// and return all of it
|> fun (x,y) -> y |> List.skip 1 |> List.append x
//index out of range so return the original list
| ys -> ys
And if you don't like the idea of simply returning the original list on indexOutOfRange - wrap the return into something
let removeAt index = function
| xs when index >= 0 && index < List.length xs ->
xs
|> List.splitAt index
|> fun (x,y) -> y |> List.skip 1 |> List.append x
|> Some
| ys -> None
I think this should be quite faster than Juliet's or Tomas' proposal but most certainly Mauricio's comment is hitting it home. If one needs to remove or delete items other data structures seem a better fit.