Nik
Nik

Reputation: 9431

F# function return several types (return kind of generic object type)?

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?

Upvotes: 0

Views: 1460

Answers (5)

Simon Stender Boisen
Simon Stender Boisen

Reputation: 3431

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;;

Upvotes: 0

nicolas
nicolas

Reputation: 9805

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.

Upvotes: 0

Tomas Petricek
Tomas Petricek

Reputation: 243041

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.

Upvotes: 8

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"

Upvotes: 0

John Palmer
John Palmer

Reputation: 25516

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

Upvotes: 5

Related Questions