是否有两个函子之间不存在自然变换?

问题描述 投票:0回答:1

我有一个Task,它基本上是带有错误情况并入的继续类型,而Optional表示可能不会产生结果的计算。

[OptionTask似乎是自然的转变,反之亦然:

const optTask = tx =>
  match(tx, {
    None: () => Task((res, rej) => rej()),
    Some: ({some}) => Task(res => res(some))
  });

const tOption = tx =>
  tx.task(x => Some(x), _ => None);

optMap(x => x + 1) (tOption(Task(res => res(5)))); // Some(6)
optMap(x => x + 1) (tOption(Task((res, rej) => rej()))); // None

// I can transform back and forth and it still works as expeced:

optMap(x => x + 1) (tOption(optTask(Some(5)))); // Some(6)
optMap(x => x + 1) (tOption(optTask(None))); // None

但是,Task用于异步计算,这破坏了自然转换:

const delay = f => ms => x =>
  Task((res, rej) => setTimeout(x => res(f(x)), ms, x));

optMap(x => x + 1) (tOption(delay(x => log(x)) (1000) (5))); // type error

我知道为什么它不起作用。使我感到困惑的是,一旦Task成为转换的源头(并且渐进性开始发挥作用),它们似乎根本就不是自然转换。但是也许我的实现是完全错误的。

这里是完整的代码:

/***[ Auxiliary ]*************************************************************/

const record = (type, o) =>
  (o[type.name || type] = type.name || type, o);

const union = type => (tag, o) =>
  (o[type] = type, o.tag = tag.name || tag, o);

const match = (tx, o) =>
  o[tx.tag] (tx);

const thisify = f => f({});

const log = x => (console.log(x), x);

const id = x => x;

/***[ Task ]******************************************************************/

const Task = task => record(
  Task,
  thisify(o => {
    o.task = (res, rej) =>
      task(x => {
        o.task = k_ => k_(x);
        return res(x);
      }, rej);
    
    return o;
  }));

// functor

const tMap = f => tx =>
  Task((res, rej) => tx.task(x => res(f(x)), rej));

const delay = f => ms => x =>
  Task((res, rej) => setTimeout(x => res(f(x)), ms, x));

/***[ Option ]****************************************************************/

const Option = union("Option");

const None = Option("None", {});

const Some = some => Option(Some, {some});

// functor

const optMap = f => tx =>
  match(tx, {
    None: _ => None,
    Some: ({some: x}) => Some(f(x))
  });

/***[ Natural transformations ]***********************************************/

const optTask = tx =>
  match(tx, {
    None: () => Task((res, rej) => rej()),
    Some: ({some}) => Task(res => res(some))
  });

const tOption = tx =>
  tx.task(x => Some(x), _ => None);

/***[ Main ]******************************************************************/

const a = optMap(x => x + 1) (tOption(Task(res => res(5))));
const b = optMap(x => x + 1) (tOption(Task((res, rej) => rej())));

const c = optMap(x => x + 1) (tOption(optTask(Some(5))));
const d = optMap(x => x + 1) (tOption(optTask(None)));

console.log(a, b, c, d);

try {
  const e = optMap(x => x + 1) (tOption(delay(x => log(x)) (1000) (5)));
} catch(e) {console.log(e.message)}
javascript functional-programming functor category-theory
1个回答
0
投票

是的,有很多函子没有自然变换。考虑身份仿函数。从Option到它的转换不可能自然,因为没有什么可以将None转换为。

© www.soinside.com 2019 - 2024. All rights reserved.