ContT मोनाड ट्रांसफॉर्मर का कार्यान्वयन Cont मोनैड जैसा ही है, लेकिन मैं इसे तीनों Either मामलों में लागू करने में सक्षम नहीं हूं

  • Right
  • Left वर्तमान संन्यासी क्रिया से
  • Left पिछले मोनैडिक संगणना से

अंतिम विफल हो जाता है और इसे ठीक करने के सभी प्रयास विफल हो जाते हैं:

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

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

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

const Either = union("Either");
const Left = left => Either(Left, {left});
const Right = right => Either(Right, {right});

const eithChain = mx => fm =>
  match(mx, {
    Left: _ => mx,
    Right: ({right: x}) => fm(x)
  });

const ContT = contt => record(ContT, {contt});

const contChainT = mmk => fmm =>
  ContT(c => mmk.contt(x => fmm(x).contt(c)));

const main = foo =>
  contChainT(ContT(k => k(foo))) (mx =>
    eithChain(mx) (x =>
      x === 0
        ? ContT(k => k(Left("ouch!")))
        : ContT(k => k(Right(x * x)))));

main(Right(5)).contt(console.log); // Right(25)
main(Right(0)).contt(console.log); // Left("ouch!")
main(Left("yikes!")).contt(console.log); // Type Error

यह निराशाजनक है। किसी भी संकेत की बहुत सराहना की जाती है!

1
Iven Marquardt 21 नवम्बर 2020, 23:39

2 जवाब

सबसे बढ़िया उत्तर

आपका main फ़ंक्शन चेक टाइप नहीं करता है।

const main = foo =>
  contChainT(ContT(k => k(foo))) (mx =>
    eithChain(mx) (x =>
      x === 0
        ? ContT(k => k(Left("ouch!")))
        : ContT(k => k(Right(x * x)))));

सबसे पहले, आइए इसे सरल करें। दिया गया है, const pureContT = x => ContT(k => k(x)) हम main को निम्न प्रकार से फिर से लिख सकते हैं।

const main = foo =>
  contChainT(pureContT(foo)) (mx =>
    eithChain(mx) (x =>
      pureContT(x === 0
        ? Left("ouch!")
        : Right(x * x))));

हालांकि, chain(pure(x))(f) f(x) (बाएं पहचान कानून) के समान है। इसलिए, हम और अधिक सरल बना सकते हैं।

const main = mx =>
  eithChain(mx) (x =>
    pureContT(x === 0
      ? Left("ouch!")
      : Right(x * x)));

यहां, आप समस्या देख सकते हैं। eithChain फ़ंक्शन का प्रकार निम्न है।

Either e a -> (a -> Either e b) -> Either e b

हालांकि, eithChain को दिया गया कॉलबैक Either के बजाय ContT देता है।


मैं वास्तव में कहूंगा कि आप इस समस्या से गलत तरीके से संपर्क कर रहे हैं।

ContT r m a = (a -> m r) -> m r

-- Therefore

ContT r (Either e) a = (a -> Either e r) -> Either e r

यह वह नहीं है जो आप चाहते हैं। आपको इसके बजाय EitherT ट्रांसफॉर्मर का उपयोग करना चाहिए।

EitherT e m a = m (Either e a)

Cont r a = (a -> r) -> r

-- Therefore

EitherT e (Cont r) a = Cont r (Either e a) = (Either e a -> r) -> r

यहाँ मैं क्या करूँगा।

// Left : e -> Either e a
const Left = error => ({ constructor: Left, error });

// Right : a -> Either e a
const Right = value => ({ constructor: Right, value });

// Cont : ((a -> r) -> r) -> Cont r a
const Cont = runCont => ({ constructor: Cont, runCont });

// either : (e -> b) -> (a -> b) -> Either e a -> b
const either = left => right => either => {
    switch (either.constructor) {
    case Left: return left(either.error);
    case Right: return right(either.value);
    }
};

// MonadEitherT : Monad m -> Monad (EitherT e m)
const MonadEitherT = ({ pure, bind }) => ({
    pure: x => pure(Right(x)),
    bind: m => f => bind(m)(either(e => pure(Left(e)))(f))
});

// MonadCont : Monad (Cont r)
const MonadCont = {
    pure: x => Cont(k => k(x)),
    bind: m => f => Cont(k => m.runCont(x => f(x).runCont(k)))
};

// MonadEitherCont : Monad (EitherT e (Cont r))
const MonadEitherCont = MonadEitherT(MonadCont);

// main : Either String Number -> EitherT String (Cont r) Number
const main = either => MonadEitherCont.bind(MonadCont.pure(either))(x =>
    MonadCont.pure(x === 0 ? Left("ouch!") : Right(x * x)));

// show : Either e a -> String
const show = either
    (e => `Left(${JSON.stringify(e)})`)
    (x => `Right(${JSON.stringify(x)})`);

// print : Either e a -> ()
const print = x => console.log(show(x));

main(Right(5)).runCont(print); // Right(25)
main(Right(0)).runCont(print); // Left("ouch!")
main(Left("yikes!")).runCont(print); // Left("yikes!")
2
Aadit M Shah 22 नवम्बर 2020, 07:09

आदित के उत्तर के पूरक के रूप में मैं ContT के साथ ट्रांसफॉर्मर के रूप में एक संस्करण को लागू करने में कामयाब रहा। वर्तमान निरंतरता में हेरफेर करने के लिए मुझे केवल मानक मोनाड Cont कार्यान्वयन और संबंधित lift की आवश्यकता थी:

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

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

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

const Either = union("Either");
const Left = left => Either(Left, {left});
const Right = right => Either(Right, {right});

const eithChain = mx => fm =>
  match(mx, {
    Left: _ => mx,
    Right: ({right: x}) => fm(x)
  });

const ContT = contt => record(ContT, {contt});

const contChainT = mmk => fmm =>
  ContT(k => mmk.contt(x => fmm(x).contt(k)));

const contLiftT = chain => mmk =>
  ContT(k => chain(mmk) (k));

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

const main = foo =>
  contChainT(contLiftT(eithChain) (foo)) (x =>
    x === 0
      ? ContT(k => Left("yikes!"))
      : ContT(k => k(x * x)));

const foo = main(Right(5)).contt(x => Right(log(x))); // logs 25
const bar = main(Right(0)).contt(x => Right(log(x)));
const baz = main(Left("ouch!")).contt(x => Right(log(x)));

log(foo); // Right(25)
log(bar); // Left("yikes!")
log(baz); // Left("ouch!")

ऐसा लगता है जैसे ContT/M एक मनमाना आधार मोनैड M और T/Cont के साथ एक मनमाना ट्रांसफार्मर T उनके में कम्यूटेटिव हैं पुतला हालांकि मेरे पास इस तरह के दावे को साबित करने के लिए गणितीय कौशल नहीं है।

0
Iven Marquardt 1 पद 2020, 11:49