2016-08-21 5 views
3

Ich habe vor kurzem begonnen, das Buch Funktionale Programmierung in Scala von Paul Chiusano und Rúnar Bjarnason zu lesen, um FP zu lernen. Ich will es lernen, weil es meinen Kopf ein wenig öffnet, meine Denkweise verdreht und hoffentlich auch hoffentlich zu einem besseren Programmierer macht.Functional Programmierung Übung mit Scala

In ihrem Buch, Chp. 3, definieren sie einen grundlegenden einfach verknüpften-Liste Typ wie folgt:

package fpinscala.datastructures 

sealed trait List[+A] 
case object Nil extends List[Nothing] 
case class Cons[+A](head: A, tail: List[A]) extends List[A] 

object List { 
    def sum(ints: List[Int]): Int = ints match { 
    case Nil => 0 
    case Cons(x,xs) => x + sum(xs) 
    } 
    def product(ds: List[Double]): Double = ds match { 
    case Nil => 1.0 
    case Cons(0.0, _) => 0.0 
    case Cons(x,xs) => x * product(xs) 
    } 
    def apply[A](as: A*): List[A] = 
    if (as.isEmpty) Nil 
    else Cons(as.head, apply(as.tail: _*)) 
} 

ich jetzt arbeiten, um die Schwanz-Methode für die Umsetzung, die in Scala Bibliotheken definiert ähnlich wie der Schwanz Methode arbeiten soll. Ich denke, dass die Idee hier ist, eine Tail-Methode innerhalb des List-Objekts zu definieren, was sie eine Companion-Methode nennen, und dann normal in einer anderen Datei aufrufen (wie eine Main-Datei).

Bisher habe ich dies:

def tail[A](ls: List[A]): List[A] = ls match { 
    case Nil => Nil 
    case Cons(x,xs) => xs 
    } 

Dann habe ich eine Hauptdatei in einem anderen Ordner erstellt:

package fpinscala.datastructures 

object Main { 
    def main(args:Array[String]):Unit = { 
     println("Hello, Scala !! ") 
     val example = Cons(1, Cons(2, Cons(3, Nil))) 
    val example2 = List(1,2,3) 
     val example3 = Nil 
    val total = List.tail(example) 
    val total2 = List.tail(example3) 
    println(total2) 
} 
} 

Dies funktioniert und gibt mir:

Hello, Scala !! 
Cons(2,Cons(3,Nil)) 

Meine Frage ist:

I Ist dies der richtige Weg, die Tail-Methode zu schreiben, so wie es die Autoren beabsichtigten? Und ist diese Paketstruktur korrekt? Weil es sich sehr falsch anfühlt, obwohl ich nur dem Autoren-Paket gefolgt bin.

Ich weiß nicht, auch wenn ich stattdessen einen bestimmten Typ verwendet haben, sollte eine polymorphe Methode des Schreibens (das ist der Name?) ...

Bär mit mir, denn ich ein Neuling auf dem Gebiet bin von FP.

+0

Es scheint völlig in Ordnung für mich. Obwohl: 1. Sie möchten Cons nicht außerhalb des versiegelten Merkmals zeigen, also ist es besser, es privat zu machen 2. Warum benötigen Sie Beispiel und Gesamtvariablen in Ihrer Hauptfunktion? – mavarazy

+0

Danke!Wie kann ich die Nachteile "einkapseln", um sie privat zu machen? Ich verstehe das Beispiel, aber es ist immer noch ein bisschen zu viel für mich, um die tatsächliche Klasse zu ändern, und in dem Buch bitten sie, einfache Methoden wie Schwanz und so hinzuzufügen ... so bin ich ratlos. In Bezug auf die Beispiele, nun, ich wollte es testen? –

Antwort

2

In der standardmäßigen Implementierung der Scalaliste würde der Versuch, den Endabschnitt einer leeren Liste zu übernehmen, eine UnsupportedOperationException auslösen. Sie könnte also etwas mehr wie

def tail[A](ls: List[A]): List[A] = ls match { 
    case Nil => throw new UnsupportedOperationException() 
    case Cons(x,xs) => xs 
} 

will auch qantik Antwort, wo er schlägt vor, mit dem Operator :: mit Scala Standardliste Implementierung funktionieren würde, aber da gibt es keine :: Verfahren auf dieser benutzerdefinierte Liste Implementierung definiert ist Es wird nicht funktionieren.

Schließlich können Sie definieren Schwanz zu berücksichtigen, so dass anstelle von

val list = List(1, 2, 3) 
val restOfList = tail(list). 

tun Sie stattdessen

val list = List(1, 2, 3) 
val restOfList = list.tail 

tun könnte, die erforderlich wäre, das Verfahren auf der Liste Merkmal definieren, im Gegensatz im List-Objekt.

-1

Sieht gut aus. Wie wäre es mit?

def tail[A](xs: List[A]): List[A] = xs match { 
    case Nil => Nil 
    case head :: xxs => xxs 
}