Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# List of Union Types

I want a list of Reports. Report can be either Detail or Section types.

module Data

type Section = { Header: string;
                 Lines:  string list;
                 Total:  string }

type Detail = { State:     string;
                Divisions: string list;
                Sections:  Section list }

type Summary = { State:    string;
                 Office:   string;
                 Sections: Section list }

type Report = Detail | Summary

Then in my code, I'd like to do the following:

let mutable (reports:Report list) = []

...

reports <- detail::reports
// or
reports <- summary::reports

The compiler complains in the first case: "The expression was expected to have type Report but here has type Detail", and appropriately similarly in the second case.

Am I out of my mind for wanting to do such a thing? Should I be thinking about the problem differently? Because Report is either Detail or Summary, shouldn't a list of Report accept either a Detail or a Summary? What is a Report list if not a list of Detail or Summary?

Thanks.

like image 761
Jeff Maner Avatar asked Dec 07 '12 21:12

Jeff Maner


2 Answers

You've just got your syntax a bit wrong:

type Report = Detail of Detail | Summary of Summary

reports <- (Detail detail)::reports
// or
reports <- (Summary summary)::reports

In your code you've basically just defined the Report type to be an enum with the two possible values Details or Summary (these are like labels, not the types of different subtypes in this context). Discriminated unions in F# are explicitly tagged, so you've also got to use one of the union constructors to create an instance to put into the list.

like image 96
kvb Avatar answered Sep 24 '22 17:09

kvb


You need to change your Report type to:

type Report = Detail of Detail | Summary of Summary

since your current definition just names the two cases of your Report type, and these names are not related to the existing Detail and Summary types.

You can then filter the Detail and Summary elements using List.choose e.g.

let details = reports |> List.choose (function Detail(d) -> Some(d) | _ -> None)
like image 43
Lee Avatar answered Sep 23 '22 17:09

Lee