Was ist ein "punktfreier" Stil (in der funktionalen Programmierung)?

100

Ein Satz, den ich kürzlich bemerkt habe, ist das Konzept des "punktfreien" Stils ...

Zuerst gab es diese und auch diese Frage .

Dann entdeckte ich hier, dass sie erwähnen: "Ein weiteres Thema, das es wert sein könnte, diskutiert zu werden, ist die Abneigung der Autoren gegen punktfreien Stil."

Was ist "punktfreier" Stil? Kann jemand eine kurze Erklärung geben? Hat es etwas mit "automatischem" Currying zu tun?

Um eine Vorstellung von meinem Niveau zu bekommen - ich habe mir selbst Scheme beigebracht und einen einfachen Scheme-Interpreter geschrieben ... Ich verstehe, was "implizites" Currying ist, aber ich kenne kein Haskell oder ML.

Paul Hollingsworth
quelle
3
Nur eine Anmerkung: um zu sehen, warum es pointfree heißt, besuchen Sie Pointfree / Aber pointfree hat mehr Punkte! bei HaskellWiki.
Petr Pudlák

Antworten:

66

Schauen Sie sich einfach den Wikipedia-Artikel an, um Ihre Definition zu erhalten:

Die stillschweigende Programmierung (punktfreie Programmierung) ist ein Programmierparadigma, bei dem eine Funktionsdefinition keine Informationen zu ihren Argumenten enthält, wobei Kombinatoren und die Funktionszusammensetzung [...] anstelle von Variablen verwendet werden.

Haskell Beispiel:

Konventionell (Sie geben die Argumente explizit an):

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

Punktfrei ( sumhat keine expliziten Argumente - es ist nur eine Falte +mit 0):

 sum = foldr (+) 0

Oder noch einfacher: Stattdessen g(x) = f(x)könnte man einfach schreiben g = f.

Also ja: Es hängt eng mit dem Curry (oder Operationen wie der Funktionszusammensetzung) zusammen.

Dario
quelle
8
Ahh ich verstehe! Sie bauen also immer neue Funktionen auf, indem Sie andere Funktionen kombinieren, anstatt Argumente zu deklarieren ... Sehr elegant!
Paul Hollingsworth
22
Ich mag es wirklich nicht, mir beim Programmieren neue Namen für Variablen / Argumente einfallen zu lassen. Das ist ein großer Grund, warum ich punktfreien Stil liebe!
Martijn
2
Inwiefern hängt es mit Curry zusammen?
Kaleidic
1
@kaleidic: Weil Sie ohne Variablennamen teilweise angewendete Funktionen erstellen müssen. Das nennen wir Currying (oder genauer gesagt, was durch Currying möglich wird)
Dario
1
Meinst du nicht sum (x:xs) ...statt sum sum (x:xs) ...?
Ehtesh Choudhury
33

Punktfreier Stil bedeutet, dass die Argumente der zu definierenden Funktion nicht explizit erwähnt werden, sondern dass die Funktion durch Funktionszusammensetzung definiert wird.

Wenn Sie zwei Funktionen haben, wie

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

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

und wenn Sie diese beiden Funktionen zu einer berechneten kombinieren möchten x*x+1, können Sie sie wie folgt "punktvoll" definieren:

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

Die sinnlose Alternative wäre, nicht über das Argument zu sprechen x:

f :: a -> a
f = inc . square
etw
quelle
21
Dummerweise ist in Haskell der "punktfreie" Weg normalerweise derjenige, der spitzer aussieht (mehr Perioden). Dieser Ärger macht eine ausgezeichnete Mnemonik. (Das Buch Real World Haskell kommentiert dies.)
Dan
3
In Bezug auf @ Dans Kommentar bietet die Pointfree HaskellWiki-Seite eine Erklärung, warum sie als pointfree bezeichnet wird .
Vincent Savard
2
@ Dan: Ich denke nicht, dass es dumm ist, da der Haskell-Punkt "dieser Kreisoperator" sein soll (sollte aber eher wie ° aussehen). Aber verwirrend ist es, besonders wenn Sie mit funktionalen Programmiersprachen noch nicht vertraut sind. Jedes Intro-Buch über Haskell sollte punktfreien Stil erklären.
Sebastian Mach
12

Ein JavaScript-Beispiel:

//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'

Referenz

Brunno
quelle
5

Punktfreier Stil bedeutet, dass der Code seine Argumente nicht explizit erwähnt, obwohl sie vorhanden sind und verwendet werden.

Dies funktioniert in Haskell aufgrund der Funktionsweise von Funktionen.

Zum Beispiel:

myTake = take

Gibt eine Funktion zurück, die ein Argument akzeptiert. Daher gibt es keinen Grund, das Argument explizit einzugeben, es sei denn, Sie möchten dies auch.

Rayne
quelle
1
Manchmal funktioniert es in Haskell 98 nicht wie in myShow = show. Es gibt mehr darüber im Haskell-Wiki
Ehtesh Choudhury
-1

Hier ist ein Beispiel in TypeScript ohne andere Bibliothek:

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;
    }
  }
}

Sie können sehen, dass der punktfreie Stil "fließender" und leichter zu lesen ist.

AZ.
quelle
Das ist kein punktfreier Stil, das ist nur eine Unterscheidung zwischen einem Lambda und einer benannten Funktion.
Kralyk
@kralyk Ich denke, Sie haben den Punkt verpasst, this.moreThan(10)ist keine benannte Funktion, sondern eine Curry-Funktion sowie eine Funktion, die implizit (also punktfrei) a transactionals Eingabe verwendet.
AZ.