Home > Software design >  F# generic type constricted to specific type?
F# generic type constricted to specific type?

Time:10-03

F# forces my unspecifed type to be a bool.

I needed a combination of List.find and List.tryPick, and made the function below. Efficiancy is not important.

What did i do wrong for type 'T to only be able to be type bool?

let FindPickCombi(list : 'T list, func : 'T -> 'U option) : bool * ('U option) =
    (List.find 
        (fun (x : 'T) -> 
            match func(x) with
            | Some _ -> true
            | _ -> false
        ) list,
    List.tryPick(fun x -> func(x)) list)

CodePudding user response:

I found the answer myself. The return type shouldn't have been bool.

Changed function to:

let FindPickCombi(list : 'T list, func : 'T -> 'U option) : 'T * ('U option) =
    (List.find 
        (fun (x) -> 
            match func(x) with
            | Some _ -> true
            | _ -> false
        ) list,
    List.tryPick(fun x -> func(x)) list)

CodePudding user response:

Your current solution in your own answer loops twice over the whole list. Also, the first part with List.find will fail with a KeyNotFoundException if nothing is found, meaning that the tryPick will never return None.

Here's an alternative, which returns both the original type of the list and the mapped typed from your func. We wrap the whole tuple in an option.

let FindPickCombi(list : 'T list, func : 'T -> 'U option) : ('T * 'U) option =
    List.tryPick(fun x -> 
        match func x with
        | Some y -> Some(x, y)
        | None -> None) list

This can be further improved by ditching the (list, func) tuple, so that our function can use currying / partial application, which further simplifies the code and uses the same order of arguments as F#'s build-in functions (that is: the function-argument comes first).

As you can see here, we don't have the list argument anymore, because that is curried from List.tryPick automatically by F#:

let FindPickCombi func =
    List.tryPick(fun x -> 
        match func x with
        | Some y -> Some(x, y)
        | None -> None)

What did i do wrong for type 'T to only be able to be type bool?

You made the return type of your function bool * 'U option, which is why the compiler forces the result of List.find to be a bool, which makes the type of 'T list a list of bools.

  • Related