Есть ли внутренняя причина, объясняющая, почему в Rust нет типов более высокого порядка?

В Rust нет типов более высокого порядка. Например, функтор (и, следовательно, монада) не может быть написан на Rust. Я хотел бы знать, есть ли глубокая причина, объясняющая это и почему.

Например, причина, которую я могу понять, может заключаться в том, что не существует абстракции с нулевой стоимостью, делающей возможным HKT. Или вывод типа значительно сложнее. И, конечно же, я также ищу объяснение, показывающее мне, почему это реальное ограничение.

Если ответ уже был дан где-то еще, не могли бы вы дать мне ссылку?


person abitbol    schedule 25.09.2019    source источник


Ответы (1)


Время и приоритет.

Отсутствие типов высшего порядка само по себе не является дизайнерским решением. Предполагается, что в Rust будет такая форма, причем наиболее популярным кандидатом будут Generic Associated Types. (2017) на данный момент.

Однако их реализация требует времени и не считается приоритетной по сравнению с другими функциями. Например, async/await имеет приоритет над HKT, и дженерики const также имеют приоритет.


Например, функтор (и, следовательно, монада) не может быть написан на Rust.

На самом деле они могут, хотя это немного громоздко.

См. отличный лайфхак Эдмунда Смита, который он разместил на https://www.reddit..com/r/rust/comments/cajn09/new_method_for_emulating_higherkinded_types_in/:

trait Unplug {
    type F; //The representation type of the higher-kinded type
    type A; //The parameter type
}

trait Plug<A> {
    type result_t;
}

pub  struct  Concrete<M: Unplug + Plug<A>,A> {
    pub unwrap: <M as Plug<A>>::result_t
}

impl<M: Unplug + Plug<A>, A> Concrete<M,A> {
    fn of<MA: Unplug<F=M, A=A> + Plug<A>>(x: MA) -> Self
        where M: Plug<A, result_t = MA>
    {
        Concrete { unwrap: x }
    }
}

С помощью которого они реализуют трейт Functor:

pub trait Functor: Unplug + Plug<<Self as Unplug>::A> {
    fn map<B, F>(f: F, s: Self) -> <Self as Plug<B>>::result_t
        where
            Self: Plug<B>,
            F: FnMut(<Self as Unplug>::A) -> B
        ;
}

//  Example impl for a represented Vec
impl<A> Functor for Concrete<Vec<forall_t>, A> {
    //  remember, Self ~ (Vec<_>, A) ~ "f a"
    fn map<B, F>(f: F, s: Self) -> <Self as Plug<B>>::result_t
        where
            F: FnMut(<Self as Unplug>::A) -> B 
    {        
        Concrete::of(s.unwrap.into_iter().map(f).collect())
    }
}

И с этого момента сборки Applicative и Monad:

pub trait Applicative: Functor {
    fn pure(s: <Self as Unplug>::A) -> Self;

    fn app<B, F>(
        f: <Self as Plug<F>>::result_t, //M<F>
        s: Self                         //M<A>
    ) -> <Self as Plug<B>>::result_t   //M<B>
    where
        F: FnMut(<Self as Unplug>::A) -> B + Clone,
        Self: Plug<F> + Plug<B> + Unplug,
        <Self as Plug<F>>::result_t:
            Unplug<F=<Self as Unplug>::F, A=F> +
            Plug<F> +
            Clone,
        <Self as Unplug>::F: Plug<F>
    ;
}

pub trait Monad : Applicative {
    fn bind<F,B>(f: F, s: Self) -> <Self as Plug<B>>::result_t
    where
        Self: Plug<F>+Plug<B>,
        F: FnMut(<Self as Unplug>::A) ->
            <Self as Plug<B>>::result_t + Clone
        ;
}

Я сказал, что это немного громоздко...

person Matthieu M.    schedule 25.09.2019
comment
Хорошо, большое спасибо за ваш ответ! Мне просто интересно, зачем использовать что-то сложное, например, GAT для HKT, вместо простой формы Haskell. Но, возможно, я что-то упускаю... - person abitbol; 25.09.2019
comment
@abitbol Я думаю, вы упускаете из виду, что вы не можете просто добавить Haskell-подобные HKT в Rust - вам нужно (1) определить, как эта функция взаимодействует с остальной частью языка, и (2) фактически реализовать ее. GAT — это небольшая ортогональная функция, которая уже полностью определена и реализуется. Это Серия блогов (в 4 частях) подробно описывает взаимосвязь между GAT (в то время называемыми ATC) и HKT. - person trentcl; 25.09.2019
comment
Часть 3, в частности, подчеркивает некоторые различия между Rust и Haskell, из-за которых было бы неудобно привязывать (части) системы Haskell к Rust. - person trentcl; 25.09.2019
comment
Да, я полностью с вами согласен: что касается текущего состояния ржавчины, добавление какой-либо функции может быть сложным. Я просто хотел знать, была ли причина, по которой первоначальный дизайн не включал эту функцию с самого начала. На самом деле, мне просто интересно узнать требования дизайна ржавчины, которые сделали ржавчину похожей на сегодняшнюю ржавчину. Но ваши ссылки могут помочь мне узнать это, я собираюсь прочитать это. Благодарю вас! - person abitbol; 25.09.2019
comment
Как я могу отслеживать, что планируется добавить в Rust со временем? - person user1857492; 24.09.2020
comment
@user1857492 user1857492: Я бы сказал, следя за обсуждениями, особенно RFC. В этом отношении он очень похож на Python/Java/C++. - person Matthieu M.; 24.09.2020