首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用van Laarhoven镜头删除对象的聚焦属性?

如何使用van Laarhoven镜头删除对象的聚焦属性?
EN

Stack Overflow用户
提问于 2019-06-16 14:49:26
回答 2查看 81关注 0票数 3

使用我的简单镜头实现,我可以执行常见的修改、设置、获取和删除操作:

代码语言:javascript
复制
// Lens type

const Lens = f => ({runLens: f, [Symbol.toStringTag]: "Lens"});

const objLens = map => k =>
  Lens(f => o =>
    map(x => Object.assign({}, o, {[k]: x})) (f(o[k]))); // object lens

// Id type

const Id = x => ({runId: x, [Symbol.toStringTag]: "Id"});
const idMap = f => tx => Id(f(tx.runId)); // functor

// Const type

const Const = x => ({runConst: x, [Symbol.toStringTag]: "Const"});
const constMap = f => tx => Const(tx.runConst); // functor

// auxiliary function

const _const = x => y => x;

// MAIN

const o = {foo: "abc", bar: 123};

const get = objLens(constMap) ("foo").runLens(x => Const(x)) (o),
  set = objLens(idMap) ("bat").runLens(_const(Id(true))) (o),
  mod = objLens(idMap) ("foo").runLens(s => Id(s.toUpperCase())) (o),
  del = objLens(idMap) ("foo").runLens(_const(Id(null))) (o); //*

console.log("get", get.runConst);
console.log("set", set.runId);
console.log("mod", mod.runId);
console.log("del", del.runId);

然而,delete并不能令人满意,因为我想删除整个属性,而不是只将值替换为空。

我如何才能做到这一点?

*请注意,我通常会使用适当的Option类型来表示没有值。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-18 14:27:58

这就是我要做的:

代码语言:javascript
复制
// type Lens a b = forall f. Functor f => (b -> f b) -> a -> f a

// newtype Const b a = Const { getConst :: b } deriving Functor
const Const = getConst => ({ getConst, map: _ => Const(getConst) });

// newtype Identity a = Identity { runIdentity :: a } deriving Functor
const Identity = runIdentity => ({ runIdentity, map: f => Identity(f(runIdentity)) });

// remove :: String -> Object -> Object
const remove = key => ({ [key]: _, ...rest }) => rest;

// prop :: String -> Lens Object (Maybe Value)
const prop = key => fun => obj =>
    fun(obj.hasOwnProperty(key) ? { fromJust: obj[key] } : null)
        .map(data => Object.assign(remove(key)(obj), data && { [key]: data.fromJust }));

// get :: Lens a b -> a -> b
const get = lens => data => lens(Const)(data).getConst;

// modify :: Lens a b -> (b -> b) -> a -> a
const modify = lens => fun => data => lens(x => Identity(fun(x)))(data).runIdentity;

// set :: Lens a b -> b -> a -> a
const set = lens => value => modify(lens)(_ => value);

// del :: Lens a (Maybe b) -> a -> a
const del = lens => set(lens)(null);

// foo :: Lens Object (Maybe Value)
const foo = prop("foo");

console.log(get(foo)({ foo: 10, bar: 20 })); // { fromJust: 10 }
console.log(del(foo)({ foo: 10, bar: 20 })); // { bar: 20 }

可以看到,像foo这样的属性镜头的类型签名是Lens Object (Maybe Value)。这是有道理的,因为如果您尝试使用get(foo)({ bar: 20 }),您应该什么也得不到。del函数适用于任何聚焦于可能值的镜头,并将其值设置为空(即null)。

归功于Bergi的showing me,它可以在计算属性上进行模式匹配。

票数 2
EN

Stack Overflow用户

发布于 2019-06-16 16:51:02

一种可能的方法是定义一个表示删除的特殊类型:

代码语言:javascript
复制
const Lens = f => ({runLens: f, [Symbol.toStringTag]: "Lens"});

const objLens = map => k =>
  Lens(f => o => map(x => {
    if (x[Symbol.toStringTag] === "Deleter") {
      const p = Object.assign({}, o);
      delete p[k];
      return p;
    }

    else
      return Object.assign({}, o, {[k]: x});
    }) (f(o[k])));

const Id = x => ({runId: x, [Symbol.toStringTag]: "Id"});
const idMap = f => tx => Id(f(tx.runId)); // functor

const _const = x => y => x;

// deletion type

const Deleter =
  ({get runDeleter() {return Deleter}, [Symbol.toStringTag]: "Deleter"});

// MAIN

const o = {foo: "abc", bar: 123};

const del = objLens(idMap) ("foo").runLens(_const(Id(Deleter))) (o);

console.log("del", del.runId);

然而,_const(Id(Deleter))并不是特别直观,但看起来有点老土。希望有更好的方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56616733

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档