Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Java/Scala から Eta #ScalaMatsuri

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Eta から Java #ScalaMatsuri

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

flatMap Scala の flatMap #ScalaMatsuri

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

-- 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

Slide 62

Slide 62 text

-- 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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

{-# 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

Slide 76

Slide 76 text

{-# 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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

{-# 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

Slide 89

Slide 89 text

{-# 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

Slide 90

Slide 90 text

{-# 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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

Eta から Scala #ScalaMatsuri

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

// 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

Slide 98

Slide 98 text

// 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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

Annoying めんどい #ScalaMatsuri

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

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

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

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

Slide 135

Slide 135 text

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

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

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