显式类型传递不等同于类型推断(在表达方面)吗?

时间:2017-06-13 10:23:09

标签: javascript haskell functional-programming type-inference traversable

我尝试将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是一个noop,它只是“忽略”了类型错误,可以这么说。

这是我的Javascript翻译:

(请注意,由于Javascirpt的原型系统不适用于几个类型类,并且无论如何都没有严格的类型检查,我使用Church编码并明确地将类型约束传递给函数。)

// 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 个答案:

答案 0 :(得分:3)

GHCi不会忽略任何类型错误。它默认为无约束ApplicativeIO,但您只能在GHCi提示符(而不是.hs源文件)中获得此行为。你可以检查

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

但仍然有

> pure Nothing
Nothing

你的javascript实现很好;你为数组传递了一个Applicative实例并得到了预期的结果。