Scalaのお勉強3

book.impress.co.jp
に取り組む。
今日は第4章、第5章。
解答を見まくった。(https://github.com/fpinscala/fpinscala)

object Main4{

  sealed trait Option[+A]{
    def map[B](f:A=>B):Option[B]={
      this match{
        case None=>None
        case Some(a) => Some(f(a))
      }
    }
    def flatMap[B](f:A=>Option[B]):Option[B]=map(f).getOrElse(None)
    def getOrElse[B>:A](default: => B):B={
      this match{
        case None=>default
        case Some(a)=>a
      }
    }
    def orElse[B>:A](ob : =>Option[B]):Option[B]=map(Some(_)).getOrElse(ob)
    def filter(f:A=>Boolean):Option[A]=this match{case Some(a) if f(a)=>this;case _ => None}

    
  }
  case class Some[+A](get:A) extends Option[A]
  case object None extends Option[Nothing]

  def mean(xs:Seq[Double]):Option[Double]= if (xs.isEmpty) None else Some(xs.sum/xs.length)

  def variance(xs:Seq[Double]):Option[Double]=mean(xs).flatMap(( m =>mean(xs.map( x =>math.pow(x-m,2)))))

  def lift[A,B](f: A => B):Option[A] => Option[B] = _.map(f)
  def insuaranceRateQuote(age:Int,numberOfSpeedingTickets:Int):Double={
    numberOfSpeedingTickets/age
  }
  def parseInsuaranceRateQuote(age:String,numberOfSpeedingTicket:String):Option[Double]={
    val optAge:Option[Int]=Try(age.toInt)
    val optTicket:Option[Int]=Try(numberOfSpeedingTicket.toInt)
    map2(optAge,optTicket)(insuaranceRateQuote)
  }

  def Try[A](a: =>A):Option[A]={
    try Some(a)
    catch { case e:Exception => None }
  }
  
  def map2[A,B,C](a:Option[A],b:Option[B])(f:(A,B)=>C):Option[C]={
    a.flatMap(aa=>b.map(bb=>f(aa,bb)))
  }
  def map3[A,B,C,D](a:Option[A],b:Option[B],c:Option[C])(f:(A,B,C)=>D):Option[D]={
    a.flatMap(aa=>b.flatMap(bb=>c.map(cc=>(f(aa,bb,cc)))))
  }

  def sequence[A](a:List[Option[A]]):Option[List[A]]={
    a match{
      case Nil=>Some(Nil)
      case x::xs=>x.flatMap(xx=>sequence(xs).map(xx::_))
    }
  }

  def traverse[A,B](a:List[A])(f:A=>Option[B]):Option[List[B]]={
    a match{
      case Nil=>Some(Nil)
      case x::xs=>f(x).flatMap(xx=>traverse(xs)(f).map(xx::_))
    }
  }

  sealed trait Either[+E,+A]{
    def map[B](f:A=>B):Either[E,B]={
      this match{
        case Right(x)=>Right(f(x))
        case Left(e)=>Left(e)
      }
    }
    def flatMap[EE >: E,B](f:A=>Either[EE,B]):Either[EE,B]={
      this match{
        case Right(x)=>f(x)
        case Left(e)=>Left(e)
      }
      
    }
    def orElse[EE >: E, B >: A](b: => Either[EE,B]):Either[EE,B]={
      this match{
        case _:Right[A]=>this
        case _:Left[E]=>b
      }
    }
    def map2[EE >: E,B,C](b:Either[EE,B])(f:(A,B)=>C):Either[EE,C]={
      flatMap(aa=>b.map(bb=>f(aa,bb)))
    }
  }
    

  def sequence_either[E,A](es:List[Either[E,A]]):Either[E,List[A]]={
    es match{
      case Nil=>Right(Nil)
      case x::xs=>x.flatMap(xx=>sequence_either(xs).map(xx::_))
    }
  }
  def traverse_either[E,A,B](as:List[A])(f:A=>Either[E,B]):Either[E,List[B]]={
    as match{
      case Nil=>Right(Nil)
      case x::xs=>f(x).flatMap(xx=>traverse_either(xs)(f).map(xx::_))
    }
    
  }
  case class Left[+E](value:E) extends Either[E,Nothing]
  case class Right[+A](value:A) extends Either[Nothing,A]

  def mean(xs:IndexedSeq[Double]):Either[String,Double]={
    if(xs.isEmpty)Left("mean of empty list")
    else Right(xs.sum/xs.length)
  }
  def Try_either[A](a: =>A):Either[Exception,A]={
    try Right(a)
    catch { case e:Exception => Left(e)}

}
object Main5{
  case object Empty extends Stream[Nothing]
  case class Cons[+A](h:()=>A,t:()=>Stream[A])extends Stream[A]

  trait Stream[+A]{
    def cons[A](hd: =>A,tl: =>Stream[A]):Stream[A]={
      lazy val head=hd
      lazy val tail=tl
      Cons(()=>head,()=>tail)
    }
    def empty[A]:Stream[A]=Empty
    
    def apply[A](as:A*):Stream[A]=if (as.isEmpty) empty else cons(as.head,apply(as.tail:_*))

    def headOption:Option[A]=this match{
      case Empty=>None
      case Cons(h,t)=>Some(h())
    }
    def toList:List[A]={
      this match{
        case Empty =>Nil
        case Cons(h,t)=>h()::t().toList
      }
    }
    def take(n:Int):Stream[A]={
      if (n<0) empty
      else{
        this match{
          case Empty => empty
          case Cons(h,t)=>cons(h(),t().take(n-1))
        }
      }
    }
    @annotation.tailrec
    private def drop(n:Int):Stream[A]={
      this match{
        case Cons(_,t) if n>0 => t().drop(n-1)
        case _ => this
      }
    }
    def exists(p:A=>Boolean):Boolean=this match{
      case Cons(h,t)=>p(h()) || t().exists(p)
      case _=>false
    }

    def foldRight[B](z: =>B)(f:(A, =>B) =>B):B=this match{
      case Cons(h,t)=>f(h(),t().foldRight(z)(f))
      case _=> z
    }
    def exists2(p:A=>Boolean):Boolean={
      foldRight(false)((a,b)=>p(a)||b)
    }

    def forAll(p:A=>Boolean):Boolean={
      foldRight(true)((a,b)=>p(a)&&b)
    }
    def takeWhile(p:A=>Boolean):Stream[A]={
      foldRight(empty[A])((a,b)=>if(p(a)) cons(a,b) else empty)
    }

    def map[B](f:A=>B):Stream[B]={
      foldRight(empty[B])((a,b)=>cons(f(a),b))
    }
    def filter(p:A=>Boolean):Stream[A]={
      foldRight(empty[A])((a,b)=>if(p(a)) cons(a,b) else b)
    }
    def append[B>:A](s: => Stream[B]):Stream[B]={
      foldRight(s)((a,b)=>cons(a,b))
    }
    def flatMap[B](f: A => Stream[B]):Stream[B]={
      foldRight(empty[B])((a,b)=>f(a).append(b))
    }
    def constant[A](a:A):Stream[A]=cons(a,constant(a))
    
    def from(n:Int):Stream[Int]=cons(n,from(n+1))

    def fibs:Stream[Int]={
      def go(f0:Int,f1:Int):Stream[Int]=cons(f0,go(f1,f0+f1))
      go(0,1)
    }
    def unfold[A,S](z:S)(f:S=>Option[(A,S)]):Stream[A]={
      def go(z1:S):Stream[A]={
        f(z1) match{
          case Some((a,s))=>cons(a,go(s))
          case None=>empty
        }
      }
      go(z)
    }
    def fibs2:Stream[Int]=unfold[Int,(Int,Int)]((0,1))({case (f0,f1)=>Some((f0,(f1,f0+f1)))})
    def from2(n:Int):Stream[Int]=unfold[Int,Int](n)(a=>Some((a+1,a+1)))
    def constant2[A](a:A):Stream[A]=unfold[A,A](a)(_=>Some((a,a)))
    def ones2:Stream[Int]=unfold[Int,Int](1)(_=>Some((1,1)))
    def tails:Stream[Stream[A]]={
      unfold(this){
        case Empty=>None
        case s=>Some((s,s drop 1))
      } append empty
    }
    def map2[B](f:A=>B):Stream[B]={
      unfold(this){
        case Cons(h,t)=>Some((f(h()),t()))
        case Empty => None
      }
    }
    def take2(n:Int):Stream[A]={
      unfold((this,n)){
        case (Cons(h,t),1) =>Some((h(),(empty,0)))
        case (Cons(h,t),n) if n>1 => Some((h(),(t(),n-1)))
        case _ =>None
      }
    }
    def takeWhile2(p:A=>Boolean):Stream[A]={
      unfold(this){
        case Cons(h,t) if p(h()) => Some((h(),t()))
        case _ => None
      }
    }
    def zipWith2[B,C](s2:Stream[B])(f:(A,B)=>C):Stream[C]={
      unfold((this,s2)){
        case (Cons(h1,t1),Cons(h2,t2)) => Some((f(h1(),h2()),(t1(),t2())))
        case _=>None
      }
    }





    
  }
  def main(args:Array[String]){
    println(Stream(1,2).take(2).toList)
    println(Stream(1,2,3,4,5,6,7,6,5,4,3,2,1).takeWhile(4>=).toList)
  }
}