Фильтрация списков Maybes - PullRequest
0 голосов
/ 17 марта 2020

Если у меня есть Maybe<int>[], и я хотел бы взять только те значения массива, которые не являются None, каков наилучший способ сделать это, и чтобы машинописный текст понимал, что он получает?

Я предполагаю, что способ печатать будет означать, что я получу int[].

Я мог бы сделать:

const x: int[] = [1, 2, 3, null]
  .map(Maybe.fromNull)
  .filter(x => !x.isNone())
  .map(x => x.getOrElse(-1)) // this ought not to ever require the default value

Но это кажется очень неуклюжим и многословным. Я чувствую, что мне не хватает лучшего способа справиться с этим.

1 Ответ

1 голос
/ 17 марта 2020

Ответ на ваш вопрос зависит от конкретной реализации Maybe, поэтому я включаю один из них, который я использую ниже. По сути, сейчас вам нужно явно аннотировать функцию как тип защиты, чтобы это работало. Поговаривали о поддержке not T типов, которые необходимы для работы !isNone(), но пока этого не произошло. Код ниже работает, хотя:

const MaybeTag = Symbol("Maybe");

type Nothing<T> = { [MaybeTag]?: T; name: "Nothing" } ;
type Just<T> ={ [MaybeTag]?: T; name: "Just";  value: T } ;
type Maybe<T> = Just<T> | Nothing<T>

const Maybe = {
    Just<T>(value: T): Just<T> {
        return { name: "Just", value };
    },
    Nothing<T = never>(): Nothing<T> {
        return { name: "Nothing" };
    },
    isNothing<T>(maybe: Maybe<T>): maybe is Nothing<T> {
        return maybe.name === "Nothing";
    },
    isJust<T>(maybe: Maybe<T>): maybe is Just<T> {
        return maybe.name === "Just";
    },
    fromNull<T>(value: T | null | undefined): Maybe<T> {
        if (value == null) return Maybe.Nothing();
        return Maybe.Just(value);
    }
}

const x: number[] = [1, 2, 3, null]
  .map(Maybe.fromNull)
  .filter(Maybe.isJust)
  .map(x => x.value) // x is Just<number> as expected

const x: number[] = [1, 2, 3, null]
  .map(Maybe.fromNull)
  // Note the explicit type guard
  .filter(function<T>(x: Maybe<T>): x is Just<T> { 
    return !Maybe.isNothing(x);
  })
  .map(x => x.value) // x is Just<number> as expected

...