$30 off During Our Annual Pro Sale. View Details »

Haskell + Scala ハイブリッド開発大作戦 #ScalaMatsuri / Operation Haskell + Scala

y_taka_23
March 16, 2018

Haskell + Scala ハイブリッド開発大作戦 #ScalaMatsuri / Operation Haskell + Scala

ScalaMatsuri 2018 で使用したスライドです。Typelead 社によって開発中の JVM 用 Haskell である Eta 言語について、Java/Scala との相互呼び出しに焦点を当てて解説しています。また後半では Scala プロジェクトを部分的に Eta で置き換えるためのベストプラクティスについても触れています。

講演概要 : http://2018.scalamatsuri.org/ja/candidates/CheshireCat_1/
録画 : https://www.youtube.com/watch?v=u9WACa-JRA4

Slides for ScalaMatsuri 2018. Eta, Haskell on JVM, is now developed by Typelead Inc. This presentation provides you ideas of Eta's ingenious way of Java/Scala interoperation, and a sort of best practice to gradually introduce Eta-parts in your Scala projects.

Call for Proposal: http://2018.scalamatsuri.org/en/candidates/CheshireCat_1/

y_taka_23

March 16, 2018
Tweet

More Decks by y_taka_23

Other Decks in Technology

Transcript

  1. Operation
    Haskell + Scala
    Towards Hybrid Functional Development
    Haskell + Scala ハイブリッド開発大作戦
    Cheshire Cat (@y_taka_23)
    ScalaMatsuri 2018 (2018/03/17)
    #ScalaMatsuri

    View Slide

  2. #ScalaMatsuri
    @y_taka_23
    ご意見ご感想は Twitter へ
    #ScalaMatsuri

    View Slide

  3. Haskell
    みなさんご存知 Haskell
    http://haskell.org
    #ScalaMatsuri

    View Slide

  4. Eta
    でも今日の題材は Eta
    https://eta-lang.org
    #ScalaMatsuri

    View Slide

  5. What’s Eta Lang?
    ● Haskell on JVM
    ○ OSS by Typelead Inc. in India
    ○ Highly compatible with Haskell
    ● Generates Java bytecode
    ○ Smooth interoperation with JVM languages
    ● Forked from GHC
    ○ The de-facto standard Haskell compiler
    Eta は JVM 上で動く Haskell
    GHC からのフォークで、バイトコードを生成
    #ScalaMatsuri

    View Slide

  6. Contents
    ● Purity in Haskell
    ○ Haskell, what a procedural language
    ○ What is the biggest difference from Scala?
    ● Java/Scala interoperation
    ○ Java Monads
    ○ Type-level programming
    ● Example of hybrid-project building
    純粋性、Java/Scala との相互呼び出し
    ハイブリッドプロジェクトの例
    #ScalaMatsuri

    View Slide

  7. 1.
    Purity in Haskell
    Haskell の純粋性
    Quarantine side-effects
    #ScalaMatsuri

    View Slide

  8. Maybe You Guys Think...
    ● Haskell is too complicated
    ○ Functional programing is Greek to me...
    ○ That’s a language for mathematicians…
    ○ Category theory...
    ● Haskell is poor at IO
    ○ Even “Hello, world” requires understanding of monads
    ○ Never be a production-ready language
    Haskell は数学的で難解という先入観
    #ScalaMatsuri

    View Slide

  9. Naive FizzBuzz in Scala
    for (i <- 1 to 100) {
    if (i % 3 == 0 && i % 5 == 0) {
    println("FizzBuzz")
    } else if (i % 3 == 0) {
    println("Fizz")
    } else if (i % 5 == 0) {
    println("Buzz")
    } else {
    println(i)
    }
    }
    Scala による単純な FizzBuzz
    #ScalaMatsuri

    View Slide

  10. Also Naive FuzzBuzz in Haskell
    main :: IO ()
    main = do
    forM_ [1..100] $ \i -> do
    if i `mod` 3 == 0 && i `mod` 5 == 0 then
    putStrLn "FizzBuzz"
    else if i `mod` 3 == 0 then
    putStrLn "Fizz"
    else if i `mod` 5 == 0 then
    putStrLn "Buzz"
    else
    putStrLn $ show i
    Haskell による単純な FizzBuzz
    #ScalaMatsuri

    View Slide

  11. Also Naive FuzzBuzz in Haskell
    main :: IO ()
    main = do
    forM_ [1..100] $ \i -> do
    if i `mod` 3 == 0 && i `mod` 5 == 0 then
    putStrLn "FizzBuzz"
    else if i `mod` 3 == 0 then
    putStrLn "Fizz"
    else if i `mod` 5 == 0 then
    putStrLn "Buzz"
    else
    putStrLn $ show i
    Haskell による単純な FizzBuzz
    for-loop
    #ScalaMatsuri

    View Slide

  12. Also Naive FuzzBuzz in Haskell
    main :: IO ()
    main = do
    forM_ [1..100] $ \i -> do
    if i `mod` 3 == 0 && i `mod` 5 == 0 then
    putStrLn "FizzBuzz"
    else if i `mod` 3 == 0 then
    putStrLn "Fizz"
    else if i `mod` 5 == 0 then
    putStrLn "Buzz"
    else
    putStrLn $ show i
    Haskell による単純な FizzBuzz
    if-conditional
    #ScalaMatsuri

    View Slide

  13. Also Naive FuzzBuzz in Haskell
    main :: IO ()
    main = do
    forM_ [1..100] $ \i -> do
    if i `mod` 3 == 0 && i `mod` 5 == 0 then
    putStrLn "FizzBuzz"
    else if i `mod` 3 == 0 then
    putStrLn "Fizz"
    else if i `mod` 5 == 0 then
    putStrLn "Buzz"
    else
    putStrLn $ show i
    Haskell による単純な FizzBuzz
    stdout
    #ScalaMatsuri

    View Slide

  14. Haskell is Not Rocket Science
    ● Procedural programming
    ○ You don’t need to be too “functional”
    ○ Remember Scala as “better Java”
    ○ Naive sequantials / conditionals / loops
    ● Mathematical background is not mandatory
    ○ HelloWorld / FizzBuzz In the usual way
    ● What’s difference of Haskell from Scala?
    Haskell は手続き的なコードも書ける
    では Scala との違いは何か?
    #ScalaMatsuri

    View Slide

  15. Scala における純粋・非純粋なメソッド
    def pureMessage(name: String): String = {
    "Hello, " ++ name
    }
    def inpureMessage(name: String): String = {
    val another = io.StdIn.readLine()
    "Hello, " ++ name ++ ", " ++ another
    }
    #ScalaMatsuri

    View Slide

  16. Scala における純粋・非純粋なメソッド
    def pureMessage(name: String): String = {
    "Hello, " ++ name
    }
    def inpureMessage(name: String): String = {
    val another = io.StdIn.readLine()
    "Hello, " ++ name ++ ", " ++ another
    }
    side-effect
    #ScalaMatsuri

    View Slide

  17. Scala における純粋・非純粋なメソッド
    def pureMessage(name: String): String = {
    "Hello, " ++ name
    }
    def inpureMessage(name: String): String = {
    val another = io.StdIn.readLine()
    "Hello, " ++ name ++ ", " ++ another
    }
    #ScalaMatsuri

    View Slide

  18. Haskell における純粋・非純粋な関数
    pureMessage :: String -> String
    pureMessage name =
    "Hello, " ++ name
    inpureMessage :: String -> String
    inpureMessage name = do
    another <- getLine
    return $ "Hello, " ++ name ++ ", " ++ another
    #ScalaMatsuri

    View Slide

  19. Haskell における純粋・非純粋な関数
    pureMessage :: String -> String
    pureMessage name =
    "Hello, " ++ name
    inpureMessage :: String -> String
    inpureMessage name = do
    another <- getLine
    return $ "Hello, " ++ name ++ ", " ++ another
    type error
    #ScalaMatsuri

    View Slide

  20. Haskell における純粋・非純粋な関数
    pureMessage :: String -> String
    pureMessage name =
    "Hello, " ++ name
    inpureMessage :: String -> IO String
    inpureMessage name = do
    another <- getLine
    return $ "Hello, " ++ name ++ ", " ++ another
    compilable
    #ScalaMatsuri

    View Slide

  21. Haskell における純粋・非純粋な関数
    pureMessage :: String -> String
    pureMessage name =
    "Hello, " ++ name
    inpureMessage :: String -> IO String
    inpureMessage name = do
    another <- getLine
    return $ "Hello, " ++ name ++ ", " ++ another
    #ScalaMatsuri

    View Slide

  22. IO as a Type in Haskell
    ● Side effects should be separated
    ○ Regardless of which programming languages
    ○ Not predictable nor testable
    ○ No built-in methodology for dealing IO in Scala
    ● In Haskell, it appears as a type
    ○ Compiler can check it at compilation time
    ○ No careless side effects
    Haskell では IO が型に現れるため
    コンパイラがチェック可能
    #ScalaMatsuri

    View Slide

  23. Recap of Section. 1
    ● Haskell in the naive ways
    ○ Procedural programming if you want
    ○ Without (explicit) math objects, like monads
    ● Side effects appear as the IO Type
    ○ Compiler can check the “real world dependency”
    ○ Quarantine “impure” parts from “pure” parts
    Haskell は手続き的な記述も可能だが
    副作用が型として見える点で一線を画す
    #ScalaMatsuri

    View Slide

  24. 2.
    Interoperation
    Java/Scala との相互呼び出し
    Levarate by JVM ecosystem
    #ScalaMatsuri

    View Slide

  25. Advantages of JVM Languages
    ● Platform independent
    ○ 3 billion devices run JVM
    ● Mature ecosystem
    ○ Reuse your existing in-house/3rd party libraries
    ● Gradual/partial introduction
    ○ Small start, without change of infrastructure
    ○ Huge market for Java developers
    既存のエコシステムに乗ることで
    移行コストを低くできるのは JVM 言語の利点
    #ScalaMatsuri

    View Slide

  26. 各言語間の相互呼び出し
    #ScalaMatsuri

    View Slide

  27. Java/Scala から Eta
    #ScalaMatsuri

    View Slide

  28. Exporting Eta Functions
    module Util where
    import Java
    capitalize :: JString -> JString
    capitalize = ...
    foreign export java "@eta.example.Util.capitalize"
    capitalize :: JString -> JString
    Eta の関数のエクスポート
    #ScalaMatsuri

    View Slide

  29. Exporting Eta Functions
    module Util where
    import Java
    capitalize :: JString -> JString
    capitalize = ...
    foreign export java "@eta.example.Util.capitalize"
    capitalize :: JString -> JString
    Eta の関数のエクスポート
    @FQDN.functionName
    #ScalaMatsuri

    View Slide

  30. Importing as a Static Method
    import eta.example.Util
    object Main {
    def main(args: Array[String]): Unit = {
    val str = "hello, eta interop!"
    println(Util.capitalize(str))
    }
    }
    Java/Scala 側からは静的メソッドに見える
    #ScalaMatsuri

    View Slide

  31. Importing as a Static Method
    import eta.example.Util
    object Main {
    def main(args: Array[String]): Unit = {
    val str = "hello, eta interop!"
    println(Util.capitalize(str))
    }
    }
    Java/Scala 側からは静的メソッドに見える
    singleton method
    #ScalaMatsuri

    View Slide

  32. Eta から Java
    #ScalaMatsuri

    View Slide

  33. Two Big Hurdles in Java Interop
    ● State handling
    ○ In OOP, objects have their internal states
    ○ Java methods are potentially polluted by IO
    ○ It looks conflicting with the purity in Haskell
    ● Class inheritance
    ○ Haskell doesn’t have subtyping
    ○ Many Java stuffs depend on inheritance
    Java 連携で問題になるのは状態の扱いと継承
    #ScalaMatsuri

    View Slide

  34. How can we deal mutable objects?
    可変オブジェクトの扱いは?
    #ScalaMatsuri

    View Slide

  35. flatMap
    Scala の flatMap
    #ScalaMatsuri

    View Slide

  36. Toy Model of of “States”
    ● Manipulate a stack
    ○ The Simplest example of internal states
    ● Simplify the model
    ○ Contents are integers
    ○ Pop an integer from the top of stack
    ○ Push an integer x on the top of stack
    ● Emulate the stack as pure functions
    単純化した「状態」のモデル
    #ScalaMatsuri

    View Slide

  37. Requirements for Stack Manipulation
    ● Stack is immutable per se
    ○ Need to return the “modified” stack as a result
    ● Concatenate sequential actions
    ○ “Doing act1, and then act2” should be an action
    ● Action depends on actions in the past
    ○ “Pop x and then pop y, and then push (x + y)”
    欲しい Stack 操作の条件
    イミュータブル、逐次処理、以前の結果の利用
    #ScalaMatsuri

    View Slide

  38. Immutable Stack
    type Stack = [Int]
    pop :: Stack -> (Int, Stack)
    pop (x : xs) = (x, xs)
    push :: Int -> Stack -> ((), Stack)
    push x = ((), x : xs)
    変更されたスタックも一緒に返す
    #ScalaMatsuri

    View Slide

  39. Immutable Stack
    type Stack = [Int]
    pop :: Stack -> (Int, Stack)
    pop (x : xs) = (x, xs)
    push :: Int -> Stack -> ((), Stack)
    push x = ((), x : xs)
    変更されたスタックも一緒に返す
    type synonym
    #ScalaMatsuri

    View Slide

  40. Immutable Stack
    type Stack = [Int]
    pop :: Stack -> (Int, Stack)
    pop (x : xs) = (x, xs)
    push :: Int -> Stack -> ((), Stack)
    push x = ((), x : xs)
    変更されたスタックも一緒に返す
    (result, modified stack)
    #ScalaMatsuri

    View Slide

  41. Immutable Stack
    type Stack = [Int]
    pop :: Stack -> (Int, Stack)
    pop (x : xs) = (x, xs)
    push :: Int -> Stack -> ((), Stack)
    push x = ((), x : xs)
    変更されたスタックも一緒に返す
    result is Unit
    #ScalaMatsuri

    View Slide

  42. Immutable Stack
    type Stack = [Int]
    pop :: Stack -> (Int, Stack)
    pop (x : xs) = (x, xs)
    push :: Int -> Stack -> ((), Stack)
    push x = ((), x : xs)
    変更されたスタックも一緒に返す
    #ScalaMatsuri

    View Slide

  43. Immutable Stack
    type Stack = [Int]
    type Action a = Stack -> (a, Stack)
    pop :: Action Int
    pop (x : xs) = (x, xs)
    push :: Int -> Action ()
    push x = ((), x : xs)
    変更されたスタックも一緒に返す
    #ScalaMatsuri

    View Slide

  44. Sequential Actions
    andThen :: Action a -> Action b -> Action b
    andThen act1 act2 = \stack ->
    let (x1, stack1) = act1 stack
    (x2, stack2) = act2 stack1
    in (x2, stack2)
    myAct :: Action ()
    myAct = push 1 `andThen` push 2 `andThen` push 3
    操作を連結した結果も操作
    #ScalaMatsuri

    View Slide

  45. Sequential Actions
    andThen :: Action a -> Action b -> Action b
    andThen act1 act2 = \stack ->
    let (x1, stack1) = act1 stack
    (x2, stack2) = act2 stack1
    in (x2, stack2)
    myAct :: Action ()
    myAct = push 1 `andThen` push 2 `andThen` push 3
    操作を連結した結果も操作
    concatenation
    #ScalaMatsuri

    View Slide

  46. Sequential Actions
    andThen :: Action a -> Action b -> Action b
    andThen act1 act2 = \stack ->
    let (x1, stack1) = act1 stack
    (x2, stack2) = act2 stack1
    in (x2, stack2)
    myAct :: Action ()
    myAct = push 1 `andThen` push 2 `andThen` push 3
    操作を連結した結果も操作
    pass the modified stack
    #ScalaMatsuri

    View Slide

  47. Reuse results of the previous actions
    andThen :: Action a -> (a -> Action b)
    -> Action b
    andThen act1 factory = \stack ->
    let (x1, stack1) = act1 stack
    (x2, stack2) = (factory x1) stack1
    in (x2, stack2)
    myAct :: Action ()
    myAct = pop `andThen` (\x ->
    pop `andThen` (\y ->
    push (x + y)))
    以前の結果に依存した操作
    #ScalaMatsuri

    View Slide

  48. Reuse results of the previous actions
    andThen :: Action a -> (a -> Action b)
    -> Action b
    andThen act1 factory = \stack ->
    let (x1, stack1) = act1 stack
    (x2, stack2) = (factory x1) stack1
    in (x2, stack2)
    myAct :: Action ()
    myAct = pop `andThen` (\x ->
    pop `andThen` (\y ->
    push (x + y)))
    以前の結果に依存した操作
    #ScalaMatsuri

    View Slide

  49. Reuse results of the previous actions
    andThen :: Action a -> (a -> Action b)
    -> Action b
    andThen act1 factory = \stack ->
    let (x1, stack1) = act1 stack
    (x2, stack2) = (factory x1) stack1
    in (x2, stack2)
    myAct :: Action ()
    myAct = pop `andThen` (\x ->
    pop `andThen` (\y ->
    push (x + y)))
    以前の結果に依存した操作
    depends on x1
    #ScalaMatsuri

    View Slide

  50. andThen :: Action a -> (a -> Action b)
    -> Action b
    最終的に得られた関数
    #ScalaMatsuri

    View Slide

  51. Option[A]#
    flatmap[B](A => Option[B]): Option[B]
    Scala の flatMap
    #ScalaMatsuri

    View Slide

  52. Action[A]#
    flatmap[B](A => Action[B]): Action[B]
    Scala の flatMap
    #ScalaMatsuri

    View Slide

  53. flatMap :: Action[A] -> (A -> Action[B])
    -> Action[B]
    Scala の flatMap
    #ScalaMatsuri

    View Slide

  54. andThen :: Action a -> (a -> Action b)
    -> Action b
    最終的に得られた関数
    #ScalaMatsuri

    View Slide

  55. (>>=) :: m a -> (a -> m b) -> m b
    Monad 型クラスの bind 関数
    #ScalaMatsuri

    View Slide

  56. Scala’s for-Comprehension
    // actual
    opt1.flatMap(x => opt2.map(y => x + y))
    // sugared
    for {
    x <- opt1
    y <- opt2
    } yield {
    x + y
    }
    Scala の for 式
    #ScalaMatsuri

    View Slide

  57. Haskell’s do-Notation
    -- actual
    myAct = pop >>= (\x -> pop >>= (\y -> push (x + y)))
    -- sugared
    myAct :: Action ()
    myAct = do
    x <- pop
    y <- pop
    push (x + y)
    Haskell の do 記法
    #ScalaMatsuri

    View Slide

  58. Haskell’s do-Notation
    -- actual
    myAct = pop >>= (\x -> pop >>= (\y -> push (x + y)))
    -- sugared
    myAct :: Action ()
    myAct = do
    x <- pop
    y <- pop
    push (x + y)
    Haskell の do 記法
    #ScalaMatsuri

    View Slide

  59. Haskell’s do-Notation
    -- actual
    myAct = pop >>= (\x -> pop >>= (\y -> push (x + y)))
    -- sugared
    myAct :: Action ()
    myAct = do
    x <- pop
    y <- pop
    push (x + y)
    Haskell の do 記法
    hidden Stack
    #ScalaMatsuri

    View Slide

  60. What’s the Java Monads?
    ● DSL for the interop
    ○ Use monads as a framework
    ● Code block of a type “Java a b”
    ○ a: Type of the “implicit” method receiver
    ○ b: Type of the final execution result
    ○ “Java a” is a monad, depending on a
    ● IO is a special case of Java monads
    Java モナドは Java 呼び出しのための DSL
    レシーバと戻り値の組で型が決まる
    #ScalaMatsuri

    View Slide

  61. -- add :: e -> Java (Deque e) Boolean
    -- poll :: Java (Deque e) e
    myAct1 :: Java (Deque Int) Boolean
    myAct1 = add 1
    myAct2 :: Java (Deque Int) Bool
    myAct2 = do
    add 2
    add 1
    x <- poll
    y <- poll
    add (x + y)
    Deque クラスによる Java モナドの例
    #ScalaMatsuri

    View Slide

  62. -- add :: e -> Java (Deque e) Boolean
    -- poll :: Java (Deque e) e
    myAct1 :: Java (Deque Int) Boolean
    myAct1 = add 1
    myAct2 :: Java (Deque Int) Bool
    myAct2 = do
    add 2
    add 1
    x <- poll
    y <- poll
    add (x + y)
    Deque クラスによる Java モナドの例
    hidden receiver :: Deque Int
    #ScalaMatsuri

    View Slide

  63. Instance Methods
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "canExecute"
    canExecute :: Java File Bool
    インスタンスメソッドのインポート
    #ScalaMatsuri

    View Slide

  64. Instance Methods
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "canExecute"
    canExecute :: Java File Bool
    インスタンスメソッドのインポート
    typeclass as a marker
    #ScalaMatsuri

    View Slide

  65. Instance Methods
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "canExecute"
    canExecute :: Java File Bool
    インスタンスメソッドのインポート
    receiver :: File
    return value :: Bool
    #ScalaMatsuri

    View Slide

  66. Constructors
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "@new"
    newFile :: String -> Java a File
    コンストラクタのインポート
    #ScalaMatsuri

    View Slide

  67. Constructors
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "@new"
    newFile :: String -> Java a File
    コンストラクタのインポート
    no receiver
    return value :: File
    #ScalaMatsuri

    View Slide

  68. Static Methods
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "@static java.io.File.createTempFile"
    createTempFile :: String -> String -> Java a File
    静的メソッドのインポート
    #ScalaMatsuri

    View Slide

  69. Static Methods
    data File = File @java.io.File
    deriving Class
    foreign import java unsafe
    "@static java.io.File.createTempFile"
    createTempFile :: String -> String -> Java a File
    静的メソッドのインポート
    no receiver
    return value :: File
    #ScalaMatsuri

    View Slide

  70. Glue of Java Monads
    java :: Java c a -> IO a
    javaWith :: (Class c) => c -> Java c a -> IO a
    <.> :: (Class c) => c -> Java c a -> Java b a
    >- :: (Class b) => Java a b -> Java b c -> Java a c
    io :: IO c -> Java c a
    メソッドレシーバーを入れ替える関数群
    #ScalaMatsuri

    View Slide

  71. The other hurdle: Inheritance
    もう一つの問題、継承関係
    #ScalaMatsuri

    View Slide

  72. foreign import java unsafe "@new"
    newFile :: String -> Java a File
    foreign import java unsafe
    toString :: Object -> String
    data File = File @java.io.File
    deriving Class
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係によるコンパイルエラー
    #ScalaMatsuri

    View Slide

  73. foreign import java unsafe "@new"
    newFile :: String -> Java a File
    foreign import java unsafe
    toString :: Object -> String
    data File = File @java.io.File
    deriving Class
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係によるコンパイルエラー
    #ScalaMatsuri
    file :: File

    View Slide

  74. foreign import java unsafe "@new"
    newFile :: String -> Java a File
    foreign import java unsafe
    toString :: Object -> String
    data File = File @java.io.File
    deriving Class
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係によるコンパイルエラー
    #ScalaMatsuri
    type error

    View Slide

  75. {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE TypeFamilies #-}
    foreign import java unsafe
    toString :: (a <: Object) => a -> String
    type instance Inherits File = '[Object]
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係を踏まえた関数呼び出し
    #ScalaMatsuri

    View Slide

  76. {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE TypeFamilies #-}
    foreign import java unsafe
    toString :: (a <: Object) => a -> String
    type instance Inherits File = '[Object]
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係を踏まえた関数呼び出し
    #ScalaMatsuri

    View Slide

  77. GHC Extensions
    ● GHC specialities
    ○ Experimental futures, out of the language spec
    ○ Eta, which is a fork of GHC, can use them
    ● Enabled by special comments
    ○ {-# LANGUAGE ExtensionNames #-}
    ● Unavoidable for modern Haskell
    ○ Especially abstract frameworks
    Eta は GHC のフォークなので
    コンパイラ拡張が使用可能
    #ScalaMatsuri

    View Slide

  78. Extensions for Inheritance
    ● DataKinds
    ○ Promote normal types to kinds
    ● TypeFamilies
    ○ Define type-level functions
    ● TypeOperators
    ○ Declare an infix operator for a 2-param typeclass
    継承関係を表現するための三つの拡張
    #ScalaMatsuri

    View Slide

  79. Types and Kinds
    ● Kinds are “types of types”
    ○ 1, 2, 3, … :: Int
    ○ Int, String, File, ... :: *
    ○ Maybe :: * -> *
    ● DataKinds promote datatypes
    ○ Types to kinds, data constructors to types
    ○ Enable to use values in type-level functions
    カインドは「型の型」
    DataKinds 拡張でデータ型を昇格できる
    #ScalaMatsuri

    View Slide

  80. TypeFamilies
    type family Inherits (a :: *) :: [*]
    data Defined = Yes | No
    type family Extends'
    (a :: Class) (b :: Class) :: Defined where
    Extends' a a = Yes
    Extends' a Object = Yes
    Extends' Object a = No
    Extends' a b = ExtendsList (Inherits a) b
    TypeFamilies 拡張を用いた型レベル計算
    #ScalaMatsuri

    View Slide

  81. TypeFamilies
    type family Inherits (a :: *) :: [*]
    data Defined = Yes | No
    type family Extends'
    (a :: Class) (b :: Class) :: Defined where
    Extends' a a = Yes
    Extends' a Object = Yes
    Extends' Object a = No
    Extends' a b = ExtendsList (Inherits a) b
    TypeFamilies 拡張を用いた型レベル計算
    type-level function
    #ScalaMatsuri

    View Slide

  82. TypeFamilies
    type family Inherits (a :: *) :: [*]
    data Defined = Yes | No
    type family Extends'
    (a :: Class) (b :: Class) :: Defined where
    Extends' a a = Yes
    Extends' a Object = Yes
    Extends' Object a = No
    Extends' a b = ExtendsList (Inherits a) b
    TypeFamilies 拡張を用いた型レベル計算
    promoted kind
    #ScalaMatsuri

    View Slide

  83. TypeFamilies
    type family Inherits (a :: *) :: [*]
    data Defined = Yes | No
    type family Extends'
    (a :: Class) (b :: Class) :: Defined where
    Extends' a a = Yes
    Extends' a Object = Yes
    Extends' Object a = No
    Extends' a b = ExtendsList (Inherits a) b
    TypeFamilies 拡張を用いた型レベル計算
    a extends b?
    #ScalaMatsuri

    View Slide

  84. TypeFamilies
    type family ExtendsList
    (a :: [*]) (b :: *) :: Defined where
    ExtendsList '[] y = No
    ExtendsList (x ': xs) y =
    Or (Extends' x y) (ExtendsList xs y)
    type family Or
    (a :: Defined) (b :: Defined) :: Defined where
    Or No No = No
    Or a b = Yes
    TypeFamilies 拡張を用いた型レベル計算
    #ScalaMatsuri

    View Slide

  85. TypeFamilies
    type family ExtendsList
    (a :: [*]) (b :: *) :: Defined where
    ExtendsList '[] y = No
    ExtendsList (x ': xs) y =
    Or (Extends' x y) (ExtendsList xs y)
    type family Or
    (a :: Defined) (b :: Defined) :: Defined where
    Or No No = No
    Or a b = Yes
    TypeFamilies 拡張を用いた型レベル計算
    (one of a) extends b?
    #ScalaMatsuri

    View Slide

  86. TypeOperators
    class (Class a, Class b) => Extends a b where
    superCast :: a -> b
    unsafeCast :: b -> a
    instance (Class a, Class b, Extends' a b ~ Yes)
    => Extends a b where
    type (<:) a b = Extends a b
    TypeOperators 拡張による型演算子の定義
    #ScalaMatsuri

    View Slide

  87. TypeOperators
    class (Class a, Class b) => Extends a b where
    superCast :: a -> b
    unsafeCast :: b -> a
    instance (Class a, Class b, Extends' a b ~ Yes)
    => Extends a b where
    type (<:) a b = Extends a b
    TypeOperators 拡張による型演算子の定義
    #ScalaMatsuri

    View Slide

  88. {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE TypeFamilies #-}
    foreign import java unsafe
    toString :: (a <: Object) => a -> String
    type instance Inherits File = '[Object]
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係を踏まえた関数呼び出し
    #ScalaMatsuri

    View Slide

  89. {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE TypeFamilies #-}
    foreign import java unsafe
    toString :: (a <: Object) => a -> String
    type instance Inherits File = '[Object]
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係を踏まえた関数呼び出し
    TypeOperators
    #ScalaMatsuri

    View Slide

  90. {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE TypeFamilies #-}
    foreign import java unsafe
    toString :: (a <: Object) => a -> String
    type instance Inherits File = '[Object]
    main :: IO ()
    main = do
    file <- java $ newFile "text.txt"
    putStrLn $ toString file
    継承関係を踏まえた関数呼び出し
    TypeFamilies
    #ScalaMatsuri

    View Slide

  91. Recap of Section. 2
    ● Exposting Eta functions
    ○ Straightforward, just as static methods
    ● Java monads
    ○ Method receiver can be considered as a monad
    ● inheritance
    ○ Type-level definitions by the GHC extensions
    Eta からエクスポートはそのまま
    インポートは Java モナドと型レベル記述を活用
    #ScalaMatsuri

    View Slide

  92. 3.
    HYBRID PROJECT
    ハイブリッド・プロジェクトの構成
    Why composability matters?
    #ScalaMatsuri

    View Slide

  93. Eta から Scala
    #ScalaMatsuri

    View Slide

  94. object Client {
    implicit val system = ActorSystem()
    implicit val materializer = ActorMaterializer()
    implicit val execContext = system.dispatcher
    val responseFuture: Future[HttpResponse] =
    Http().singleRequest(
    HttpRequest(uri = "https://akka.io"))
    responseFuture.onComplete {
    case Success(res) => println(res)
    case Failure(_) => sys.error("ERROR!")
    }
    }
    Scala による Akka HTTP Client のサンプル
    #ScalaMatsuri

    View Slide

  95. apply メソッドの糖衣構文
    // sugared
    val system = ActorSystem()
    // actual
    val system = ActorSystem.apply()
    data ActorSystem = ...
    foreign import java unsafe
    "@static akka.actor.ActorSystem.apply"
    newActorSystem :: Java a ActorSystem
    #ScalaMatsuri

    View Slide

  96. apply メソッドの糖衣構文
    // sugared
    val system = ActorSystem()
    // actual
    val system = ActorSystem.apply()
    data ActorSystem = ...
    foreign import java unsafe
    "@static akka.actor.ActorSystem.apply"
    newActorSystem :: Java a ActorSystem
    static method
    #ScalaMatsuri

    View Slide

  97. // sugared
    val materializer = ActorMaterializer()
    /* actual
    *
    * ActorMaterializer.apply(
    * settings: Option[MaterializerSettings] = None,
    * prefix: Option[String] = None
    * ) (implicit context: ActorRefFactory)
    */
    val materializer =
    ActorMaterializer(None, None, system)
    実は大量のデフォルト・暗黙引数
    #ScalaMatsuri

    View Slide

  98. // sugared
    val materializer = ActorMaterializer()
    /* actual
    *
    * ActorMaterializer.apply(
    * settings: Option[MaterializerSettings] = None,
    * prefix: Option[String] = None
    * ) (implicit context: ActorRefFactory)
    */
    val materializer =
    ActorMaterializer(None, None, system)
    実は大量のデフォルト・暗黙引数
    default / implicit args
    #ScalaMatsuri

    View Slide

  99. data Option a = Option (@scala.Option a)
    data ActorRefFactory = ...
    data ActorMaterializerSettings = ...
    type instance Inherits ActorSystem =
    '[Object, ActorRefFactory]
    foreign import java unsafe
    "@static akka.stream.ActorMaterializer.apply"
    newActorMaterializer
    :: (a <: ActorRefFactory)
    => Option ActorMaterializerSettings
    -> Option JString -> a
    -> Java c ActorMaterializer
    明示的なインポートが必要
    #ScalaMatsuri

    View Slide

  100. Annoying
    めんどい
    #ScalaMatsuri

    View Slide

  101. Difficulty in Scala Interop
    ● Eta interop is “sugar free”
    ○ Designed for Java interoperation
    ○ Poor support for commonly-used Scala data types
    ● Lots of boilerplates required
    ○ Backfire of Scala’s sophisticated features
    ○ Code generator is not well-developed
    ● Better to use Java libraries
    Eta から Scala のライブラリを呼ぶと
    ボイラプレートが増えがち
    #ScalaMatsuri

    View Slide

  102. Best Practice for Hybrid Projects
    ● Phase 1: Eta inside Scala
    ○ Eta is only for pure logic, like data transformation
    ○ Scala parts invokes Eta
    ○ Communicate with outside by Scala
    ● Phase 2: Java Inside Eta
    ○ Eta is for main parts of the service
    ○ Eta invokes Java, to communicate others
    第一段階:Scala 内に Eta を埋め込む
    第二段階:Eta 内に Java を埋め込む
    #ScalaMatsuri

    View Slide

  103. Gradual Hybriding Strategy
    段階的な置き換え戦略
    Framework
    Micro Service
    #ScalaMatsuri

    View Slide

  104. Gradual Hybriding Strategy
    段階的な置き換え戦略
    Framework
    #ScalaMatsuri

    View Slide

  105. Gradual Hybriding Strategy
    段階的な置き換え戦略
    Framework
    #ScalaMatsuri

    View Slide

  106. Gradual Hybriding Strategy
    段階的な置き換え戦略
    Framework
    #ScalaMatsuri

    View Slide

  107. Gradual Hybriding Strategy
    段階的な置き換え戦略
    Framework
    #ScalaMatsuri

    View Slide

  108. Gradual Hybriding Strategy
    段階的な置き換え戦略
    REST, gRPC
    #ScalaMatsuri

    View Slide

  109. Gradual Hybriding Strategy
    段階的な置き換え戦略
    REST, gRPC
    #ScalaMatsuri

    View Slide

  110. Etlas
    ● Standard Build Tool for Eta
    ○ Forked from Cabal in Haskell
    ○ Similar to sbt in Scala
    ● Dependency manager + task runner
    ○ Common build definition with Haskell (.cabal)
    ○ Accesses official Haskell package repos (Hackage)
    ○ Fetches patches from eta-hackage
    Eta 用ビルドツール Etlas
    Haskell と共通の仕組みを利用
    #ScalaMatsuri

    View Slide

  111. Toy Example
    ● Microservice written in Scala
    ○ On Scala pipeline, built by sbt
    ● Transform JSON
    ○ Consider records like { “name”: “alice”, “age”: 17 }
    ○ Capitalize “name” fields
    ○ Add 1 to the “age” fields
    簡単なサンプルプロジェクト
    #ScalaMatsuri

    View Slide

  112. Embed Eta into Scala
    Scala プロジェクトに Eta を埋め込む
    Framework
    #ScalaMatsuri

    View Slide

  113. Directory Structure
    +-- project
    | +-- plugins.sbt
    +-- src
    +-- main
    +-- scala
    | +-- example
    | +-- Main.scala
    +-- eta
    +-- example.cabal
    +-- Example
    +-- Transform.hs
    プロジェクトの構成
    #ScalaMatsuri

    View Slide

  114. Directory Structure
    +-- project
    | +-- plugins.sbt
    +-- src
    +-- main
    +-- scala
    | +-- example
    | +-- Main.scala
    +-- eta
    +-- example.cabal
    +-- Example
    +-- Transform.hs
    プロジェクトの構成
    embedded project
    #ScalaMatsuri

    View Slide

  115. Cabal File for Etlas
    library
    build-depends: base
    , lens
    exported-moduels: Example.Transform
    default-language: Haskell2010
    Etlas 用ビルド定義
    #ScalaMatsuri

    View Slide

  116. Cabal File for Etlas
    library
    build-depends: base
    , lens
    exported-moduels: Example.Transform
    default-language: Haskell2010
    Etlas 用ビルド定義
    Haskell library
    #ScalaMatsuri

    View Slide

  117. module Example.Transform where
    fixJson :: JString -> JString
    fixJson = toJava . transform . fromJava
    where
    transform :: Text -> Text
    transform json = json
    & (key "name" . _String) %~ toUpper
    & (key "age" . _Integral) %~ (+1)
    foreign export java
    "@static eta.example.Transform.fixJson"
    fixJson :: JString -> JString
    Eta 側:純粋なロジック
    #ScalaMatsuri

    View Slide

  118. module Example.Transform where
    fixJson :: JString -> JString
    fixJson = toJava . transform . fromJava
    where
    transform :: Text -> Text
    transform json = json
    & (key "name" . _String) %~ toUpper
    & (key "age" . _Integral) %~ (+1)
    foreign export java
    "@static eta.example.Transform.fixJson"
    fixJson :: JString -> JString
    Eta 側:純粋なロジック
    #ScalaMatsuri

    View Slide

  119. package example
    import eta.example.Transform
    object Main extends App {
    val writer = new PrintWriter(new File("out.json"))
    Source.fromResource("in.json")
    .getLine.foreach { json =>
    writer.write(Transform.fixJson(json) ++ "\n")
    }
    writer.close()
    }
    Scala 側:外界との inpure なやりとり
    #ScalaMatsuri

    View Slide

  120. package example
    import eta.example.Transform
    object Main extends App {
    val writer = new PrintWriter(new File("out.json"))
    Source.fromResource("in.json")
    .getLine.foreach { json =>
    writer.write(Transform.fixJson(json) ++ "\n")
    }
    writer.close()
    }
    Scala 側:外界との inpure なやりとり
    singleton method
    #ScalaMatsuri

    View Slide

  121. sbt Plugin for Etlas
    +-- project
    | +-- plugins.sbt
    +-- src
    +-- main
    +-- scala
    | +-- example
    | +-- Main.scala
    +-- eta
    +-- example.cabal
    +-- Example
    +-- Transform.hs
    プラグインの導入
    #ScalaMatsuri

    View Slide

  122. sbt Plugin for Etlas
    +-- project
    | +-- plugins.sbt
    +-- src
    +-- main
    +-- scala
    | +-- example
    | +-- Main.scala
    +-- eta
    +-- example.cabal
    +-- Example
    +-- Transform.hs
    プラグインの導入
    addSbtPlugin("com.typelead" % "sbt-eta" % "0.1.0")
    #ScalaMatsuri

    View Slide

  123. Embed Java into Eta
    Eta プロジェクトに Java を埋め込む
    Framework
    #ScalaMatsuri

    View Slide

  124. Directory Structure
    +-- example.cabal
    +-- src
    | +-- Main.hs
    +-- java
    +-- example
    +-- Util.java
    プロジェクトの構成
    #ScalaMatsuri

    View Slide

  125. Directory Structure
    +-- example.cabal
    +-- src
    | +-- Main.hs
    +-- java
    +-- example
    +-- Util.java
    プロジェクトの構成
    embedded project
    #ScalaMatsuri

    View Slide

  126. Cabal File for Etlas
    executable eta-example
    main-is: Main.hs
    hs-source-dirs: src
    build-depends: base
    default-language: Haskell2010
    java-sources: java/example/Util.java
    , /path/to/Util.class
    , /path/to/Util.jar
    maven-depends: com.example:awesome:x.y.z
    Etlas 用ビルド定義
    #ScalaMatsuri

    View Slide

  127. Cabal File for Etlas
    executable eta-example
    main-is: Main.hs
    hs-source-dirs: src
    build-depends: base
    default-language: Haskell2010
    java-sources: java/example/Util.java
    , /path/to/Util.class
    , /path/to/Util.jar
    maven-depends: com.example:awesome:x.y.z
    Etlas 用ビルド定義
    Java stuffs
    #ScalaMatsuri

    View Slide

  128. Cabal File for Etlas
    executable eta-example
    main-is: Main.hs
    hs-source-dirs: src
    build-depends: base
    default-language: Haskell2010
    java-sources: java/example/Util.java
    , /path/to/Util.class
    , /path/to/Util.jar
    maven-depends: com.example:awesome:x.y.z
    Etlas 用ビルド定義
    Maven repository
    #ScalaMatsuri

    View Slide

  129. Recap of Section. 3
    ● Scala libraries are hard to use from Eta
    ○ Eta cannot handle Scala’s syntactic sugar
    ○ In the most cases, Java version is better to import
    ● Follow the best practice
    ○ Firstly embed Eta into Scala
    ○ Then embed Java into Eta
    ● sbt, Maven repos + Etlas integration
    Eta から呼ぶなら Scala ではなく Java
    ビルドツールを通じて段階的に導入可能
    #ScalaMatsuri

    View Slide

  130. 4.
    NEXT STEPS
    今日から始める Eta
    Let’s be a Eta expert
    #ScalaMatsuri

    View Slide

  131. Tour of Eta
    ● Online tutorials with a sandbox
    ○ https://tour.eta-lang.org
    ● The best starting point for Eta newbies
    ● Focusing on practical use
    ○ Basics, like syntax and flow control
    ○ “Haskell-ish” design patterns
    ○ A little more practical than “Learn you a Haskell”
    Eta 公式のオンラインチュートリアル
    #ScalaMatsuri

    View Slide

  132. Eta 公式のオンラインチュートリアル
    #ScalaMatsuri

    View Slide

  133. Japan Haskell User Group (Haskell-jp)
    ● Since Mar. 2017
    ● Monthly meetup
    ○ a.k.a. Mokumoku-kai
    ○ Newbies are welcome!
    ○ https://haskell-jp.connpass.com
    ● Slack / Reddit / Blog
    ○ https://haskell.jp
    日本 Haskell ユーザグループの活動
    #ScalaMatsuri

    View Slide

  134. 日本 Haskell ユーザグループの活動
    #ScalaMatsuri

    View Slide

  135. Google Summer of Code
    ● Ideas List (abr)
    ○ Better type error messages
    ○ Eta on Android
    ○ High-performance Web server with Fibers threading
    ○ Purity & nullability analysis
    ● Deadline: 27th Mar. 16:00 UTC
    ○ https://eta-lang.org/contribute/gsoc/2018
    Google Summer of Code の対象プロジェクトに
    #ScalaMatsuri

    View Slide

  136. 5.
    SUMMARY
    本日のまとめ
    What you’ve gotten in 40 mins
    #ScalaMatsuri

    View Slide

  137. Summary
    ● IO in Haskell
    ○ Compiler can check side-effect as a type
    ● Java/Scala interoperation
    ○ Java monads + type-level GHC extensions
    ● Strategy for hybrid projects
    ○ Haskell is for internal pure logic, inside Scala
    本日のまとめ
    #ScalaMatsuri

    View Slide

  138. Scala もいいけど Haskell もね!
    Happy Haskelling!
    Presented by Cheshire Cat (@y_taka_23)
    #ScalaMatsuri

    View Slide