Last active
August 29, 2015 14:17
-
-
Save HeartSaVioR/78ab19710f9d78f91392 to your computer and use it in GitHub Desktop.
Functional Programming in Scala (chap 3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def tail[A](lst: List[A]): List[A] = lst match { | |
case Nil => Nil | |
case x :: xs => xs | |
} | |
// solution in a book | |
// https://github.com/fpinscala/fpinscala/blob/master/answerkey/datastructures/02.answer.scala | |
/* | |
// Although we could return `Nil` when the input list is empty, we choose to throw an exception instead. This is a somewhat subjective choice. In our experience, taking the tail of an empty list is often a bug, and silently returning a value just means this bug will be discovered later, further from the place where it was introduced. | |
// It's generally good practice when pattern matching to use `_` for any variables you don't intend to use on the right hand side of a pattern. This makes it clear the value isn't relevant. | |
def tail[A](l: List[A]): List[A] = | |
l match { | |
case Nil => sys.error("tail of empty list") | |
case Cons(_,t) => t | |
} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def setHead[A](lst: List[A], head: A): List[A] = lst match { | |
case Nil => head :: Nil | |
case x :: xs => head :: xs | |
} | |
// solution in a book | |
// https://github.com/fpinscala/fpinscala/blob/master/answerkey/datastructures/03.answer.scala | |
/* | |
// If a function body consists solely of a match expression, we'll often put the match on the same line as the function signature, rather than introducing another level of nesting. | |
def setHead[A](l: List[A], h: A): List[A] = l match { | |
case Nil => sys.error("setHead on empty list") | |
case Cons(_,t) => Cons(h,t) | |
} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def drop[A](l: List[A], n: Int): List[A] = { | |
if (n <= 0) | |
l | |
else | |
l match { | |
case Nil => Nil | |
case x :: xs => drop(xs, n - 1) | |
} | |
} | |
// solution in a book | |
// https://github.com/fpinscala/fpinscala/blob/master/answerkey/datastructures/04.answer.scala | |
/* | |
// Again, it's somewhat subjective whether to throw an exception when asked to drop more elements than the list contains. The usual default for `drop` is not to throw an exception, since it's typically used in cases where this is not indicative of a programming error. If you pay attention to how you use `drop`, it's often in cases where the length of the input list is unknown, and the number of elements to be dropped is being computed from something else. If `drop` threw an exception, we'd have to first compute or check the length and only drop up to that many elements. | |
def drop[A](l: List[A], n: Int): List[A] = | |
if (n <= 0) l | |
else l match { | |
case Nil => Nil | |
case Cons(_,t) => drop(t, n-1) | |
} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def dropWhile[A](l: List[A], f: A => Boolean): List[A] = { | |
l match { | |
case Nil => Nil | |
case x :: xs => if (f(x)) dropWhile(xs, f) else l | |
} | |
} | |
// solution in a book | |
// https://github.com/fpinscala/fpinscala/blob/master/answerkey/datastructures/05.answer.scala | |
/* | |
// Somewhat overkill, but to illustrate the feature we're using a _pattern guard_, | |
// to only match a `Cons` whose head satisfies our predicate, `f`. | |
// The syntax is to add `if <cond>` after the pattern, before the `=>`, | |
// where `<cond>` can use any of the variables introduced by the pattern. | |
def dropWhile[A](l: List[A], f: A => Boolean): List[A] = | |
l match { | |
case Cons(h,t) if f(h) => dropWhile(t, f) | |
case _ => l | |
} | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def init[A](l: List[A]): List[A] = l match { | |
case Nil => Nil | |
case x :: Nil => Nil | |
case x :: xs => x :: init(xs) | |
} | |
// solution in a book | |
// https://github.com/fpinscala/fpinscala/blob/master/answerkey/datastructures/06.answer.scala | |
/* | |
// Note that we're copying the entire list up until the last element. Besides being inefficient, the natural recursive solution will use a stack frame for each element of the list, which can lead to stack overflows for large lists (can you see why?). With lists, it's common to use a temporary, mutable buffer internal to the function (with lazy lists or streams, which we discuss in chapter 5, we don't normally do this). So long as the buffer is allocated internal to the function, the mutation is not observable and RT is preserved. | |
// Another common convention is to accumulate the output list in reverse order, then reverse it at the end, which doesn't require even local mutation. We'll write a reverse function later in this chapter. | |
def init[A](l: List[A]): List[A] = | |
l match { | |
case Nil => sys.error("init of empty list") | |
case Cons(_,Nil) => Nil | |
case Cons(h,t) => Cons(h,init(t)) | |
} | |
def init2[A](l: List[A]): List[A] = { | |
import collection.mutable.ListBuffer | |
val buf = new ListBuffer[A] | |
@annotation.tailrec | |
def go(cur: List[A]): List[A] = cur match { | |
case Nil => sys.error("init of empty list") | |
case Cons(_,Nil) => List(buf.toList: _*) | |
case Cons(h,t) => buf += h; go(t) | |
} | |
go(l) | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment