Привет, FSharpers (или любой MLer)
Все еще пытаюсь улучшить свои навыки моделирования домена (из ООП). Допустим, у меня есть следующие
type A =
| AA of AA
| AB of AB
type AA =
{ Code : 'a
Time : 'b }
type AB =
{ Code : 'a
Whatsoever : 'c }
А теперь представим, что мне нужна следующая сигнатура функции: (A -> 'a)
Насколько я понимаю, у меня есть решение:
let f (a1:A) =
match a1 with
| AA a -> a.Code
| AB a -> a.Code
неудобство этого решения состоит в том, что оно требует от меня всегда добавлять новые случаи к моему совпадению, если я должен был добавить некоторые из них в объединение A.
Я предполагаю, что другим решением будет решение кортежного типа (но с потерей «именования» поля):
type A =
| AA of AA * 'a
| AB of AB * 'a
type AA =
{ Time : 'b }
type AB =
{ Whatsoever : 'c }
let f (a1:A) =
snd a1
Есть ли какое-нибудь простое решение, которое я пропустил? Спасибо!
У меня может быть идея, используя общий тип, такой как:
type A =
| AA of Tmp<AA>
| AB of Tmp<AB>
type Tmp<'T> =
{ Code : 'a
Other : 'T }
type AA =
{ Time : 'b }
type AB =
{ Whatsoever : 'c }
Этот:
let f (a1:A) = snd a1
не будет работать, потому что, чтобы добраться до кортежа, вам сначала нужно сопоставить AA
и AB
.
Это могло сработать:
type A0<'b, 'c> =
| AA of AA<'b>
| AB of AB<'c>
type A<'a, 'b, 'c> = A0<'b, 'c> * 'a
let f (a1:A<_,_,_>) =
snd a1
Ваше решение с Tmp<_>
эквивалентно использованию кортежа.
Кстати, в F# порядок элементов важен, для доступа к типу AA
его необходимо объявить перед типом A
. Ваш первый пример должен выглядеть примерно так:
type AA<'a, 'b> = {
Code : 'a
Time : 'b }
type AB<'a, 'c> = {
Code : 'a
Whatsoever : 'c }
type A<'a, 'b, 'c> =
| AA of AA<'a, 'b>
| AB of AB<'a, 'c>
let f (a1:A<_,_,_>) =
match a1 with
| AA a -> a.Code
Также, чтобы использовать общие параметры, такие как 'a
или 'b
, их необходимо объявить вверху:
type A<'a, 'b, 'c> = ...
Действительно, я забыл расположить декларацию в правильном порядке. Большое спасибо, я понял, как сделать код более универсальным.