Given the following types:
type Title = string
type Document = Title * Element list
and Element = Par of string | Sec of Document
I'm attempting to create a function which will traverse the tree and count the number of occurrences of Sec.
Given the following example:
let s1 = ("section 1", [Par "Bla"])
let s2 = ("section 2", [Sec s21; Par "Bla"])
let s21 = ("subsection 2.1", [Par "Bla"])
let s3 = ("section 3", [Par "Bla"])
let doc = ("Compiler project", [Par "Bla"; Sec s1; Sec s2; Sec s3]);
A function taking a Document to count number of Sections, noOfSecs d would in this case return 4, as there are 4 Sections in this case. I've attempted something, but I'm a little stuck, especially what to do when I hit a Par:
let rec noOfSecs d =
match d with
| (_,[]) -> 0
| (_,e::es) -> (findSecs e)
and findSecs = function
| Sec(t,_::es) -> 1 + noOfSecs (t,es)
| Par p -> //What should we do here?
There are 0 Secs within a Par string so you can return 0 for that case. In noOfSecs you need to sum the Sec cases for each element in the element list, not just the first one. You can use List.sumBy for this:
let rec noOfSecs (_, elems) =
List.sumBy findSecs elems
and findSecs = function
| Sec d -> 1 + noOfSecs d
| Par p -> 0
Related
I have a csv file containing daily weights as follows:
Date,Name,Weight
11-Sep-2017,Alpha,9-1
13-Sep-2017,Alpha,8-13
15-Sep-2017,Alpha,8-11
Though I can successfully import them using CsvProvider, the weight column defaults to System.DateTime.
// Weight
[<Measure>] type lb
[<Literal>]
let input = "DayWeights.csv"
type Weights = CsvProvider<input, HasHeaders=true>
let data = Weights.GetSample()
for row in data.Rows do
printfn "Output: (%A, %A, %A)" row.Date row.Name row.Weight
Is it possible to create a Unit of Measure (UoM) to define "stlb" with the option to convert to lbs on import and, if so, how?
I don't think you could represent stones-pounds as a single numeric type, and units of measure can only be used on numeric types (although there is some discussion about changing this in future). This is because some of their features only make sense with numeric operations like addition and multiplication. The units themselves are multiplied and divided:
[<Measure>] type lb
2<lb> + 2<lb> // 4<lb>
2<lb> * 2<lb> // 4<lb ^ 2>
2<lb> / 2<lb> // 1
Instead of units of measure, if you want some kind of tag to know that a given value has a type of stones-pounds, you could create a single case discriminated union:
type StonesPounds = StonesPounds of int * int
// StonesPounds -> int<lb>
let convertToLb (StonesPounds (s, p)) = (s * 14 + p) * 1<lb>
StonesPounds (1, 2) |> convertToLb // 16<lb>
The downside of this compared to units of measure is that you have to manually pack and unpack these values in code before you can use the numbers and there is a runtime cost for that too.
I resolved the automatic converting of the input weight column to System.DateTime as follows:
// http://fssnip.net/27
let lazySplit (sep:string) (str:string) =
match sep, str with
| ((null | ""), _) | (_, (null | "")) -> seq [str]
| _ ->
let n, j = str.Length, sep.Length
let rec loop p =
seq {
if p < n then
let i = match str.IndexOf(sep, p) with -1 -> n | i -> i
yield str.Substring(p, i - p)
yield! loop (i + j)
}
loop 0
let weight input =
input
|> (fun x -> lazySplit "/" x |> Seq.take 2 |> String.concat("-"))
let data = Weighings.GetSample()
for row in data.Rows do
let stlbs = weight (string row.Weight)
printfn "Output: (%A, %A, %A)" row.Date row.Name stlbs
// Output: 11-Sep-2017,"Alpha","09-01")
Thanks to one and all for your expert help and guidance.
I mainly work in C# and am new to F#/function languages and I'm having a problem with a pretty simple program.
I have a function that creates a record with two integer fields. The fields are chosen System.Random.NextDouble inside a match to align with certain probabilities. I then have a for loop that should run the createCustomer function four times.
The problem I'm having is that the Customer is the same for all 10 iterations of the for loop and the printfn inside of getIATime only seems to execute once.
Program.fs
open Simulation
[<EntryPoint>]
let main argv =
printfn "%A" argv
printfn "Test"
for i in 1 .. 10 do
let mutable customer = createCustomer
printfn "i: %d\tIA: %d\tService: %d" i customer.interArrivalTime customer.serviceTime
ignore (System.Console.ReadLine()) //Wait for keypress # the end
0 // return an integer exit code
Simulation.fs
module Simulation
type Customer = {
interArrivalTime: int
serviceTime: int
}
let createCustomer =
let getRand =
let random = new System.Random()
fun () -> random.NextDouble()
let getIATime rand =
printf "Random was: %f\n" rand
match rand with
| rand when rand <= 0.09 -> 0
| rand when rand <= 0.26 -> 1
| rand when rand <= 0.53 -> 2
| rand when rand <= 0.73 -> 3
| rand when rand <= 0.88 -> 4
| rand when rand <= 1.0 -> 5
let getServiceTime rand =
match rand with
| rand when rand <= 0.2 -> 1
| rand when rand <= 0.6 -> 2
| rand when rand <= 0.88 -> 3
| rand when rand <= 1.0 -> 4
{interArrivalTime = getIATime (getRand()); serviceTime = getServiceTime (getRand())}
Your getCustomer is not a function, but a value. Its body is executed only once during program initialization, and the result is stored in a field, which can then be accessed. When you think that you "call" the function, you actually merely reference the value. No calling is going on, because there is nothing to call.
To make getCustomer a function, give it a parameter. This is how functions differ from values in F#: if you have a parameter, you're a function; if not - you're a value. Since there is no actual data that you'd want to pass to the function, you can give it a "dummy" ("placeholder") parameter of type unit. This type has exactly one value, and that value is written as ():
let createCustomer () =
let getRand =
let random = new System.Random()
fun () -> random.NextDouble()
...
Then call it like this:
for i in 1 .. 10 do
let mutable customer = createCustomer()
printfn "i: %d\tIA: %d\tService: %d" i customer.interArrivalTime customer.serviceTime
I want to build a dictionary from a list of items.
An item has the following definition:
type Item =
| A of TotalPrice * Special
| B of TotalPrice * Special
| C of TotalPrice
| D of TotalPrice
I want the keys of the dictionary to map to the case ids:
| A
| B
| C
| D
I would then have the values for the case id be a list.
How do I separate the case ids from the case values?
Example:
let dictionary = items |> List.map (fun item -> item) // uh...
Appendix:
module Checkout
(*Types*)
type UnitPrice = int
type Qty = int
type Special =
| ThreeForOneThirty
| TwoForFourtyFive
type TotalPrice = { UnitPrice:int ; Qty:int }
type Item =
| A of TotalPrice * Special
| B of TotalPrice * Special
| C of TotalPrice
| D of TotalPrice
(*Functions*)
let totalPrice (items:Item list) =
let dictionary = items |> List.map (fun item -> item) // uh...
0
(*Tests*)
open FsUnit
open NUnit.Framework
[<Test>]
let ``buying 2 A units, B unit, A unit = $160`` () =
// Setup
let items = [A ({UnitPrice=50; Qty=2} , ThreeForOneThirty)
B ({UnitPrice=30; Qty=1} , TwoForFourtyFive)
A ({UnitPrice=50; Qty=1} , ThreeForOneThirty)]
items |> totalPrice |> should equal 160
Your data is badly defined for your use case. If you want to refer to the kinds of items by themselves, you need to define them by themselves:
type ItemKind = A | B | C | D
type Item = { Kind: ItemKind; Price: TotalPrice; Special: Special option }
Then you can easily build a dictionary of items:
let dictionary = items |> List.map (fun i -> i.Kind, i) |> dict
Although I must note that such dictionary may not be possible: if the items list contains several items of the same kind, some of them will not be included in the dictionary, because it can't contain multiple identical keys. Perhaps I didn't understand what kind of dictionary you're after.
If you want to create the dictionary with keys like A, B, C and D you will fail because A and B are constructors with type TotalPrice * Special -> Item and C and D are constructors of type TotalPrice -> Item. Dictionary would have to make a decision about type of keys.
Getting DU constructor name should be doable by reflection but is it really necessary for your case?
Maybe different type structure will be more efficient for your case, ie. Fyodor Soikin proposal.
Maybe the following will clarify somewhat why datastructure and code is no good, and as such also clarify that this mainly is not related to FP as indicated in some of the comments et al.
My guess is that the question is related to "how can this be grouped", and lo and behold, there is in fact a groupBy function!
(*Types*)
type UnitPrice = int
type Qty = int
type Special =
| ThreeForOneThirty
| TwoForFourtyFive
type TotalPrice = { UnitPrice:int ; Qty:int }
type Item =
| A of TotalPrice * Special
| B of TotalPrice * Special
| C of TotalPrice
| D of TotalPrice
let items = [A ({UnitPrice=50; Qty=2} , ThreeForOneThirty)
B ({UnitPrice=30; Qty=1} , TwoForFourtyFive)
A ({UnitPrice=50; Qty=1} , ThreeForOneThirty)]
let speciallyStupidTransformation =
function
| ThreeForOneThirty -> 34130
| TwoForFourtyFive -> 2445
let stupidTransformation =
function
| A (t,s) -> "A" + (s |> speciallyStupidTransformation |> string)
| B (t,s) -> "B" + (s |> speciallyStupidTransformation |> string)
| C (t) -> "C"
| D(t) -> "D"
let someGrouping = items |> List.groupBy(stupidTransformation)
val it : (string * Item list) list =
[("A34130",
[A ({UnitPrice = 50;
Qty = 2;},ThreeForOneThirty); A ({UnitPrice = 50;
Qty = 1;},ThreeForOneThirty)]);
("B2445", [B ({UnitPrice = 30;
Qty = 1;},TwoForFourtyFive)])]
Yeah its still a bad idea. But its somewhat grouped uniquely, and may be misused further to aggregate some sums or whatever.
Adding some more code for that, like the following:
let anotherStupidTransformation =
function
| A(t,_) -> (t.UnitPrice, t.Qty)
| B(t,_) -> (t.UnitPrice, t.Qty)
| C(t) -> (t.UnitPrice, t.Qty)
| D(t) -> (t.UnitPrice, t.Qty)
let x4y x y tp q =
if q%x = 0 then y*q/x else tp/q*(q%x)+(q-q%x)/x*y
let ``34130`` = x4y 3 130
let ``2445`` = x4y 2 45
let getRealStupidTotal =
function
| (s, (tp,q)) ->
(s|> List.ofSeq, (tp,q))
|> function
| (h::t, (tp,q)) ->
match t |> List.toArray |> System.String with
| "34130" -> ``34130`` tp q
| "2445" -> ``2445`` tp q
| _ -> tp
let totalPrice =
items
|> List.groupBy(stupidTransformation)
|> List.map(fun (i, l) -> i,
l
|> List.map(anotherStupidTransformation)
|> List.unzip
||> List.fold2(fun acc e1 e2 ->
((fst acc + e1) * e2, snd acc + e2) ) (0,0))
|> List.map(getRealStupidTotal)
|> List.sum
val totalPrice : int = 160
might or might not yield some test cases correct.
For the above testdata as far as I can read the initial code at least is ok. The sum does get to be 160...
Would I use this code anywhere? Nope.
Is it readable? Nope.
Is it fixable? Not without changing the way the data are structured to avoid several of the stupid transformations...
I am new to F# and have been messing around with records and changing them. I am trying to apply my own function with out using map to my list. This is what i have so far. I am just wondering if my approach for how to write a mapping without using the map function the correct way of thinking about it.
module RecordTypes =
// creation of simple record
// immutable by default - key word mutable allows that to change
type Student =
{
Name : string
mutable age : int
mutable major : string
}
// setting up a few records with student information
// studentFive.age <- studentFive.age + 2 ; example of how to change mutable variable
let studentOne = { Name = "bob" ; age = 20 ; major = "spanish" }
let studentTwo= { Name = "sally" ; age = 18 ; major = "english" }
let studentThree = { Name = "frank" ; age = 22 ; major = "history" }
let studentFour = { Name = "lisa" ; age = 19 ; major = "math" }
let studentFive = { Name = "john" ; age = 17 ; major = "philosophy" }
// placing the records into a lits
let studentList = [studentOne; studentTwo; studentThree ;studentFour; studentFive]
// placing the records into a lits
let studentList = [studentOne; studentTwo; studentThree ;studentFour; studentFive]
// itterate through a list and printing each records
printf "the unsorted list of students: \n"
studentList |> List.iter (fun s-> printf "Name: %s, Age: %d, Major: %s\n" s.Name s.age s.major)
// a sort of the records based on the name, can be sorted by other aspects in the records
let sortStudents alist =
alist
|> List.sortBy (function student -> student.age)
let rec selectionSort = function
| [] -> [] //if the list is empty it will return an empty list
| l -> let min = List.min l in // otherwise set a min variable and use the min function to find the smallest item in a list
let rest = List.filter (fun i -> i <> min) l in // set a variable to hold the rest of the list using filter
// Returns a new collection containing only the elements of the collection for which the given predicate returns true
// fun sets up a lambda expression that if ( i -> i <> (not equal boolean) min) if i(the record is not the min put it into a list)
let sortedList = selectionSort rest in // sort the rest of the list that isnt the min
min :: sortedList // :: is an operator that creates a list, left elem appended to right side
let unsortedList = studentList
let sortedList = selectionSort unsortedList
printfn "sorted list based on first name:\n"
sortedList |> List.iter(fun s -> printf "Name: %s, Age: %d, Major: %s\n" s.Name s.age s.major)
here is where i tried to create my own map with function foo
let foo x = x + 1
let applyOnEachElement (list : Student list) (someFunction) =
list |> List.iter(fun s -> someFunction s.age)
//let agedStudents = applyOnEachElement studentList foo
printf " the students before function is applied to each: \n"
sortedList |> List.iter(fun s -> printf "Name: %s, Age: %d, Major: %s\n" s.Name s.age s.major)
printf " the student after function is applied to each: \n"
agedStudents |> List.iter(fun s -> printf "Name: %s, Age: %d, Major: %s\n" s.Name s.age s.major)
In the last comment, the OP mentions his almost complete solution. With a bit of added formatting and a forgotten match construct, it looks as follows:
let rec applyOnEachElement2 (list: Student list) (f) =
match list with
| [] -> []
| hd :: tl -> hd::applyOnEachElement2 f tl
This is quite close to the correct implementation of map function! There are only two issues:
when calling applyOnEachElement2 recursively, you switched the parameters
the f parameter is passed recursively but never actually used for anything
To fix this, all you need is to switch the order of parameters (I'll do this on the function arguments to get the parameters in the same order as standard map) and call the f function on hd on the last line (so that the function returns a list of transformed elements):
let rec applyOnEachElement2 f (list: Student list) =
match list with
| [] -> []
| hd :: tl -> (f hd)::applyOnEachElement2 f tl
You can also make it generic by dropping the type annotation, which gives you a function with the same type signature as the built in List.map:
let rec applyOnEachElement2 f list =
match list with
| [] -> []
| hd :: tl -> (f hd)::applyOnEachElement2 f tl
First, in order to provide full disclosure, I want to point out that this is related to homework in a Machine Learning class. This question is not the homework question and instead is something I need to figure out in order to complete the bigger problem of creating an ID3 Decision Tree Algorithm.
I need to generate tree similar to the following when given a truth table
let learnedTree = Node(0,"A0", Node(2,"A2", Leaf(0), Leaf(1)), Node(1,"A1", Node(2,"A2", Leaf(0), Leaf(1)), Leaf(0)))
learnedTree is of type BinaryTree which I've defined as follows:
type BinaryTree =
| Leaf of int
| Node of int * string * BinaryTree * BinaryTree
ID3 algorithms take into account various equations to determine where to split the tree, and I've got all that figured out, I'm just having trouble creating the learned tree from my truth table. For example if I have the following table
A1 | A2 | A3 | Class
1 0 0 1
0 1 0 1
0 0 0 0
1 0 1 0
0 0 0 0
1 1 0 1
0 1 1 0
And I decide to split on attribute A1 I would end up with the following:
(A1 = 1) A1 (A1 = 0)
A2 | A3 | Class A2 | A3 | Class
0 0 1 1 0 1
0 1 0 0 0 0
1 0 1 0 0 0
0 1 1
Then I would split the left side and split the right side, and continue the recursive pattern until the leaf nodes are pure and I end up with a tree similar to the following based on the splitting.
let learnedTree = Node(0,"A0", Node(2,"A2", Leaf(0), Leaf(1)), Node(1,"A1", Node(2,"A2", Leaf(0), Leaf(1)), Leaf(0)))
Here is what I've kind of "hacked" together thus far, but I think I might be way off:
let rec createTree (listToSplit : list<list<float>>) index =
let leftSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(index) = 1. then Some(x) else None)
let rightSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(index) = 0. then Some(x) else None)
if leftSideSplit.Length > 0 then
let pureCheck = isListPure leftSideSplit
if pureCheck = 0 then
printfn "%s" "Pure left node class 0"
createTree leftSideSplit (index + 1)
else if pureCheck = 1 then
printfn "%s" "Pure left node class 1"
createTree leftSideSplit (index + 1)
else
printfn "%s - %A" "Recursing Left" leftSideSplit
createTree leftSideSplit (index + 1)
else printfn "%s" "Pure left node class 0"
Should I be using pattern matching instead? Any tips/ideas/help? Thanks a bunch!
Edit: I've since posted an implementation of ID3 on my blog at:
http://blogs.msdn.com/chrsmith
Hey Jim, I've been wanting to write a blog post implementing ID3 in F# for a while - thanks for giving me an execute. While this code doesn't implement the algorithm full (or correctly), it should be sufficient for getting you started.
In general you have the right approach - representing each branch as a discriminated union case is good. And like Brian said, List.partition is definitely a handy function. The trick to making this work correctly is all in determining the optimal attribute/value pair to split on - and to do that you'll need to calculate information gain via entropy, etc.
type Attribute = string
type Value = string
type Record =
{
Weather : string
Temperature : string
PlayTennis : bool
}
override this.ToString() =
sprintf
"{Weather = %s, Temp = %s, PlayTennis = %b}"
this.Weather
this.Temperature
this.PlayTennis
type Decision = Attribute * Value
type DecisionTreeNode =
| Branch of Decision * DecisionTreeNode * DecisionTreeNode
| Leaf of Record list
// ------------------------------------
// Splits a record list into an optimal split and the left / right branches.
// (This is where you use the entropy function to maxamize information gain.)
// Record list -> Decision * Record list * Record list
let bestSplit data =
// Just group by weather, then by temperature
let uniqueWeathers =
List.fold
(fun acc item -> Set.add item.Weather acc)
Set.empty
data
let uniqueTemperatures =
List.fold
(fun acc item -> Set.add item.Temperature acc)
Set.empty
data
if uniqueWeathers.Count = 1 then
let bestSplit = ("Temperature", uniqueTemperatures.MinimumElement)
let left, right =
List.partition
(fun item -> item.Temperature = uniqueTemperatures.MinimumElement)
data
(bestSplit, left, right)
else
let bestSplit = ("Weather", uniqueWeathers.MinimumElement)
let left, right =
List.partition
(fun item -> item.Weather = uniqueWeathers.MinimumElement)
data
(bestSplit, left, right)
let rec determineBranch data =
if List.length data < 4 then
Leaf(data)
else
// Use the entropy function to break the dataset on
// the category / value that best splits the data
let bestDecision, leftBranch, rightBranch = bestSplit data
Branch(
bestDecision,
determineBranch leftBranch,
determineBranch rightBranch)
// ------------------------------------
let rec printID3Result indent branch =
let padding = new System.String(' ', indent)
match branch with
| Leaf(data) ->
data |> List.iter (fun item -> printfn "%s%s" padding <| item.ToString())
| Branch(decision, lhs, rhs) ->
printfn "%sBranch predicate [%A]" padding decision
printfn "%sWhere predicate is true:" padding
printID3Result (indent + 4) lhs
printfn "%sWhere predicate is false:" padding
printID3Result (indent + 4) rhs
// ------------------------------------
let dataset =
[
{ Weather = "windy"; Temperature = "hot"; PlayTennis = false }
{ Weather = "windy"; Temperature = "cool"; PlayTennis = false }
{ Weather = "nice"; Temperature = "cool"; PlayTennis = true }
{ Weather = "nice"; Temperature = "cold"; PlayTennis = true }
{ Weather = "humid"; Temperature = "hot"; PlayTennis = false }
]
printfn "Given input list:"
dataset |> List.iter (printfn "%A")
printfn "ID3 split resulted in:"
let id3Result = determineBranch dataset
printID3Result 0 id3Result
You can use List.partition instead of your two List.choose calls.
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Collections.List.html
(or now http://msdn.microsoft.com/en-us/library/ee353738(VS.100).aspx )
It isn't clear to me that pattern matching will buy you much here; the input type (list of lists) and processing (partitioning and 'pureness' check) doesn't really lend itself to that.
And of course when you finally get the 'end' (a pure list) you need to create a tree, and then presumably this function will create a Leaf when the input only has one 'side' and it's 'pure', but create a Node out of the left-side and right-side results for every other input. Maybe. I didn't quite grok the algorithm completely.
Hopefully that will help steer you a little bit. May be useful to draw up a few smaller sample inputs and outputs to help work out the various cases of the function body.
Thanks Brian & Chris! I was actually able to figure this out and I ended up with the following. This calculates the information gain for determining the best place to split. I'm sure there are probably better ways for me to arrive at this solution especially around the chosen data structures, but this is a start. I plan to refine things later.
#light
open System
let trainList =
[
[1.;0.;0.;1.;];
[0.;1.;0.;1.;];
[0.;0.;0.;0.;];
[1.;0.;1.;0.;];
[0.;0.;0.;0.;];
[1.;1.;0.;1.;];
[0.;1.;1.;0.;];
[1.;0.;0.;1.;];
[0.;0.;0.;0.;];
[1.;0.;0.;1.;];
]
type BinaryTree =
| Leaf of int
| Node of int * string * BinaryTree * BinaryTree
let entropyList nums =
let sumOfnums =
nums
|> Seq.sum
nums
|> Seq.map (fun x -> if x=0.00 then x else (-((x/sumOfnums) * Math.Log(x/sumOfnums, 2.))))
|> Seq.sum
let entropyBinaryList (dataListOfLists:list<list<float>>) =
let classList =
dataListOfLists
|> List.map (fun x -> x.Item(x.Length - 1))
let ListOfNo =
classList
|> List.choose (fun x -> if x = 0. then Some(x) else None)
let ListOfYes =
classList
|> List.choose (fun x -> if x = 1. then Some(x) else None)
let numberOfYes : float = float ListOfYes.Length
let numberOfNo : float = float ListOfNo.Length
let ListOfNumYesAndSumNo = [numberOfYes; numberOfNo]
entropyList ListOfNumYesAndSumNo
let conditionalEntropy (dataListOfLists:list<list<float>>) attributeNumber =
let NoAttributeList =
dataListOfLists
|> List.choose (fun x -> if x.Item(attributeNumber) = 0. then Some(x) else None)
let YesAttributeList =
dataListOfLists
|> List.choose (fun x -> if x.Item(attributeNumber) = 1. then Some(x) else None)
let numberOfYes : float = float YesAttributeList.Length
let numberOfNo : float = float NoAttributeList.Length
let noConditionalEntropy = (entropyBinaryList NoAttributeList) * (numberOfNo/(numberOfNo + numberOfYes))
let yesConditionalEntropy = (entropyBinaryList YesAttributeList) * (numberOfYes/(numberOfNo + numberOfYes))
[noConditionalEntropy; yesConditionalEntropy]
let findBestSplitIndex(listOfInstances : list<list<float>>) =
let IGList =
[0..(listOfInstances.Item(0).Length - 2)]
|> List.mapi (fun i x -> (i, (entropyBinaryList listOfInstances) - (List.sum (conditionalEntropy listOfInstances x))))
IGList
|> List.maxBy snd
|> fst
let isListPure (listToCheck : list<list<float>>) =
let splitList = listToCheck |> List.choose (fun x -> if x.Item(x.Length - 1) = 1. then Some(x) else None)
if splitList.Length = listToCheck.Length then 1
else if splitList.Length = 0 then 0
else -1
let rec createTree (listToSplit : list<list<float>>) =
let pureCheck = isListPure listToSplit
if pureCheck = 0 then
printfn "%s" "Pure - Leaf(0)"
else if pureCheck = 1 then
printfn "%s" "Pure - Leaf(1)"
else
printfn "%A - is not pure" listToSplit
if listToSplit.Length > 1 then // There are attributes we can split on
// Chose best place to split list
let splitIndex = findBestSplitIndex(listToSplit)
printfn "spliting at index %A" splitIndex
let leftSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(splitIndex) = 1. then Some(x) else None)
let rightSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(splitIndex) = 0. then Some(x) else None)
createTree leftSideSplit
createTree rightSideSplit
else
printfn "%s" "Not Pure, but can't split choose based on heuristics - Leaf(0 or 1)"