Как моделировать зависимые и вложенные типы сумм? - PullRequest
2 голосов
/ 22 мая 2019

Мне интересно, как можно организовать следующий тип данных, особенно в Rust, но ответы на любом языке программирования интересны.

Моя система обрабатывает запросы нескольких типов, каждый из которых связан с различными данными, например,

enum Request {
    A(i64),
    B(f64),
    C(String),
}

Если обработанный запрос утвержден, нам нужно сохранить запрос вместе с данными о процессе утверждения, но тип данных зависит от типа. Поэтому я хочу сказать

enum ApprovedRequest {
    ApprovedA(Request::A, i64),
    ApprovedB(Request::B, f64),
    ApprovedC(Request::C, String),
}

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

enum DeniedRequest {
    DeniedA(Request::A, String),
    DeniedB(Request::B, String),
    DeniedC(Request::C, i64),
}

Это не допустимый Rust, потому что Request :: A не является типом. См. Выпуск 754. Я думаю, что способ, которым я представил проблему, был бы вариантом использования для зависимых типов. Но в любом случае, есть какие-нибудь предложения, как организовать это на Rust или другом языке с сопоставлением с образцом?

1 Ответ

2 голосов
/ 22 мая 2019

В этом случае мое подходящее решение заключается в создании независимых типов и оборачивании их в перечисление:

struct A(i64);
struct B(f64);
struct C(String);

enum Request {
    A(A),
    B(B),
    C(C),
}

Здесь требуется немного повторения, но в остальном это довольно просто.Имена не обязательно должны совпадать.


С этим на месте, выражение ApprovedRequest и DeniedRequest возможно сразу.

Другая возможность , хотя, является использование признаков и обобщений:

trait Approved {
    type Payload;
}

struct ApprovedT<T: Approved> {
    request: T,
    approval: T::Payload,
}

enum ApprovedRequest {
    A(ApprovedT<A>),
    B(ApprovedT<B>),
    C(ApprovedT<C>),
}

И затем, для каждого запроса, объясните полезную нагрузку:

impl Approved for A {
    type Payload = i64;
}

impl Denied for A {
    type Payload = String;
}

Основное преимущество этого подхода состоит в том, что любой метод, которому необходимо манипулироватьутвержденный запрос и его полезная нагрузка для утверждения могут быть сделаны общими для ApprovedT, в противном случае, какой будет тип полезной нагрузки?


Я думаю, как я представил проблемубудет использоваться для зависимых типов.

Осторожно; Зависимая типизация - это концепция компьютерных наук, обычно понимаемая как связывание значений времени выполнения с типами.

Например, для следующего потребуются зависимые типы, так как значение времени выполнения заканчивается использованиемв определении типа:

//  Not valid Rust.
fn create_array(n: usize) -> [u8; n];
...