스칼라의 콜렉션의 fold와 reduce와 scan 함수는 시간이 조금만 지나면 혼동되기 쉬운 것 같다. 

accumulate 기능이 있어서 서로 비슷하게 생겼다..





List(1,2,3).foldLeft(100)((s,x) => s - x)

((100 - 1) - 2) -3 = 94 




List(1,2,3).foldRight(100)((s,x) => s - x)

1 - (2 - (3 - 100)) = -98




List(1,2,3).reduceLeft((s,x) => s - x)

(1 - 2) - 3 = -4




List(1,2,3).reduceRight((s,x) => s - x)

1 - ( 2 - 3) = 2






List(1,2,3).scanLeft(100)((s, x) => s - x)

List(100, 100-1, (100-1)-2, (100-1)-2-3) 

=> List(100, 99, 97, 94)





List(1,2,3).scanRight(100)((s, x) => s - x)

// index3 : 초기값 100

// index2 : 3 - 100 = -97

// index1 : 2 - -97 = 99

// index0 : 1 - 99 = -98

List(-98, 99, -97, 100)

Posted by '김용환'
,


scalameter(https://scalameter.github.io/)는 마이크로 벤치마킹 기능을 가진 툴이다.  JVM warm up 또는 GC 의 영향을 받아 속도 체크가 좀 틀릴 수 있다. 이를 좀 막고 측정할 수 있는 라이브러리를 알게 되었다.


slideshare에 관련 자료가 잘 설명되어 있다. 


ScalaMeter 2014 from Aleksandar Prokopec







sbt 설정에 다음 라이브러리를 추가한다.

"com.storm-enroute" %% "scalameter-core" % "0.7"

(!!! 0.6에는 라이브러리가 많이 없으니 최신 버전을 활용하는 것이 좋다)



sbt console을 사용해서 scalameter를 임포트한다.



scala> import org.scalameter._




jvm warm up 관련해서 메모리 초기화로 인해서 결과 값이 달라지지 않게 하니 적당히 잘 나온다.



scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res28: Double = 0.688856


scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res29: Double = 0.689882


scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res30: Double = 0.684432


scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res31: Double = 0.681093


scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res32: Double = 0.678273


scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res33: Double = 0.671677


scala> withWarmer(new Warmer.Default) measure { (0 until 100000).toArray }

res34: Double = 0.695395







메모리 정보도 확인할 수 있다.


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res9: Double = 399.656


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res10: Double = 400.016


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res11: Double = 399.656


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res12: Double = 400.016


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res13: Double = 399.656


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res14: Double = 399.656


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res15: Double = 400.016


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res16: Double = 399.656


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res17: Double = 397.08


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res18: Double = 400.016


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res19: Double = 399.656


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res20: Double = 400.016


scala> withMeasurer(new Measurer.MemoryFootprint) measure { (0 until 100000).toArray }

res21: Double = 397.568




GC 정보는 다음과 같이 테스트할 수 있다. 


scala>  withMeasurer(new Measurer.GarbageCollectionCycles, Aggregator.median[Int]) measure { (0 until 9999000).toArray }

res5: org.scalameter.Quantity[Int] = 2 #


scala>  withMeasurer(new Measurer.GarbageCollectionCycles, Aggregator.median[Int]) measure { (0 until 9999000).toArray }

res6: org.scalameter.Quantity[Int] = 2 #


scala>  withMeasurer(new Measurer.GarbageCollectionCycles, Aggregator.median[Int]) measure { (0 until 9999000).toArray }

res7: org.scalameter.Quantity[Int] = 2 #


scala>  withMeasurer(new Measurer.GarbageCollectionCycles, Aggregator.median[Int]) measure { (0 until 9999000).toArray }

res8: org.scalameter.Quantity[Int] = 2 #




관련 소스는 다음과 같다.


https://github.com/scalameter/scalameter/blob/master/scalameter-core/src/main/scala/org/scalameter/Measurer.scala


Posted by '김용환'
,


스칼라 콘솔에서 테스트하고 싶은 예제 코드가 있을 때 실행 라인이 아닌 

전체 예제 코드를 실행하고 싶을 때 :paste를 사용하면 된다. 



스칼라 콘솔(REPL)을 실행한다.


scala> 



:paste를 입력하고 엔터를 입력한다.


scala> :paste

// Entering paste mode (ctrl-D to finish)



그리고 코드를 입력 한 후 Ctrl+D 키를 함께 누른다. 

그러면 결과가 실행된다.



scala> :paste

// Entering paste mode (ctrl-D to finish)


  def max(xs: List[Int]): Int = xs match {

    case List() => throw new java.util.NoSuchElementException

    case x :: Nil => x

    case _ => val t: Int = max(xs.tail); if (t > xs.head) t else xs.head

  }


  val m = max(List(3,2,1,100))

  print(m)


// Exiting paste mode, now interpreting.


m: Int = 100

Posted by '김용환'
,



스칼라의 DynamicVariable은 Java의 Thread Local State 변수와 동일한 효과를 가진다. 




import scala.concurrent.ExecutionContext
import scala.util.DynamicVariable

object DynamicVariableExample extends App {

def execute(body: =>Unit) = ExecutionContext.global.execute(new Runnable {
def run() = body
})

val dyn = new DynamicVariable[Int](10)

def doSomething = println(Thread.currentThread().getName() + ":" + dyn.value)

dyn.withValue(1) { execute(doSomething) }
dyn.withValue(50) { execute(doSomething) }
println

}



결과


scala-execution-context-global-11:1

scala-execution-context-global-12:50




내부 코드를 살펴보면,java.lang.InheritableThreadLocal을 사용하고 있다. 


class DynamicVariable[T](init: T) {
private val tl = new InheritableThreadLocal[T] {
override def initialValue = init.asInstanceOf[T with AnyRef]
}


public class InheritableThreadLocal<T> extends ThreadLocal<T> {


Posted by '김용환'
,

스칼라에서는 underscore를 많은 용도로 사용할 수 있다.


그 중 변수를 기본값으로 초기화를 하라라는 의미이다. 


scala>  var a: String = _

a: String = null



var에 underscore를 사용할 수 있지만, val에 사용하면 에러를 리턴한다. 



scala>  val a: String = _

<console>:11: error: unbound placeholder parameter

        val a: String = _

                        ^


함수도 초기화할 수 있다.


private var myExpr: () => Int = _






scala 언어 스펙에 따르면.. 다음과 같이 정의하고 있다.

http://www.scala-lang.org/files/archive/spec/2.11/06-basic-declarations-and-definitions.html




A variable definition var $x$: $T$ = _ can appear only as a member of a template. It introduces a mutable field with type $T$ and a default initial value. The default value depends on the type $T$ as follows:

defaulttype $T$
0Int or one of its subrange types
0LLong
0.0fFloat
0.0dDouble
falseBoolean
()Unit
nullall other types



Posted by '김용환'
,


람다 이론에 대해서 정확히 알지도 못한채 공부하고 책을 번역했다. 휴. 부족한 것이 많다.




Deduction, Reduction, Lamda Calculus, Substitution model.. 



코세라 강의https://www.coursera.org/learn/progfun2/lecture/Gd31A/lecture-3-1-functions-and-state) 중에 Church-Rosser의 람다 이론이 나와서 공부하기 좋은 링크를 걸어본다.


http://www.aistudy.com/pioneer/Church.A.htm


http://www.aistudy.com/computer/lambda_calculus.htm


https://groups.google.com/forum/#!topic/han.sci.math/SwxTPD2AYmM



https://www.cs.cornell.edu/~kozen/papers/ChurchRosser.pdf



https://en.wikipedia.org/wiki/Church%E2%80%93Rosser_theorem



http://syjdev.tistory.com/15

http://syjdev.tistory.com/16

http://syjdev.tistory.com/17

http://syjdev.tistory.com/18







'scala' 카테고리의 다른 글

[scala] DynamicVariable 예제  (0) 2017.07.07
[scala] 변수를 사용하기 위한 underscore  (0) 2017.07.05
[scala] Stream 의 concat은 #::이다.  (0) 2017.07.03
[scala] forall, for 예제 코드  (0) 2017.06.30
[scala] forall 표현식  (0) 2017.06.30
Posted by '김용환'
,



scala에서 Stream은 lazy하게 계산되는 리스트이다. 


Stream에서 concat을 하려면 :: 이 아니라 #::을 사용한다. 



scala> val stream = 1 #:: 2 #:: 3 #:: Stream.empty

stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)



실행 예제이다.


scala> def fibFrom(a: Int, b: Int): Stream[Int]  = a #:: fibFrom(b, a + b)

fibFrom: (a: Int, b: Int)Stream[Int]



여기서 엄청 큰 수를 넣어도 Stream(1, ?로 나타난다. 


scala> val fibs = fibFrom(1, 1).take(3)

fibs: scala.collection.immutable.Stream[Int] = Stream(1, ?)


scala> fibs.toList

res0: List[Int] = List(1, 1, 2)



또 다른 예제이다.'

scala> def from(n: Int): Stream[Int] = n #:: from(n+1)

from: (n: Int)Stream[Int]


scala>  val nats = from(0)

nats: Stream[Int] = Stream(0, ?)


scala>     val m4s = nats map (_ * 4)

m4s: scala.collection.immutable.Stream[Int] = Stream(0, ?)





실제 m4s에 매개 변수가 길더라도 lazy라서 아직 계산되지 않았다.


scala> m4s take 10000000

res2: scala.collection.immutable.Stream[Int] = Stream(0, ?)



실제 수행되는 시점에 toList를 호출한다.


scala> (m4s take 10000000).toList.drop(3)




Posted by '김용환'
,



코세라 강의 중 괜찮은 예제가 있어서 소개한다.



https://www.coursera.org/learn/progfun1/lecture/JIPKx/lecture-6-2-combinatorial-search-and-for-expressions


scala에서 소수를 구하는 isPrime() 

def isPrime(n: Int): scala.Boolean = (2 until n) forall (n % _ != 0)

println(isPrime(2)) // true
println(isPrime(3)) // true
println(isPrime(4)) // false
println(isPrime(5)) // true
println(isPrime(6)) // false
println(isPrime(7)) // true
println(isPrime(8)) // false
println(isPrime(9)) // false



합산이 소수일때만 더하는 집합 예제이다. 


def isPrime(n: Int): scala.Boolean = (2 until n) forall (n % _ != 0)

val result = (1 until 7) flatMap (i =>
(1 until i) map (j => (i, j))) filter (pair =>
isPrime(pair._1 + pair._2)
)

println(result)


결과는 다음과 같다. 


Vector((2,1), (3,2), (4,1), (4,3), (5,2), (6,1), (6,5))




scalaProduct 예제이다. 

def scalarProduct(left: List[Double], right: List[Double]): Double = (for ((x, y) <- left zip right) yield x * y).sum


결과는 다음과 같다. 


scala> scalarProduct(List(3,4,5), List(2,2,2))

res39: Double = 24.0


Posted by '김용환'
,

[scala] forall 표현식

scala 2017. 6. 30. 19:33



스칼라의 forall 표현식 예제이다.


콜렉션에 대해서 forall을 사용하면 모든 Range에 대해서 forall 표현식이 참이라면 true를 리턴한다.


scala> Range(2,3) forall (x => x == 2 || x == 3)

res34: Boolean = true






그러나, Range() 에다가 forall을 사용하면 결과 값은 무엇이 될까? 


scala> (2 until -1) forall (_ % 2== 0)

res37: Boolean = true


scala> (2 until 2) forall (_ % 2== 0)

res37: Boolean = true



true이다!!!

Posted by '김용환'
,

scala의 filter류 예제이다. 



filterNot은 filter의 expression의 !과 동일하다.

partition은 filter 와 filterNot을 합친 결과와 동일하다.


  val list = List(1,2,3,4,5)

  println(list.filter(x => x > 3))  // List(4, 5)


  println(list.filterNot(x => x > 3))  // List(1, 2, 3)

  println(list.filter(x => !(x > 3)))  // List(1, 2, 3)


  println(list.partition(x => x > 3)) // (List(4, 5),List(1, 2, 3))

  println(list.filter(x => x > 3), list.filterNot(x => x > 3)) // (List(4, 5),List(1, 2, 3))



결과는 다음과 같다. 


List(4, 5)

List(1, 2, 3)

List(1, 2, 3)

(List(4, 5),List(1, 2, 3))

(List(4, 5),List(1, 2, 3))





takeWhile과 dropWhile은 처음봤을 때 기억해도 잘 나지 않는데. 다시 해봐야 겨우 기억나는 익숙치 않은(?) api이다.


take는 처음 엘리먼트를 얻는다. 


takeWhile은 take를 기반으로 생각하면 좋다.


takeWhile은 술어함수가 list의 엘리먼트가 참에서 시작해서 거짓이 되는 시점의 엘리먼트를 얻는다. 



  val list = List(19, 5, -1, 0, 4, 10, 30)


  println(list.take(1)) // List(19)


  println(list.takeWhile(x => x == 0)) // List()

  println(list.takeWhile(x => x > 0)) // List(19, 5)

  println(list.takeWhile(x => x == 19)) // List(19)




drop(t)는 t번째 엘리먼트부터의 엘리먼트만 리턴한다. 

dropWhile은 drop을 기반으로 이해하는 것이 좋다. 

dropWhile은 술어 함수가 처음으로 거짓이 되는 엘리먼트부터를 얻는다. 

  val list = List(19, 5, -1, 0, 4, 10, 30)
  println(list.drop(3)) // List(0, 4, 10, 30)
  println(list.dropWhile(x => x > 0)) // List(-1, 0, 4, 10, 30)
  println(list.dropWhile(x => x > 5)) // List(5, -1, 0, 4, 10, 30)





span은 takeWhile과 dropWhile를 하나로 결합한 함수이다. 


  val list = List(19, 5, -1, 0, 4, 10, 30)

  println(list.span(x => x > 5))   // (List(19),List(5, -1, 0, 4, 10, 30))

  println(list.takeWhile(x => x > 5), list.dropWhile(x => x > 5)) // (List(19),List(5, -1, 0, 4, 10, 30))




'scala' 카테고리의 다른 글

[scala] forall, for 예제 코드  (0) 2017.06.30
[scala] forall 표현식  (0) 2017.06.30
[scala] mergesort(match) 예제  (0) 2017.06.29
[scala] expansion of function value  (0) 2017.06.28
[scala] Boolean-ifThenElse (coursera 강의 발췌)  (0) 2017.06.28
Posted by '김용환'
,