122

我最近注意到的一个短语是“无点”风格的概念......

首先,有这个问题,还有这个问题。

然后,我发现他们在这里提到“另一个可能值得讨论的话题是作者不喜欢无点风格。”

什么是“无点”风格?有人可以给出简明的解释吗?它与“自动”柯里化有关吗?

为了了解我的水平 - 我一直在自学 Scheme,并编写了一个简单的 Scheme 解释器......我了解“隐式”柯里化是什么,但我不知道任何 Haskell 或 ML。

4

6 回答 6

75

只需查看Wikipedia 文章即可获得您的定义:

隐式编程(无点编程)是一种编程范式,其中函数定义不包括有关其参数的信息,使用组合器和函数组合 [...] 而不是变量。

哈斯克尔示例:

常规(您明确指定参数):

sum (x:xs) = x + (sum xs)
sum [] = 0

无点(sum没有任何明确的参数 - 它只是一个+以 0 开头的折叠):

 sum = foldr (+) 0

或者更简单:g(x) = f(x)你可以只写. 而不是g = f.

所以是的:它与柯里化(或函数组合之类的操作)密切相关。

于 2009-06-03T12:38:22.703 回答
42

无点风格意味着被定义的函数的参数没有明确提及,该函数是通过函数组合来定义的。

如果你有两个功能,比如

square :: a -> a
square x = x*x

inc :: a -> a
inc x = x+1

如果你想将这两个函数组合成一个计算函数x*x+1,你可以像这样定义它“point-full”:

f :: a -> a
f x = inc (square x)

无点替代方案是不谈论论点x

f :: a -> a
f = inc . square
于 2009-06-03T12:46:49.347 回答
17

JavaScript 示例:

//not pointfree cause we receive args
var initials = function(name) {
  return name.split(' ').map(compose(toUpperCase, head)).join('. ');
};

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
const join = m => m.join();

//pointfree
var initials = compose(join('. '), map(compose(toUpperCase, head)), split(' '));

initials("hunter stockton thompson");
// 'H. S. T'

参考

于 2017-04-25T20:12:24.040 回答
7

无点风格意味着代码没有明确提及它的参数,即使它们存在并且正在使用。

由于函数的工作方式,这在 Haskell 中有效。

例如:

myTake = take

返回一个带有一个参数的函数,因此没有理由显式键入参数,除非您也想要。

于 2009-06-06T14:14:31.227 回答
0

尽管代码清楚地说明了无点的想法(即没有参数),但我无法使提供 Brunno 的 javascript 示例工作。所以我使用ramda.js来提供另一个例子。

假设我需要找出句子中最长的单词,给定一个字符串,"Lorem ipsum dolor sit amet consectetur adipiscing elit"我需要输出类似{ word: 'consectetur', length: 11 }

如果我使用纯 JS 样式代码,我将使用 map 和 reduce 函数像这样编写代码

let str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit'
let strArray = str.split(' ').map((item) => ({ word: item, length: item.length }))
let longest = strArray.reduce(
    (max, cur) => (cur.length > max.length ? cur : max), 
    strArray[0])
console.log(longest) 

使用 ramda,我仍然使用 map 和 reduce,但我会像这样编写代码

const R = require('ramda')
let longest = R.pipe(
  R.split(' '),
  R.map((item) => ({ word: item, length: item.length })),
  R.reduce((max, cur) => (max.length > cur.length ? max : cur), { length: 0 })
)
let tmp = longest(str)
console.log(tmp)

我会争辩说,我的 ramda 代码的要点是将我的函数链接在一起的管道,它使我的目的更加清晰。无需创建临时变量strArray是一个奖励(如果我在管道中有超过 3 个步骤,那么它将成为一个真正的奖励)。

于 2020-12-08T07:31:43.487 回答
-1

这是 TypeScript 中的一个示例,没有任何其他库:

interface Transaction {
  amount: number;
}

class Test {
  public getPositiveNumbers(transactions: Transaction[]) {
    return transactions.filter(this.isPositive);

    //return transactions.filter((transaction: {amount: number} => transaction.amount > 0));
  }

  public getBigNumbers(transactions: Transaction[]) {
    // point-free
    return transactions.filter(this.moreThan(10));

    // not point-free
    // return transactions.filter((transaction: any) => transaction.amount > 10);
  }

  private isPositive(transaction: Transaction) {
    return transactions.amount > 0;
  }

  private moreThan(amount: number) {
    return (transaction: Transaction) => {
      return transactions.amount > amount;
    }
  }
}

您可以看到无点样式更“流畅”且更易于阅读。

于 2018-02-22T00:12:25.730 回答