Цель единичного случая дискриминации союза

Я определяю монадический наблюдаемый/реактивный парсер. Это ведет себя совершенно иначе, чем обычный анализатор, поскольку это непрерывный запрос. Базовый тип:

IObservable<'a> -> IObservable<'b>

Глядя на различные реализации синтаксических анализаторов на функциональных языках, кажется, что более подходящим способом определения вещей является объединение с разграничением по одному регистру:

type Pattern<'a,'b> = Pattern of (IObservable<'a> -> IObservable<'b>)

Это означает, что мне нужно извлечь базовую функцию, чтобы использовать ее:

let find (Pattern p) = p

Вопрос в том, является ли это просто соглашением или для целей последующего расширения, или есть причина сделать это, даже если определение никогда не изменится?

Бонусный вопрос: если это просто для более удобной подписи типа, почему бы просто не использовать псевдоним типа:

type Pattern<'a,'b> = IObservable<'a> -> IObservable<'b>

Я продвинулся в этом довольно далеко и не нашел случая, когда на компонуемость влияет неиспользование DU.


person yamen    schedule 14.04.2012    source источник


Ответы (2)


Компилятор F# не сохраняет информацию об аббревиатуре типа, поэтому вы вообще не получаете выгоды от выведения типа. Сигнатуру типа можно понимать как спецификацию программы; позволить средству проверки типов выполнять свою работу — хороший способ убедиться в корректности ваших программ.

Вам нужно явно указать аннотацию типа везде в случае псевдонима типа:

type Vector = float * float

// val add : float * float -> float * float -> Vector
let add ((x1, y1): Vector) ((x2, y2): Vector): Vector = (x1 + y1, x2 + y2)

но это не дает вам прозрачности при использовании DU:

type Vector = V of float * float

// val add : Vector -> Vector -> Vector
let add (V(x1, y1)) (V(x2, y2)) = V(x1 + y1, x2 + y2)

В сложных программах четкие подписи типов действительно облегчают компоновку.

Мало того, что проще добавить больше случаев в DU с одним регистром, но также проще расширить DU с помощью методов-членов и статических методов. Например, вы часто переопределяете ToString() для красивой печати.

person pad    schedule 14.04.2012
comment
Спасибо, это на самом деле довольно конкретная причина. Определенно не хочется везде печатать IObservable<'a> -> IObservable<'b> вместо Pattern<'a,'b>. - person yamen; 15.04.2012
comment
Продолжение много лун спустя. В итоге я добавил к союзу второй случай, и, таким образом, вселенная находится в равновесии. - person yamen; 25.03.2014

Насколько я понимаю, тип объединения с разграничением в одном регистре предназначен для предоставления имени, которое семантически релевантно вашей проблемной области, для типа серверной части общего назначения, имя которого - «строка».

Это легкое исправление утечки абстракции для семантики, и только это, AFAIK

person nicolas    schedule 14.04.2012
comment
Я не думаю, что это правда. Вот что такое псевдоним типа. Объединение с разграничением в одном регистре — это полный класс, и в данном случае оно является оболочкой для функции (или делегата в разговоре о C#). - person yamen; 14.04.2012
comment
конечно. но я не знаю другого применения, кроме этого... также обратите внимание, что вы можете добавить некоторые методы к типам объединения. - person nicolas; 14.04.2012