Общий параметр в Союзе

Привет, 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

Есть ли какое-нибудь простое решение, которое я пропустил? Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
42
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

У меня может быть идея, используя общий тип, такой как:

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> = ...

Действительно, я забыл расположить декларацию в правильном порядке. Большое спасибо, я понял, как сделать код более универсальным.

Jeff_hk 05.12.2018 09:46

Другие вопросы по теме