为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

慕虎7371278 2022-06-05 09:45:09
我正在尝试将以下 Haskell 代码转换为 Javascript:data These a b = This a | That b | These a bclass Align f where  align :: (These a b -> c) -> f a -> f b -> f cinstance 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 ysliftAlign2 f a b = align t  where t (This l)    = f l b        t (That r)    = f a r        t (These l r) = f l rzipPad 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类型,而是处理数组。效率对于这种翻译并不重要。
查看完整描述

2 回答

?
慕雪6442864

TA贡献1812条经验 获得超5个赞

这就是我会做的。


/*

    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 c

const 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是多态的。它们不是专门用于数组的。


查看完整回答
反对 回复 2022-06-05
?
慕丝7291255

TA贡献1859条经验 获得超6个赞

等效于的 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 数组。


查看完整回答
反对 回复 2022-06-05
  • 2 回答
  • 0 关注
  • 86 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信