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
यह निराशाजनक है। किसी भी संकेत की बहुत सराहना की जाती है!
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!")
आदित के उत्तर के पूरक के रूप में मैं 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
उनके में कम्यूटेटिव हैं पुतला हालांकि मेरे पास इस तरह के दावे को साबित करने के लिए गणितीय कौशल नहीं है।