Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map a sequence of discriminated unions (where all items are of the same case) onto a sequence of items of the type of the case?

Tags:

f#

I have the following:

type union1 =
    | Case1 of string
    | Case2 of int

let union1s = seq { for i in 1..5 do yield case2 i }

How do I change union1s to a sequence of type seq<int>?

Something like:

let matchCase item =
    match item with
    | Case1 x -> x
    | Case2 x -> x

let case2s = Seq.map matchCase union1s

This attempt does not work because matchCase can not return two different types.

The suggested answers have the same problem (if I understand correctly)

let matchCaseOpt = function
    | Case1 x -> Some x
    | Case2 x -> Some x
    | _ -> None

let case2s = Seq.choose matchCaseOpts unions1s

The expression Some x expects expects type Option string in the match for Case2

I have solved my particular use-case by using a DU of sequences.

type Union1s =
    | Case1s of seq<string>
    | Case2s of seq<int>    
like image 278
Remko Avatar asked Sep 04 '13 07:09

Remko


People also ask

How is a discriminated union defined?

A discriminated union is a union data structure that holds various objects, with one of the objects identified directly by a discriminant. The discriminant is the first item to be serialized or deserialized. A discriminated union includes both a discriminant and a component.

When to use discriminated union?

Discriminated unions are useful for heterogeneous data; data that can have special cases, including valid and error cases; data that varies in type from one instance to another; and as an alternative for small object hierarchies.

What is discriminated unions in TypeScript?

The concept of discriminated unions is how TypeScript differentiates between those objects and does so in a way that scales extremely well, even with larger sets of objects. As such, we had to create a new ANIMAL_TYPE property on both types that holds a single literal value we can use to check against.

What is a union in F#?

Advertisements. Unions, or discriminated unions allows you to build up complex data structures representing well-defined set of choices. For example, you need to build an implementation of a choice variable, which has two values yes and no. Using the Unions tool, you can design this.


1 Answers

You are assuming your sequence contains not a single case1, so if this is not true you need to throw an exception.

let matchCase item =
    match item with
    | Case1 x -> failwith "Unexpected Case1"
    | Case2 x -> x

let case2s = Seq.map matchCase union1s

An alternative approach, if you are not sure the sequence contains always the same case is to use an Option

let matchCase item =
    match item with
    | Case1 x -> None
    | Case2 x -> Some x

Then it depends on how you will handle these cases, you can just filter out the None values using Seq.choose instead of Seq.map as shown on the other answer.

Which approach to follow depends if you consider having an argument with Case1s an exceptional case or part of the logic of your program. There was a question regarding this F#: Some, None, or Exception? recently.

Using a DU of sequences is correct if you are not mixing Cases, that way your DU Type restrict your domain to the actual cases.

like image 149
Gus Avatar answered Sep 22 '22 10:09

Gus