问题
I'm defining a monadic observable/reactive parser. This behaves quite differently to a normal parser as it is a continuous query. The underlying type is:
IObservable<'a> -> IObservable<'b>
From looking at various parser implementations in functional languages, it seems as though the more appropriate way to define things is a single case discriminated union:
type Pattern<'a,'b> = Pattern of (IObservable<'a> -> IObservable<'b>)
Which means I then need to extract the underlying function to use it:
let find (Pattern p) = p
The question is: Is this just by convention, or for purposes of later extension, or is there a reason to do this even if the definition never changes?
Bonus question: If it's just for a more convenient type signature, why not just use a type alias:
type Pattern<'a,'b> = IObservable<'a> -> IObservable<'b>
I've advanced quite a way through this, and haven't found a case where composability is affected by not using the DU.
回答1:
F# compiler doesn't preserve information about type abbreviation, so you do not benefit from type inference at all. Type signature can be understood as program specification; letting the type checker do their job is a good way to ensure correctness of your programs.
You need explicitly specify type annotation everywhere in the case of type alias:
type Vector = float * float
// val add : float * float -> float * float -> Vector
let add ((x1, y1): Vector) ((x2, y2): Vector): Vector = (x1 + y1, x2 + y2)
but it doesn't give you transparency as using DUs:
type Vector = V of float * float
// val add : Vector -> Vector -> Vector
let add (V(x1, y1)) (V(x2, y2)) = V(x1 + y1, x2 + y2)
In complex programs clear type signatures indeed make it easier to maintain composability.
Not only it's simpler to add more cases to single-case DUs, but also it's easier to extend DUs with member and static methods. One example is you often override ToString()
for pretty printing.
回答2:
From what I understand, single case discriminated union type are there to provide a name that is semantically relevant to your problem domain, to an otherwise general purpose back end type whose name is 'string'.
It is a light abstraction leakage fix for semantics, and only that, AFAIK
来源:https://stackoverflow.com/questions/10150767/purpose-of-a-single-case-discriminated-union