I'm relatively new to F# and am really having a real struggle with parsing an expression tree, which contains nested lists. From bits and pieces on the web I have cobbled together the following.
My standard type is defined:
type Return =
| Real of float
| Func of string * Return list
I make a function call to an external application, which returns something like:
val out : Return =
Func
("List",
[Func ("List",[Real 1.0; Real 2.0; Real 3.0]);
Func ("List",[Real 1.0; Real 2.0; Real 3.0]);
Func ("List",[Real 1.0; Real 2.0; Real 3.0])])
and which I'm needing to parse into
[ [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ]
My initial naive thought was along the lines of
let rec parse data =
match data with
| Real(y) -> y
| Func("List", x) -> x |> List.map parse
| _ -> failwithf "Unrecognised"
but it's complaining about the type differences, which I now understand.
My second thought is to maybe use some recursive List.fold (as I can fold over the list of Reals and get the inner lists, but can't figure out how to generalise it into a recursive function without the compiler complaining out type). Beyond my current intellectual fire-power.
My third thought is that maybe the return I get from the external application is making this too difficult, as there is no indication in the tuple fst about what is in the tuple snd, apart from the fact it is a "list of something"?
There is this: Convert tree to list but it's as cryptic as the solutions I'm trying tbh.
Any pointers as to which avenue I pursue would be really appreciated.
What is the type of the object you want your parse function to return?
If your desired output is [ [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ; [1.0; 2.0; 3.0] ], it appears that what you want to return is neither a float list nor a float list list, but rather an arbitrarily nested list of float.
But that doesn't exist as a standard type, and you'll need to define it yourself as a recursive discriminated union (we'll make it generic for good practice):
type NestedList<'a> =
| Single of 'a
| Collection of NestedList<'a> list
Well look at that! It's just a thin reskin over your original Return type. That's because the original type is pretty much already a standard nested list implementation, except for the "List" label thing.
The parse function then has almost no real work left to do:
let rec parse = function
| Real y -> Single y
| Func ("List", returns) -> Collection (returns |> List.map parse)
| Func (l, _) -> failwithf "Unrecognised label %s" l
Sometimes it is good to annotate the function you are implementing. Then it becomes explicit of what you are trying to do:
type Return =
| Real of float
| Func of string * Return list
let rec parse (data : Return) : float list =
match data with
| Real y -> [ y ]
| Func (_, returns) -> returns |> List.collect parse
| _ -> failwithf "Unrecognised"
Your x |> List.map parse has a type float list list but on other branch your expression has a type float. Am I correct that you tried to return float list?
Related
I m trying to filter a mixed data type for a specific type, say float (ideally this would be dynamic though)
here my example:
let testobj = [8.0 , 1.0, "bla" ; 8.0 , 1.0, "bla"]
let testfun data = data |> List.filter (fun a ->
match a.GetType() with
| float -> a
| _ -> 0.0)
now this should return [8.0 , 1.0, 0.0 ; 8.0 , 1.0, 0.0] for testobj but I m gettting an error that the function is of type bool
This isn't what you want to do.
Seriously.
F# wants lists to be homogeneous and your list is not homogeneous. float and string don't share a common base class so you're not going to get a list from it.
What F# wants you to do is to use a discriminated union for this. So if you have this type:
type Composite =
| Num of float
| Str of string
you can define your list like this:
let data = [ Num(8.0); Num(1.0); Str("bla"); Num(8.0); Num(1.0); Str("bla") ]
and from there you can pattern match on the types and your function looks like this:
let testfun d = d |> List.map (fun a ->
match a with
| Num x -> a
| _ -> Num(0.0) )
data|> testfun |> printfn "%A"
And the output will be:
[Num 8.0; Num 1.0; Num 0.0; Num 8.0 ; Num 1.0 ; Num 0.0;]
If you want floats in the end and not Composites, do this:
let testfun1 d = d |> List.map (fun a ->
match a with
| Num x -> x
| _ -> 0.0 )
which sheds the composite type. And everything (and I mean everything) in that code is type strong and type-safe.
From a real-world maintenance point of view, I would eschew the _ case in the matches and instead use all my types, reasoning that if I extend Composite to include another type I would want the compiler to scream at me and look at each function that uses it rather than silently assuming that 0.0 or Num(0.0) is really what I wanted.
For example, if I added integers to that type, this would do exactly the wrong thing if I wanted to sum the contents of a list of composites.
Given that you're stuck/hell-bent on a weakly-typed data set, then you want something like this:
let testfun2 d = d |> Array.map (fun (a:Object) ->
match a with
| :? float as x -> x
| _ -> 0.0
)
let data:Object[] = [|8.0; 1.0; "bla"; 8.0; 1.0; "bla"|]
data |> testfun2 |> printfn "%A"
which will print what you expect. Note that I'm using proper Array syntax and not list syntax.
However this is feeling really wonky for F#. See how I have to adorn a and d with types? In my previous code, the language can figure it all out. If I don't adorn either, I get compiler errors because we're really going against the grain of the type system.
If I were you, I would be inclined to do something like this first:
let recast d = d |> Array.map (fun (a:Object) ->
match a with
| :? float as x -> Num x
| :? string as x -> Str x
| _ -> raise (ArgumentException("that was unexpected: " + a.GetType().Name))
)
which turns this into an Array of Composite which is now type strong. If you tack on |> Array.toList after the Array.map, you get a list (if you want that).
Is there a quick and simple way to convert an entire list of strings into floats or integers
and add them together similar to this in F#?
foreach(string s in list)
{
sum += int.Parse(s);
}
If you want to aim for minimal number of characters, then you can simplify the solution posted by Ganesh to something like this:
let sum = list |> Seq.sumBy int
This does pretty much the same thing - the int function is a generic conversion that converts anything to an integer (and it works on strings too). The sumBy function is a combination of map and sum that first projects all elements to a numeric value and then sums the results.
Something like this should have the same effect:
let sum = list |> Seq.map System.Int32.Parse |> Seq.sum
F# doesn't seem to support referring to the method on int so I had to use System.Int32 instead.
In F# the type seq is an alias for the .NET IEnumerable, so this code works on arrays, lists etc.
Note the use of Parse in "point-free" style - a function without its argument can be used directly as an argument to another function that expects that type. In this case Seq.map has this type:
('a -> 'b) -> seq<'a> -> seq<'b>
And since System.Int32.Parse has type string -> int, Seq.map System.Int32.Parse has type seq<string> -> seq<int>.
Technically, there are at least 3 different approaches:
1) The Seq.sum or sumBy approach described in the other answers is the canonical way of getting the sum in F#:
let sum = Seq.sumBy int list
2) For instructional purposes, it may be interesting to see how closely one can simulate C# behavior in F#; for instance, using a reference cell type:
let inline (+=) x y = x := !x + y
let sum = ref 0
for s in list do sum += int s
3) Same idea as 2), but using a byref pointer type:
let inline (+=) (x:_ byref) y = x <- x + y
let mutable sum = 0
for s in list do &sum += int s
I keep learning F# pattern matching with my simple function which should return square root if argument is number, argument otherwise. I've modified it a bit and it looks like as follows.
let my_sqrt (o: obj) =
match o with
| :? float as d -> (sqrt d).ToString()
| _ as x -> x.ToString()
It is working fine for my purpose, but what if I don't want to cast return value to string? How can I return "some object" and then use it in printfn "%A" (my_sqrt [| 1; 2; 3 |]) construction?
Even though your example is just a demonstration of what you're trying to do, it is worth pointing out that this is probably not a good design. In F#, you would not normally use functions that operate on objects using casts - a better way to represent this would be a discriminated union:
type MyInput =
| Numeric of float
| Other of obj
let my_sqrt = function
| Numeric d -> Numeric (sqrt d)
| Other o -> Other o
This function works on a type that is either Numeric or Other, but thanks to the DU, you do not need any casting. I think something along these lines would be a better approach to your actual problem too.
I think you want
let my_sqrt (o: obj) =
match o with
| :? float as d -> (sqrt d) :> obj
| _ as x -> x
just upcast to object
I think your function is ok. When you want to compute each square root, you have to map your function over array like this:
Array.map my_sqrt [| 1.0; 2.0; 3.0 |] |> printfn "%A"
As mentioned in TP answer, the general idea should be, wherever possible, to surface information to your type system.
It is then easier for you to read and reason your program, as you have named things.
That means F# can actually work for you and tell you when you made something wrong
That makes it always worth the investment.
I agree with Tomas that using a Discriminated Union would be better. There is no Either monad built into F# but you could use the Choice union to standardize the interface:
let my_sqrt (o : obj) =
match o with
| :? float as d -> Choice1Of2 (sqrt d)
| o -> Choice2Of2 o;;
Define the function max2 that takes two integers as arguments and returns the largest of them.
I did this: let max2 x y = if x < y then y else x this I belive is correct
Then define the function max_list that returns the largest of the elements in a nonempty list of integers by calling max2. For the empty list, it should abort with an error message ( raising an exception)
I did this: let list = [3;4] let max_list = if list.IsEmpty then 0 else max2 list.Item(0) list.Item(1) but this wont work if the list is more then two elements. I dont want to use any object-orientated stuff. What is the correct answer?
The correct answer is that you should read about recursion with lists.
F# list is built up gradually using empty list [] and cons (::) constructor. For example,
[3; 4] is a syntactic sugar for 3::4::[]. We often use pattern matching on lists in writing recursive functions.
Here is a recursive function following your requirements closely:
let rec max_list xs =
match xs with
// The function aborts with an error message on empty lists
| [] -> invalidArg "xs" "Empty list"
// Return immediately on a singleton list
| [x] -> x
// xs has at least two elements, call max_list
// on the bigger element of the first two ones and the rest of the list
| x1::x2::xs' -> max_list((max2 x1 x2)::xs')
On a side note, there is a built-in generic max function which also works on integers.
A simple recursive solution:
let max2 x y = if x < y then y else x
let max_list list =
let rec loop hi list =
match list with
| h::t -> let hi = max2 h hi
loop hi t
| [] -> hi
match list with
| h::t -> loop h t
| [] -> invalidArg "list" "Empty list"
Test in FSI:
> max_list [3;4;5;1;2;9;0];;
val it : int = 9
For each element in the list, compare it to the previous highest ('hi'). Pass the new highest and the rest of the list into the loop function, until the input list is empty. Then just return 'hi'.
I've just started messing around with F# and am trying to do some basic parallel computation to get familiar with the language. I'm having trouble with type mismatches. Here's an example:
let allVariances list =
seq {
for combination in allCombinations list do
yield (combination, abs(targetSum - List.sum combination))
}
let compareVariance tup1 tup2 =
if snd tup1 < snd tup2 then
tup1
else
tup2
let aCompareVariance tup1 tup2 =
async { return compareVariance tup1 tup2 }
let matchSum elements targetSum =
allVariances elements
|> Seq.reduce aCompareVariance
|> Async.Parallel
|> Async.RunSynchronously
So, "allVariances elements" produces a seq<float list * float>. CompareVariance takes two of those <float list * float> tuples and returns the one with the smaller second item (variance). My goal is to use Reduce to end up with the tuple with the smallest variance. However, I get a type mismatch on the aCompareVariance argument:
Error 1 Type mismatch. Expecting a float list * float -> float list * float -> float list * float but given a float list * float -> float list * float -> Async<float list * float> The type 'float list * float' does not match the type 'Async<float list * float>'
It seems like the Async return type isn't accepted by Reduce?
Seq.reduce takes a function and a sequence and reduces the list using the function. That is, the outcome of reducing a sequence {a1;a2;a3;...;an} with function f will be f(f(...f(f(a1,a2),a3),...),an))...). However, the function you're passing can't be applied this way, because the return type (Async<float list * float>) doesn't match the argument types (float list * float). What exactly are you trying to achieve?
Also, keep in mind that async computations are great for asynchronous work, but not ideal for parallel work. See F#: Asynch and Tasks and PLINQ, oh my! and Task Parallel Library vs Async Workflows.
EDIT
Here's one way to write a function which will reduce items more like you expected, operating sort of like this:
[|a1; a2; a3; a4|]
[|f a1 a2; f a3 a4|]
f (f a1 a2) (f a3 a4)
At each stage, all applications of f will take place in parallel. This uses Async.Parallel, which as mentioned above is probably less appropriate than using the Task Parallel Library (and may even be slower than just doing a normal synchronous Array.reduce). As such, just consider this to be demonstration code showing how to piece together the async functions.
let rec reduce f (arr:_[]) =
match arr.Length with
| 0 -> failwith "Can't reduce an empty array"
| 1 -> arr.[0]
| n ->
// Create an array with n/2 tasks, each of which combines neighboring entries using f
Array.init ((n+1)/2)
(fun i ->
async {
// if n is odd, leave last item alone
if n = 2*i + 1 then
return arr.[2*i]
else
return f arr.[2*i] arr.[2*i+1]})
|> Async.Parallel |> Async.RunSynchronously
|> reduce f
Note that converting items to and from Async values all happens internally to this function, so it has the same type as Array.reduce and would be used with your normal compareVariance function rather than with aCompareVariance.