I have a simple tree structure like this..
type Tree<'a,'b> =
| Node of list<'a * Tree<'a,'b>>
| Leaf of 'b
let phonebook = Node["MyPhonebook",
Node["Work",
Node["Company1", Node["Employee1", Leaf("phone#")];
"Company2", Leaf("phone#")];
"Private",
Node["Family", Node["Brother", Leaf("phone#");]; "Sister", Leaf("phone#")]
]
]
Im simply trying to print root folders (Work, Private) of this phone book but cant seem to get it right whatever I do...
let listelements tree =
match tree with
| Node[a, b] -> // OK - root node
printfn "%s" a // OK - root folder name
match b with
//| _ -> printf "%A" b // OK - prints whole node
| Node[a, b] -> printf "%A" a // Match failure!
listelements phonebook
After that I realized I've been matching tuple with list so I tried something a bit different but i get missmatches again.
let phonebook = [Node["Work",
Node["Company1", Node["Employee1", Leaf("phone#")];
"Company2", Leaf("phone#")];
"Private",
Node["Family", Node["Brother", Leaf("phone#");]; "Sister", Leaf("phone#")]
]
]
let listelements tree =
for i in tree do
match i with
| Node[a, b] -> printf "%s" a // Match fail
let listelements tree =
//tree |> List.iter (fun x -> printf "%A" x) // OK - prints nodes
tree |> List.iter (fun x ->
match x with
| Node[a, b] -> printf "%A" a) // Match fail
What the hell am I doing wrong here? There has to be a more elegant and simple way to do this. I come from C# and this is driving me insane :P
You are matching a list of a single element (a tuple) against a List, so in the first case the list contains only one element and it pass though the compiler warns you that the matching is incomplete.
But in the second match the list contains two tuples, so it fails.
Use instead a head::tail pattern, like this:
| Node((a, b)::xs)
or if you are not interested in the tail at all:
| Node((a, b)::_)
NOTE
Something that will help to clarify your code: tree is a list of tuples as from the definition. It's better if you write the pattern making the parenthesis of the tuple explicit, I mean if you write:
| Node[(a, b)] ->
instead of just
| Node[a, b] ->
Here the compiler understand that is a tuple, but a human may not, especially if it comes from a Haskell background.
So, writing the parenthesis will probably help you to figure out that the problem is that you are matching agains a list with only one tuple.
UPDATE
If you want to print all elements using List.iter:
let rec listelements tree =
let printNode (a, b) =
printfn "%s" a
listelements b
match tree with
| Leaf leaf -> printfn "Leaf %s" leaf
| Node(listOfNodes) -> List.iter printNode listOfNodes
Related
I have the following Discriminated Union (DU) declaration:
type Book =
| Dictionary of string[]
| Novel of int[]
| Comics of bool[]
An example:
let x = Dictionary [|"a"; "b"|]
How can I extract the length of the array inside without doing pattern matching and without caring about the data type of the array (in this case: string, int, bool). Note: I have no control over the DU declaration; as a result, I can't write new member method within Book, like getArrayLength()
Of course, we can do it in some way as followed:
match x with
| Dictionary (x: _[]) -> x |> Array.length
| Novel (x: _[]) -> x |> Array.length
| Comics (x: _[]) -> x |> Array.length
But typing x |> Array.length a lot is incovenient. This is a simple example, but we can think of a general problem:
type Animal =
| Dog of DogClass
| Cat of CatClass
| Cow of CowClass
...
... and DogClass, CatClass, etc. may share something. We want to get that shared thing. E.g. those classes inherit from AnimalClass, within which there is countLegs() method. Suppsed there are many animals, pattern matching for all of them while the code block after -> is almost the same. I love the principle DRY (Don't Repeat Yourself).
Is there any convenient way to tackle such problem?
==
EDITED 21.10.2019
I was also looking for some syntax like:
let numEles =
match x with
| _ (arr: _[]) -> x |> Array.Length
| _ -> failwith "No identifiers with fields as Array."
let numLegs =
match anAnimall with
| _ (animal: ?> Animal) -> animal.countLegs()
| _ -> failwith "Can't count legs because of not being an animal."
I think this still follows the spirit of matching, but seem like this approach is not supported.
Realistically, there's no getting around pattern matching here. DUs were, in a way, built for it. Since you don't control the type, you can always add a type extension:
type Book with
member this.Length =
match this with
| Dictionary d -> d.Length
| Novel n -> n.Length
| Comics c -> c.Length
let x = Dictionary [|"a"; "b"|]
printfn "%d" x.Length // Prints 2
Though it's also equally valid to define a Book module with a length function on it if you prefer that:
module Book =
let length b =
match b with
| Dictionary d -> d.Length
| Novel n -> n.Length
| Comics c -> c.Length
let x = Dictionary [|"a"; "b"|]
printfn "%d" (x |> Book.length) // prints 2
But you'll need to write a pattern match expression on the Book type at least once. The fact that every case is made up of data that all has the same property doesn't really help the fact that you need to still identify every case individually.
I'm trying to write a tail-recursion function that will look at a list of distinct words, a list of all words, and return a list with the count of occurrences of each word. I'm actually reading the words out of files in a directory, but I can't seem to get the tail-recursion to compile. This is what I have so far:
let countOccurence (word:string) list =
List.filter (fun x -> x.Equals(word)) list
//(all words being a list of all words across several files)
let distinctWords = allWords |> Seq.distinct
let rec wordCloud distinct (all:string list) acc =
match distinct with
| head :: tail -> wordCloud distinct tail Array.append(acc, (countOccurence head all)) //<- What am I doing with my life?
| [] -> 0
I realize this is probably a fairly straightforward question, but I've been banging my head for an hour on this final piece of the puzzle. Any thoughts?
There are several issues with the statement as given:
Use of Array.append to manipulate lists
Typos
Incorrect use of whitespace to group things together
Try expressing the logic as a series of steps instead of putting everything into a single, unreadable line of code. Here's what I did to understand the problems with the above expression:
let rec wordCloud distinct (all:string list) acc =
match distinct with
| head :: tail ->
let count = countOccurence head all
let acc' = acc |> List.append count
wordCloud distinct tail acc'
| [] -> 0
This compiles, but I don't know if it does what you want it to do...
Notice the replacement of Array.append with List.append.
This is still tail recursive, since the call to wordCloud sits in the tail position.
After several hours more work, I came up with this:
let countOccurance (word:string) list =
let count = List.filter (fun x -> word.Equals(x)) list
(word, count.Length)
let distinctWords = allWords |> Seq.distinct |> Seq.toList
let print (tup:string*int) =
match tup with
| (a,b) -> printfn "%A: %A" a b
let rec wordCloud distinct (all:string list) (acc:(string*int) list) =
match distinct with
| [] -> acc
| head :: tail ->
let accumSoFar = acc # [(countOccurance head all)]
wordCloud tail all accumSoFar
let acc = []
let cloud = (wordCloud distinctWords allWords acc)
let rec printTup (tupList:(string*int) list) =
match tupList with
| [] -> 0
| head :: tail ->
printfn "%A" head
printTup tail
printTup cloud
This problem actually has a pretty straightforward solution, if you take a step back and simply type in what you want to do.
/// When you want to make a tag cloud...
let makeTagCloud (words: string list) =
// ...take a list of all words...
words
// ...then walk along the list...
|> List.fold (fun cloud word ->
// ...and check if you've seen that word...
match cloud |> Map.tryFind word with
// ...if you have, bump the count...
| Some count -> cloud |> Map.add word (count+1)
// ...if not, add it to the map...
| None -> cloud |> Map.add word 1) Map.empty
// ...and change the map back into a list when you are done.
|> Map.toList
Reads like poetry ;)
I have a list :
[objA;objB;objC;objD]
I need to do the following reduction :
obj -> obj -> obj
ie :
objA objB -> objB'
and then take back the original list so that I get :
[objB';objC;objD]
I am trying to do the following :
let rec resolveConflicts = function
| [] -> []
| [c] -> resolveConflict c
| [x;y] -> resolveConflict x
|> List.filter getMovesRelatedtoY
|> List.append y
|> resolveConflict
| [x;y::tail] ->
let y' = resolveConflict x
|> List.filter getMovesRelatedtoY
|> List.append y
resolveConflicts y'::tail
This syntax is not correct, may be I am not even using the correct tool... I am open to any well suited solution so that I can learn.
As to why, I filter the list and append one to another, it is just that every conflict is a list of moves.
To match first element, second element and the rest of the list, use this pattern:
| fst::snd::rest ->
You can match any constant number of first elements using this styling:
| fst::snd::thrd:: ... ::rest ->
I'm trying to solve tasks from 99 Haskell problems in F#.
The task #7 looks pretty simple, and the solution can be found in lots of places. Except the fact that the first several solutions that I've tried and found by googling (e.g. https://github.com/paks/99-FSharp-Problems/blob/master/P01to10/Solutions.fs) are wrong.
My example is pretty simple.
I'm trying to build extremely deep nested structure and fold it
type NestedList<'a> =
| Elem of 'a
| NestedList of NestedList<'a> list
let flatten list =
//
(* StackOverflowException
| Elem(a) as i -> [a]
| NestedList(nest) -> nest |> Seq.map myFlatten |> List.concat
*)
// Both are failed with stackoverflowexception too https://github.com/paks/99-FSharp-Problems/blob/master/P01to10/Solutions.fs
let insideGen count =
let rec insideGen' count agg =
match count with
| 0 -> agg
| _ ->
insideGen' (count-1) (NestedList([Elem(count); agg]))
insideGen' count (Elem(-1))
let z = insideGen 50000
let res = flatten z
I've tried to rewrite solution in CPS style, but eiter I'm doing something wrong or look into incorrect direction - everything that I've tried isn't working.
Any advices?
p.s. Haskell solution, at least on nested structure with 50000 nested levels is working slowly, but without stack overflow.
Here's a CPS version that doesn't overflow using your test.
let flatten lst =
let rec loop k = function
| [] -> k []
| (Elem x)::tl -> loop (fun ys -> k (x::ys)) tl
| (NestedList xs)::tl -> loop (fun ys -> loop (fun zs -> k (zs # ys)) xs) tl
loop id [lst]
EDIT
A much more readable way to write this would be:
let flatten lst =
let results = ResizeArray()
let rec loop = function
| [] -> ()
| h::tl ->
match h with
| Elem x -> results.Add(x)
| NestedList xs -> loop xs
loop tl
loop [lst]
List.ofSeq results
Disclaimer - I'm not a deep F# programmer and this will not be idiomatic.
If your stack is overflowing, it means that you don't have a tail recursive solution. It also means that you are choosing to use stack memory for state. Traditionally, you want to exchange heap memory for stack memory since heap memory is in comparatively large supply. So the trick is to model a stack.
I'm going to define a virtual machine that is a stack. Each stack element will be a state nugget for traversing a list which will include the list and a program counter, which is the current element to examine and will be a tuple of a NestedList<'a> list * int. The list is the current list being traversed. The int is the current position in the list.
type NestedList<'a> =
| Elem of 'a
| Nested of NestedList<'a> list
let flatten l =
let rec listMachine instructions result =
match instructions with
| [] -> result
| (currList, currPC) :: tail ->
if currPC >= List.length currList then listMachine tail result
else
match List.nth currList currPC with
| Elem(a) -> listMachine ((currList, currPC + 1 ) :: tail) (result # [ a ])
| Nested(l) -> listMachine ((l, 0) :: (currList, currPC + 1) :: instructions.Tail) result
match l with
| Elem(a) -> [ a ]
| Nested(ll) -> listMachine [ (ll, 0) ] []
What have I done? I've written a tail-recursive function that operates of "Little Lisper" style code - if my instruction list is empty, return my accumulated result. If not, operate on the top of the stack. I bind a convenience variable to the top and if the PC is at the end, I recurse on the tail of the stack (pop) with the current result. Otherwise, I look at the current element in the list. If it's an Elem, I recurse, advancing the PC and appending the Elem onto the list. If it's not an elem, I recurse, by pushing a new stack with the NestedList followed by the current stack elem with the PC advanced by 1 and everything else.
Suppose I have the following code:
type Vehicle =
| Car of string * int
| Bike of string
let xs = [ Car("family", 8); Bike("racing"); Car("sports", 2); Bike("chopper") ]
I can filter above list using incomplete pattern matching in an imperative for loop like:
> for Car(kind, _) in xs do
> printfn "found %s" kind;;
found family
found sports
val it : unit = ()
but it will cause a:warning FS0025: Incomplete pattern matches on this expression. For example, the value 'Bike (_)' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.
As the ignoring of unmatched elements is my intention, is there a possibility to get rid of this warning?
And is there a way to make this work with list-comprehensions without causing a MatchFailureException? e.g. something like that:
> [for Car(_, seats) in xs -> seats] |> List.sum;;
val it : int = 10
Two years ago, your code was valid and it was the standard way to do it. Then, the language has been cleaned up and the design decision was to favour the explicit syntax. For this reason, I think it's not a good idea to ignore the warning.
The standard replacement for your code is:
for x in xs do
match x with
| Car(kind, _) -> printfn "found %s" kind
| _ -> ()
(you could also use high-order functions has in pad sample)
For the other one, List.sumBy would fit well:
xs |> List.sumBy (function Car(_, seats) -> seats | _ -> 0)
If you prefer to stick with comprehensions, this is the explicit syntax:
[for x in xs do
match x with
| Car(_, seats) -> yield seats
| _ -> ()
] |> List.sum
You can silence any warning via the #nowarn directive or --nowarn: compiler option (pass the warning number, here 25 as in FS0025).
But more generally, no, the best thing is to explicitly filter, as in the other answer (e.g. with choose).
To explicitly state that you want to ignore unmatched cases, you can use List.choose and return None for those unmatched elements. Your codes could be written in a more idomatic way as follows:
let _ = xs |> List.choose (function | Car(kind, _) -> Some kind
| _ -> None)
|> List.iter (printfn "found %s")
let sum = xs |> List.choose (function | Car(_, seats)-> Some seats
| _ -> None)
|> List.sum