如何使用这些标记的联合来实现 zipPad?

我正在尝试将以下 Haskell 代码转换为 Javascript:


data These a b = This a | That b | These a b


class Align f where

  align :: (These a b -> c) -> f a -> f b -> f c


instance Align [] where

  align f []     []     = []

  align f (x:xs) []     = f (This x)    : align f xs []

  align f []     (y:ys) = f (That y)    : align f [] ys

  align f (x:xs) (y:ys) = f (These x y) : align f xs ys


liftAlign2 f a b = align t

  where t (This l)    = f l b

        t (That r)    = f a r

        t (These l r) = f l r


zipPad a b = liftAlign2 (,) a b

我在翻译这个liftAlign2函数时遇到了麻烦。它需要一个元组构造函数和两个默认值,但我不知道从何t而来。这是我到目前为止的代码:


const union = type => (tag, o) =>

  (o.type = type.name || type, o.tag = tag.name || tag, o);


const These_ = union("These");


const This = _this => These_(This, {this: _this});

const That = that => These_(That, {that});

const These = _this => that => These_(These, {this: _this, that});


const Pair = x => y => [x, y];


const align = f => ([x, ...xs]) => ([y, ...ys]) =>

  x === undefined && y === undefined ? []

    : y === undefined ? [f(This(x)), ...align(f) (xs) ([])]

    : x === undefined ? [f(That(y)), ...align(f) ([]) (ys)]

    : [f(These(x) (y)), ...align(f) (xs) (ys)];


const liftAlign2 = f => x => y => ?


const zipPad = x => y =>

  liftAlign2(Pair) (x) (y);


const zipPad ("") (0) (["foo", "bar"]) ([2, 4, 6]); // [["foo", 2], ["bar", 4], ["", 6]]

我知道 JS 代码效率很低,因为它不处理函数List类型,而是处理数组。效率对于这种翻译并不重要。


慕虎7371278
浏览 87回答 2
2回答

慕雪6442864

这就是我会做的。/*    data These a b        = This  { fromThis :: a }        | That  { fromThat :: b }        | These { fromThis :: a, fromThat :: b }*/const This  = fromThis => ({ fromThis });const That  = fromThat => ({ fromThat });const These = fromThis => fromThat => ({ fromThis, fromThat });// type Align f = forall a b c. (These a b -> c) -> f a -> f b -> f c// alignArray :: Align []const alignArray = f => xs => xs.reduceRight((next, x) => ([y, ...ys]) =>        [f(y === undefined ? This(x) : These(x)(y)), ...next(ys)],    ys => ys.map(y => f(That(y))));// liftAlign2 :: Align f -> (a -> b -> c) -> a -> b -> f a -> f b -> f cconst liftAlign2 = align => f => x => y =>    align(({ fromThis = x, fromThat = y }) =>        f(fromThis)(fromThat));// zipPad :: Align f -> a -> b -> f a -> f b -> f (a, b)const zipPad = align => liftAlign2(align)(x => y => [x, y]);// result :: [(String, Number)]const result = zipPad(alignArray)("")(0)(["foo", "bar"])([2, 4, 6]);// [["foo", 2], ["bar", 4], ["", 6]]console.log(result);注意liftAlign2和zipPad是多态的。它们不是专门用于数组的。

慕丝7291255

等效于的 javascriptliftAlign2是const liftAlign2 = f => x => y => align (t =>         f (t.this === undefined ? x : t.this) (t.that === undefined ? y : t.that)    );liftAlign2调用你的align函数。它传递的参数是一个以 aThese作为参数的函数。如果它们存在,它返回调用的结果,如果f它们These不存在则回退到。xy通过这样做,它f从一个对两个普通值进行操作的函数“提升”到一个对两个列表进行操作的函数。在zipPad fis 中Pair,因此这会从两个列表构造成对的值,直到最短列表的长度,然后重复回退值直到最长列表的长度。值得注意的是,这并不完全等同于 Haskell 代码。这是因为 Haskell 代码更具多态性;它允许您调用liftAlign2(也ZipPad)作为类型类实例的任何Align类型。虽然这包括列表,但不仅限于列表。相比之下,javascript 代码专门用于 js 数组。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript