布尔“not”函数的函数组合(不是布尔值)

2024-01-01

我正在 TS 中工作,但会在下面显示 tsc -> ES6 代码。

我有一个函数“isDigit”,如果字符代码在数字 0-9 范围内,则该函数返回 true。该函数 (isDigit) 必须作为参数传递到高阶函数中。

const isDigit = (char, charC = char.charCodeAt(0)) => (charC > 47 && charC < 58);

作为另一个高阶函数的一部分,我需要知道一个字符是否不是数字。当然,像下面这样的东西会起作用......

const notDigit = (char, charC = char.charCodeAt(0)) => !isDigit(char);

但如果我可以将 isDigit 与另一个函数(我将称为 notFun)组合起来,将 not 运算符应用于 isDigit 的结果来生成 notDigit,那会更令人满意。在下面的代码中,“boolCond”用于控制是否应用 not 运算符。下面的代码“几乎”有效,但它返回一个布尔值,而不是一个在处理高阶函数时不起作用的函数。

const notFun = (myFun, boolCond = Boolean(condition)) => (boolCond) ? !myFun : myFun;

通常情况下,在准备这个问题时,我最终找到了答案,所以我将分享我的答案,看看社区有哪些改进。

上面观察到的问题(获取布尔值而不是函数)是“函数组合”的问题,我在 Eric Elliot 的帖子中找到了几种可选方法,从中我选择了“管道”函数组合方法。

请参阅埃里克·埃利奥特 (Eric Elliot) 的精彩帖子 https://medium.com/javascript-scene/master-the-javascript-interview-what-is-function-composition-20dfb109a1a0#.amiqhc2eh

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

这个管道组合函数的实现看起来像下面的 TS...对于那些在家中学习的人,我已经包含了递归计数 while 'recCountWhile' 函数,它是组合(即管道)函数的最终使用者(请原谅这些函数出现的顺序相反,但这样做是为了清楚起见)。

export const removeLeadingChars: (str: string) => string = 
  (str, arr = str.split(''), 
   dummy = pipe(isDigit, notFun), cnt = recCountWhile(arr, dummy, 0)) => 
          arr.slice(cnt).reduce((acc, e) => acc.concat(e),'');

export const recCountWhile: (arr: string[], fun: (char: string) => boolean, sum: number) => number = 
  (arr, fun, sum, test = (!(arr[0])) || !fun(arr[0]) ) => 
      (test) ? sum : recCountWhile(arr.slice(1), fun, sum + 1);

结果是一个组合函数“removeLeadingChars”,它将“isDigit”与“notFun”(使用管道函数)组合成“dummy”函数,并传递给recCountWhile函数。这将返回引导字符串的“非数字”(即除数字之外的字符)的计数,然后将这些字符从数组的头部“切片”,并将数组缩减回字符串。

我非常希望听到任何可能改进这种方法的调整。


很高兴您找到答案并仍然发布问题。我认为这是一个很好的学习方式。

为了进行函数组合练习,这就是我如何构建你的函数。

see 把事情简单化下面是我如何用实际代码处理这个问题

const comp = f => g => x => f(g(x))

const ord = char => char.charCodeAt(0)

const isBetween = (min,max) => x => (x >= min && x <= max)

const isDigit = comp (isBetween(48,57)) (ord)

const not = x => !x

const notDigit = comp (not) (isDigit)

console.log(isDigit('0')) // true
console.log(isDigit('1')) // true
console.log(isDigit('2')) // true
console.log(isDigit('a')) // false

console.log(notDigit('0')) // false
console.log(notDigit('a')) // true

代码审查

顺便说一句,你使用默认参数和泄露的私有 API 所做的事情非常奇怪

// charC is leaked API
const isDigit = (char, charC = char.charCodeAt(0)) => (charC > 47 && charC < 58);

isDigit('9')     // true
isDigit('9', 1)  // false   wtf
isDigit('a', 50) // true    wtf

我知道你可能正在这样做,所以你不必写这个

// I'm guessing you want to avoid this
const isDigit = char => {
  let charC = char.charCodeAt(0)
  return charC > 47 && charC < 58
}

...但该函数实际上要好得多,因为它不会泄漏私有 API(charCvar) 给外部调用者

你会注意到我解决这个问题的方法是使用我自己的isBetween组合器和柯里化导致了一个非常干净的实现,我认为

const comp = f => g => x => f(g(x))

const ord = char => char.charCodeAt(0)

const isBetween = (min,max) => x => (x >= min && x <= max)

const isDigit = comp (isBetween(48,57)) (ord)

更多的代码会执行这种可怕的默认参数操作

// is suspect you think this is somehow better because it's a one-liner
// abusing default parameters like this is bad, bad, bad
const removeLeadingChars: (str: string) => string = 
  (str, arr = str.split(''), 
   dummy = pipe(isDigit, notFun), cnt = recCountWhile(arr, dummy, 0)) => 
          arr.slice(cnt).reduce((acc, e) => acc.concat(e),'');

尽量避免为了让一切变得简单而牺牲代码的质量。上面的功能比这里的功能差很多

// huge improvement in readability and reliability
// no leaked variables!
const removeLeadingChars: (str: string) => string = (str) => {
  let arr = str.split('')
  let dummy = pipe(isDigit, notFun)
  let count = recCountWhile(arr, dummy, 0)
  return arr.slice(count).reduce((acc, e) => acc.concat(e), '')
}

把事情简单化

您可以...保留它,而不是将字符串拆分为数组,然后迭代数组以计算前导非数字,然后根据计数分割数组的头部,最后将数组重新组装为输出字符串简单的

const isDigit = x => ! Number.isNaN (Number (x))

const removeLeadingNonDigits = str => {
  if (str.length === 0)
    return ''
  else if (isDigit(str[0]))
    return str
  else
    return removeLeadingNonDigits(str.substr(1))
}

console.log(removeLeadingNonDigits('hello123abc')) // '123abc'
console.log(removeLeadingNonDigits('123abc'))      // '123abc'
console.log(removeLeadingNonDigits('abc'))         // ''

所以,是的,我不确定你问题中的代码是否只是为了练习,但如果这确实是最终目标,那么确实有一种更简单的方法可以从字符串中删除前导非数字。

The removeLeadningNonDigits这里提供的函数是纯函数,不会泄漏私有变量,处理其给定域(字符串)的所有输入,并保持易于阅读的风格。我会建议这个(或其他东西likethis)与您问题中建议的解决方案进行比较。


函数组合与“管道”

组合两个函数通常按从右到左的顺序完成。有些人发现很难阅读/推理,所以他们想出了一个从左到右的函数作曲家,大多数人似乎都同意这一点pipe是个好名字。

你的没有任何问题pipe实现,但我认为很高兴看到如果您努力使事情尽可能简单,生成的代码会变得干净一些。

const identity = x => x

const comp = (f,g) => x => f(g(x))

const compose = (...fs) => fs.reduce(comp, identity)

或者如果你想和我的咖喱一起工作comp之前在帖子中介绍过

const identity = x => x

const comp = f => g => x => f(g(x))

const uncurry = f => (x,y) => f(x)(y)

const compose = (...fs) => fs.reduce(uncurry(comp), identity)

这些功能中的每一个都有其自己独立的效用。所以如果你定义compose这样,您就可以免费获得其他 3 个功能。

将此与pipe您的问题中提供的实施:

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

同样,这很好,但它将所有这些东西混合在一个函数中。

  • (v,f) => f(v)本身就是有用的函数,为什么不单独定义它,然后通过名称使用它呢?
  • the => x正在合并具有无数用途的恒等函数
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

布尔“not”函数的函数组合(不是布尔值) 的相关文章

  • 将鼠标悬停时的鼠标光标更改为锚状样式

    如果我将鼠标悬停在div鼠标光标将更改为 HTML 锚点中的光标 我怎样才能做到这一点 假设你的div has an id myDiv 将以下内容添加到您的 CSS 中 这cursor pointer指定光标应与用于锚点 超链接 的手形图标
  • Chart.js 在初始化时设置活动段

    我正在使用 Chart js v2 并且尝试在加载图表时模拟圆环图上某个段的 悬停状态 因此看起来有一个部分已突出显示 我已经搜索和梳理了代码一天 但找不到一个好的方法来做到这一点 提前致谢 设置片段的悬停样式有点令人困惑 因为它没有真正记
  • 为什么我的淘汰单选按钮在另一个具有点击绑定的元素内时会失败?

    我有一个单选按钮列表 我想要点击 li 他们还检查单选按钮 这一切都有效 直到我放了一个name单选元素上的属性 然后我的代码停止工作 我的代码如下所示 ul li li ul li
  • 如何更改 Google Maps v3 API for Directions 中的开始和结束标记图像

    我使用 DirectionsRender 绘制了一条路线 但我不知道如何用我自己的标记替换通用的 Google 标记 我知道并在正常的谷歌地图情况下使用它 但发现很难用开始和结束的方向标记来做到这一点 如果这是一个愚蠢的问题 感谢您的任何建
  • Scala 解析器组合器的运算符优先级

    我正在研究需要考虑运算符优先级的解析逻辑 我的需求并不太复杂 首先 我需要乘法和除法比加法和减法具有更高的优先级 例如 1 2 3 应视为 1 2 3 这是一个简单的例子 但你明白了 我需要将更多自定义标记添加到优先级逻辑中 我可以根据此处
  • 隐藏 Div 的父级

    我只是想隐藏父divcomments section div class content content green div div div 我试过这个 document getElementById comments section pa
  • 调整图像大小并将画布旋转 90 度

    这里有很多关于在 js 上使用画布旋转图像的主题 我阅读了其中的大部分内容 但无法找到解决我的问题的方法 我正在接收任何分辨率的图像 来自上传组件 我将其大小调整为 1024x768 如下所示 var canvas document cre
  • 使用 CSS 或 Javascript 填充动画

    我只是想知道是否可以使用 CSS 或 javascript 创建填充动画 基本上我想创建一个填充动画 如下图所示 http i40 tinypic com eit6ia png http i40 tinypic com eit6ia png
  • 闭包作为数据合并习惯的解决方案

    我正在尝试解决闭包问题 而且我think我发现了一个案例 他们可能会有所帮助 我有以下几部分需要处理 一组正则表达式 旨在清理状态名称 位于函数中 具有州名称 上述函数创建的标准化形式 和州 ID 代码的 data frame 用于链接两者
  • window.location 和 location.href 之间的区别

    我对之间的区别感到困惑window location and location href 两者似乎都以相同的方式行事 有什么不同 window location是一个对象 它保存有关当前文档位置的所有信息 主机 href 端口 协议等 lo
  • 刷新页面时保存用户的选择

    我目前有一个页面显示不同团队的数据 我有一些数据 用户可以单击使其处于 打开 或 关闭 状态 并为每个数据显示不同的图标 它基本上就像一个清单 只是没有物理复选框 我想记住哪些 复选框 已被选中 即使在用户刷新页面或关闭浏览器并稍后返回之后
  • 有没有办法在 onclick 触发时禁用 iPad/iPhone 上的闪烁/闪烁?

    所以我有一个有 onclick 事件的区域 在常规浏览器上单击时 它不会显示任何视觉变化 但在 iPad iPhone 上单击时 它会闪烁 闪烁 有什么办法可以阻止它在 iPad iPhone 上执行此操作吗 这是一个与我正在做的类似的示例
  • Vuejs 2:去抖动不适用于手表选项

    当我在 VueJs 中反跳此函数时 如果我提供毫秒数作为原语 它就可以正常工作 但是 如果我将其提供为对 prop 的引用 它会忽略它 这是道具的缩写版本 props debounce type Number default 500 这是不
  • 从数据库检查数据的异步解决方案各种循环子句

    我想要做的是异步检查数据库并从中获取结果 在我的应用程序中我试图实现Asynchronously将此步骤解决为 从数据库中检查手机号码JsonArray循环子句的种类 Create JsonArray从结果 打印创建的数组 我学到了足够多的
  • 在移动设备上滚动

    这个问题更多的是一个建议研究 我确实希望它对其他人有帮助 并且它不会关闭 因为我不太确定在哪里寻求有关此事的建议 在过去的 6 个月里 我一直在进行移动开发 我有机会处理各种设备上的各种情况和错误 最麻烦的是滚动问题 当涉及到在网站的多个区
  • 日期出现奇怪的错误,“未捕获非法访问”

    所以我试图找到最新的DateJavascript 可以处理 我把它减少到 9 月 275760 并增加了我开始捕获未捕获的天数illegal access例外new Date 09 24 275760 to new Date 10 13 2
  • 如何隐藏/禁用 Highcharts.js 中的图例框?

    我想问是否可以使用 HighCharts js 库隐藏图表中的所有图例框 var chart object chart renderTo render to type graph type colors graph colors title
  • 用于交互式图形绘制的轻量级 JavaScript 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有兴趣了解用于绘制交互式图表的最轻量级 javascript 库 我掌握的数据主要是与海洋研究相关的科学数据 我知道一些 jquery
  • 如何用另一个响应替换窗口的 URL 哈希?

    我正在尝试使用替换方法更改哈希 URL document location hash 但它不起作用 function var anchor document location hash this returns me a string va
  • 如何使用asm.js进行测试和开发?

    最近我读到asm js规范 看起来很酷 但是是否有任何环境 工具来开发和测试这个工具 这还只是处于规范阶段吗 您可以尝试使用 emscripten 和 ASM JS 1 并从侧分支在 firefox 构建中运行它 有关 asm js 的链接

随机推荐