Является ли передача явного типа не эквивалентна выводу типа (с точки зрения выразительности)?

Я пытаюсь перевести traverse/sequenceA в Javascript. Теперь следующее поведение реализации Haskell доставляет мне неприятности:

traverse (\x -> x) Nothing -- yields Nothing
sequenceA Nothing -- yields Nothing
traverse (\x -> x) (Just [7]) -- yields [Just 7]
sequenceA (Just [7]) -- yields [Just 7]

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

instance Traversable Maybe where
    traverse _ Nothing = pure Nothing
    traverse f (Just x) = Just <$> f x

pure Nothing не должен работать в этом случае, так как не существует минимального аппликативного контекста, в который можно было бы вставить значение. Кажется, что компилятор проверяет тип этого выражения лениво, и поскольку отображение функции id выполняется поверх Nothing это просто, он просто "пропускает" ошибку типа, так сказать.

Вот мой перевод Javascript:

(Обратите внимание, что поскольку системы-прототипа Javascirpt недостаточно для пары классов типов и строгой проверки типов в любом случае нет, я работаю с кодировкой Черча и передаю ограничения типа в функции явно.)

// minimal type system realized with `Symbol`s

const $tag = Symbol.for("ftor/tag");
const $Option = Symbol.for("ftor/Option");

const Option = {};

// value constructors (Church encoded)

const Some = x => {
  const Some = r => {
    const Some = f => f(x);
    return Some[$tag] = "Some", Some[$Option] = true, Some;
  };

  return Some[$tag] = "Some", Some[$Option] = true, Some;
};

const None = r => {
  const None = f => r;
  return None[$tag] = "None", None[$Option] = true, None;
};

None[$tag] = "None";
None[$Option] = true;

// Traversable

// of/map are explicit arguments of traverse to imitate type inference
// tx[$Option] is just duck typing to enforce the Option type
// of == pure in Javascript

Option.traverse = (of, map) => ft => tx =>
 tx[$Option] && tx(of(None)) (x => map(Some) (ft(x)));

// (partial) Array instance of Applicative

const map = f => xs => xs.map(f);
const of = x => [x];

// helpers

const I = x => x;

// applying

Option.traverse(of, map) (I) (None) // ~ [None]
Option.traverse(of, map) (I) (Some([7])) // ~ [Some(7)]

Очевидно, этот перевод отклоняется от реализации на Haskell, потому что я получаю [None] где я должен получить None, Честно говоря, такое поведение в точности соответствует моей интуиции, но я думаю, интуиция не так полезна в функциональном программировании. Теперь мой вопрос

  • я просто сделал ошибку новичка?
  • или явная передача типа не эквивалентна выводу типа (с точки зрения выразительности)?

1 ответ

Решение

GHCi не пропускает ни одной ошибки типа. По умолчанию без ограничений Applicative в IO, но вы получаете это поведение только в приглашении GHCi (а не .hs исходный файл). Ты можешь проверить

> :t pure Nothing
pure Nothing :: Applicative f => f (Maybe b)

Но все еще есть

> pure Nothing
Nothing

Ваша реализация javascript в порядке; Вы прошли в Applicative экземпляр для массивов и получил то, что ожидается.

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