Functional programming “什么是”呢;“无积分”;风格(在函数式编程中)?

Functional programming “什么是”呢;“无积分”;风格(在函数式编程中)?,functional-programming,coding-style,scheme,pointfree,Functional Programming,Coding Style,Scheme,Pointfree,我最近注意到的一个短语是“无点”风格的概念 首先,有一个问题,还有 然后,我发现他们提到“另一个值得讨论的话题是作者对无点风格的厌恶。” 什么是“无点”风格?有人能给一个简洁的解释吗?这与“自动”咖喱有关吗 为了了解我的水平,我一直在自学Scheme,并编写了一个简单的Scheme解释器。。。我理解什么是“隐式”咖喱,但我不知道任何Haskell或ML。只要看一下就可以得到你的定义: 默契编程(无点编程)是一种编程范式,其中函数定义不包含有关其参数的信息,使用组合符和函数组合[…]而不是变量 哈

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

首先,有一个问题,还有

然后,我发现他们提到“另一个值得讨论的话题是作者对无点风格的厌恶。”

什么是“无点”风格?有人能给一个简洁的解释吗?这与“自动”咖喱有关吗

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

只要看一下就可以得到你的定义:

默契编程(无点编程)是一种编程范式,其中函数定义不包含有关其参数的信息,使用组合符和函数组合[…]而不是变量

哈斯克尔示例:

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

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

或者更简单:您可以只编写
g=f
,而不是
g(x)=f(x)


因此,是的:它与curry(或函数组合之类的操作)密切相关。

无点风格意味着没有明确提到所定义函数的参数,函数是通过函数组合定义的

如果你有两个函数,比如

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

inc :: a -> a
inc x = x+1
如果您想将这两个函数合并为一个计算
x*x+1
,可以将其定义为“满点”,如下所示:

f :: a -> a
f x = inc (square x)
无点替代方案是不讨论参数
x

f :: a -> a
f = inc . square

无点样式意味着代码不显式地提到它的参数,即使它们存在并且正在使用

这在Haskell中有效,因为函数的工作方式

例如:

myTake = take
返回一个接受一个参数的函数,因此没有理由显式键入参数,除非您也需要。

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'

以下是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;
    }
  }
}

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

我无法使Bruno提供的javascript示例正常工作,尽管代码清楚地说明了无点思想(即无参数)。所以我用它来提供另一个例子

假设我需要找出一个句子中最长的单词,给定一个字符串
“Lorem ipsum dolor sit amet concertetur adipising elit”
我需要输出类似
{word:'concertetur',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个步骤,那么它将成为一个真正的奖励)。

啊,我明白了!所以你总是通过组合其他函数而不是声明参数来建立新函数。。。非常优雅!我真的不喜欢在编程时给变量/参数起新名字。这是我喜欢无点风格的一个重要原因!它与Currying有什么关系?@kaleidic:因为没有变量名,您需要编写部分应用的函数。这就是我们所说的咖喱(或者更准确地说,通过咖喱可以实现的东西)你不是指
sum(x:xs).
而不是
sum(x:xs).
?愚蠢的是,在哈斯凯尔,“无点”的方式通常看起来更尖锐(更多周期)。这种烦恼会产生很好的记忆力。(现实世界哈斯凯尔对此的评论)关于@Dan的评论,哈斯凯尔维基页面解释了为什么它被称为无点。@Dan:我不认为这很愚蠢,因为哈斯凯尔点应该是“那个圆操作符”(不过看起来应该更像°)。但它令人困惑,尤其是当你对函数式编程语言还不熟悉的时候;关于haskell的每一本介绍书都应该解释无点风格。有时,它在haskell 98中不起作用,如在
myShow=show
中。关于它的更多信息,请注意:要了解它为什么被称为无点访问HaskellWiki。这不是无点风格,这只是lambda和命名函数之间的区别。@kralyk我想你没有抓住重点,
这一点。超过(10)
不是命名函数,它是一个curried函数,也是一个隐式(因此无点)将
事务
作为其输入。链接已更改为,但我无法运行代码
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) 
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)