2 回答
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是多态的。它们不是专门用于数组的。
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 数组。
添加回答
举报