Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using Eta for what you don't like writing in Scala

Using Eta for what you don't like writing in Scala

The integration of Scala with a lazy-by-default, modern and statically-typed functional language could lead to some interesting language-heterogeneous implementations despite the fact that the Eta programming language is missing a comprehensive documentation, robust concurrency support and an interactive REPL.

This talk aims to cover some of those interaction patterns to help both people already working or struggling with Haskell, and through that to also motivate the use of Eta for those still unfamiliar with this "end of the FP spectrum".

Filippo Vitale

May 03, 2017
Tweet

More Decks by Filippo Vitale

Other Decks in Technology

Transcript

  1. May 2017
    @filippovitale
    Using for what you
    don't like writing in .

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. What is Eta?

    View Slide

  8. https://jaxenter.com/pirates-of-the-jvm-the-infographic-132524.html

    View Slide

  9. https://jaxenter.com/pirates-of-the-jvm-the-infographic-132524.html

    View Slide

  10. Modern Haskell on the JVM
    - Rahul Muttineni
    - github.com/typelead/eta
    - github.com/typelead/etlas
    - github.com/typelead/eta-hackage
    - Objectives
    - JVM + Haskell Ecosystems
    - Accessibility for beginners
    It is GHC 7.10.3

    View Slide

  11. Modern Haskell on the JVM
    - Rahul Muttineni
    - github.com/typelead/eta
    - github.com/typelead/etlas
    - github.com/typelead/eta-hackage
    - Objectives
    - JVM + Haskell Ecosystems
    - Accessibility for beginners
    forked from haskell/cabal
    It is GHC 7.10.3

    View Slide

  12. Modern Haskell on the JVM
    - Rahul Muttineni
    - github.com/typelead/eta
    - github.com/typelead/etlas
    - github.com/typelead/eta-hackage
    - Objectives
    - JVM + Haskell Ecosystems
    - Accessibility for beginners
    forked from haskell/cabal
    set of patches for
    particular packages from
    Hackage that cannot be
    built out-of-the-box
    It is GHC 7.10.3

    View Slide

  13. What does Eta compile?

    View Slide

  14. module Main where
    import System.CPUTime
    main :: IO ()
    main = getCPUTime >>= print
    object Main extends App {
    println(System.nanoTime() * 1000)
    }
    https://github.com/filippovitale/eta-playground/tree/master/simplest-ghc-program

    View Slide

  15. module Main where
    import System.CPUTime
    main :: IO ()
    main = getCPUTime >>= print
    object Main extends App {
    println(System.nanoTime() * 1000)
    }
    λ> :t getCPUTime
    getCPUTime :: IO Integer

    View Slide

  16. module Main where
    import System.CPUTime
    main :: IO ()
    main = getCPUTime >>= print
    object Main extends App {
    println(System.nanoTime() * 1000)
    }
    λ> :t print
    print :: Show a => a -> IO ()
    λ> :t getCPUTime
    getCPUTime :: IO Integer
    λ> :i Integer

    instance Show Integer

    View Slide

  17. module Main where
    import System.CPUTime
    main :: IO ()
    main = getCPUTime >>= print
    object Main extends App {
    println(System.nanoTime() * 1000)
    }

    View Slide

  18. module Main where
    import System.CPUTime
    main :: IO ()
    main = getCPUTime >>= print
    object Main extends App {
    nanoTime() * 1000 |> println
    }

    View Slide

  19. $ cat > Main.hs
    stack ghc Main.hs && ./Main

    View Slide

  20. $ cat > Main.hs
    $ eta Main.hs
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...

    View Slide

  21. $ cat > Main.hs
    $ eta Main.hs
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    $ java -jar RunMain.jar
    422227000000

    View Slide

  22. $ cat > Main.hs
    $ eta Main.hs
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    Driver
    .hs
    ghc
    Core STG
    https://www.microsoft.com/en-us/research/wp-content/uploads/1992/04/spineless-tagless-gmachine.pdf

    View Slide

  23. $ cat > Main.hs
    $ eta Main.hs
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    Driver
    Parser
    Typechecker
    Desugarer
    Optimizer
    Simplifier
    Code
    Generator
    .hs
    Core STG
    ghc
    http://www.aosabook.org/en/ghc.html

    View Slide

  24. $ cat > Main.hs
    $ eta Main.hs
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    Driver
    Parser
    Typechecker
    Desugarer
    Optimizer
    Simplifier
    Code
    Generator
    .hs
    Core STG
    .jar

    View Slide

  25. $ cat > Main.hs
    $ eta Main.hs
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    $ ls -lh
    -rw-r--r-- 711B Main.hi
    -rw-r--r-- 84B Main.hs
    -rw-r--r-- 3.3K Main.jar
    -rw-r--r-- 18M RunMain.jar
    - Main.jar content
    - all the dependencies
    - GHC runtime-system
    https://github.com/filippovitale/eta-playground/tree/master/simplest-ghc-program

    View Slide

  26. How can we use libs from
    the JVM ecosystem?

    View Slide

  27. View Slide

  28. {-# LANGUAGE MagicHash #-}
    module Main where
    import Java
    -- foreign import declaration
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeIO :: IO Int64
    main :: IO ()
    main = nanoTimeIO >>= print
    $ eta Main.hs && java -jar RunMain.jar
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    149320110727531
    IO Monad
    https://github.com/filippovitale/eta-playground/blob/master/java-static-import

    View Slide

  29. {-# LANGUAGE MagicHash #-}
    module Main where
    import Java
    -- foreign import declaration
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeJava :: Java a Int64
    main :: IO ()
    main = java nanoTimeJava >>= print
    $ eta Main.hs && java -jar RunMain.jar
    [1 of 1] Compiling Main ( Main.hs, Main.jar )
    Linking RunMain.jar ...
    149319575014401
    java :: Java c a -> IO a
    Java Monad

    View Slide

  30. {-# LANGUAGE MagicHash #-}
    module Main where
    import Java
    -- foreign import declarations
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeJava :: Java a Int64
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeIO :: IO Int64
    forall a. Java a b
    -- isomorphic to --
    IO b
    https://github.com/typelead/eta/issues/255#issuecomment-290937594

    View Slide

  31. {-# LANGUAGE MagicHash #-}
    module Main where
    import Java
    -- foreign import declarations
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeJava :: Java a Int64
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeIO :: IO Int64
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimePlain :: Int64
    main :: IO ()
    main = do
    java nanoTimeJava >>= print
    java nanoTimeJava >>= print
    nanoTimeIO >>= print
    nanoTimeIO >>= print
    print nanoTimePlain
    print nanoTimePlain

    View Slide

  32. {-# LANGUAGE MagicHash #-}
    module Main where
    import Java
    -- foreign import declarations
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeJava :: Java a Int64
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimeIO :: IO Int64
    foreign import java unsafe "@static java.lang.System.nanoTime" nanoTimePlain :: Int64
    main :: IO ()
    main = do
    java nanoTimeJava >>= print
    java nanoTimeJava >>= print
    nanoTimeIO >>= print
    nanoTimeIO >>= print
    print nanoTimePlain
    print nanoTimePlain
    $ java -jar RunMain.jar
    149319575014401
    149320109787317
    149320110727531
    149320111517553
    149320112027191
    149320112027191
    https://github.com/filippovitale/eta-playground/blob/master/java-static-import

    View Slide

  33. From Java static methods
    to full libraries

    View Slide

  34. https://github.com/filippovitale/eta-playground/tree/master/javafx-canvas-grid

    View Slide

  35. $ mkdir javafx-canvas-grid && cd "$_"
    $ etlas init && tree
    .
    ├── LICENSE
    ├── Setup.hs
    ├── javafx-canvas-grid.cabal

    View Slide

  36. $ mkdir javafx-canvas-grid && cd "$_"
    $ etlas init && tree
    .
    ├── LICENSE
    ├── Setup.hs
    ├── javafx-canvas-grid.cabal
    └── src
    ├── CanvasGridApp.hs
    ├── JavaFX
    │ ├──
    │ ├──
    │ └──
    ├── JavaFX.hs
    └── Main.hs

    View Slide

  37. $ mkdir javafx-canvas-grid && cd "$_"
    $ etlas init && tree
    .
    ├── LICENSE
    ├── Setup.hs
    ├── javafx-canvas-grid.cabal
    └── src
    ├── CanvasGridApp.hs
    ├── JavaFX
    │ ├── Core.hs
    │ ├── Methods.hs
    │ └── Types.hs
    ├── JavaFX.hs
    └── Main.hs

    View Slide

  38. module JavaFX.Types where
    import Java
    data {-# CLASS "javafx.stage.Stage" #-} Stage = Stage (Object# Stage) deriving Class
    data {-# CLASS "javafx.scene.Scene" #-} Scene = Scene (Object# Scene) deriving Class
    data {-# CLASS "javafx.scene.Group" #-} Group = Group (Object# Group) deriving Class
    -- There is a default instance for “object arrays”
    data {-# CLASS "javafx.scene.canvas.Canvas" #-} Canvas = Canvas (Object# Canvas) deriving Class
    data {-# CLASS "javafx.scene.canvas.Canvas[]" #-} Canvases = Canvases (Object# Canvases) der...
    instance JArray Canvas Canvases
    src/JavaFX/Types.hs

    View Slide

  39. module JavaFX.Methods where
    import Java
    import JavaFX.Types
    -- Stage methods
    foreign import java unsafe "show" show :: Java Stage ()
    foreign import java unsafe "setTitle" setTitle :: String -> Java Stage ()
    foreign import java unsafe "setScene" setScene :: Scene -> Java Stage ()
    -- GraphicsContext methods
    foreign import java unsafe "fillOval" fillOval ::
    Double -> Double -> Double -> Double -> Java GraphicsContext ()
    src/JavaFX/Methods.hs

    View Slide

  40. import javafx.application.Application
    import javafx.stage.Stage
    class CanvasGridApp extends Application {
    override def start(primaryStage: Stage): Unit = {
    ???
    }
    }

    View Slide

  41. module CanvasGridApp where
    import Java
    data {-# CLASS "org.eta.CanvasGridApp extends javafx.application.Application" #-}
    CanvasGridApp = CanvasGridApp (Object# CanvasGridApp)
    start :: Stage -> Java CanvasGridApp ()
    start primaryStage = undefined
    foreign export java "start" start :: Stage -> Java CanvasGridApp ()
    src/CanvasGridApp.hs
    class CanvasGridApp extends Application {
    override def start(primaryStage: Stage): Unit = {
    ???
    }
    }

    View Slide

  42. start :: Stage -> Java CanvasGridApp ()
    start primaryStage = do
    c <- newCanvas w h
    gc <- c <.> getGraphicsContext2D
    src/CanvasGridApp.hs
    -- Execute a Java action in the Java monad of another class
    -- with respect to the given object.
    (<.>) :: (Class c) => c -> Java c a -> Java b a

    View Slide

  43. start :: Stage -> Java CanvasGridApp ()
    start primaryStage = do
    c <- newCanvas w h
    gc <- c <.> getGraphicsContext2D
    forM_ [(i, j) | i <- [0..(n-1)], j <- [0..(n-1)]]
    $ \(i, j) -> gc <.> fillOval (u*i) (u*j) (u*r) (u*r)
    src/CanvasGridApp.hs

    View Slide

  44. start :: Stage -> Java CanvasGridApp ()
    start primaryStage = do
    c <- newCanvas w h
    gc <- c <.> getGraphicsContext2D
    forM_ [(i, j) | i <- [0..(n-1)], j <- [0..(n-1)]]
    $ \(i, j) -> gc <.> fillOval (u*i) (u*j) (u*r) (u*r)
    s <- (newGroup c) >>= newScene
    primaryStage <.> (setScene s >> setTitle "Eta-JavaFX CanvasGrid" >> show)
    where w = 320
    h = 320
    n = 8
    u = (min w h) / n
    r = 0.9
    src/CanvasGridApp.hs

    View Slide

  45. $ etlas run
    Resolving dependencies...
    Configuring javafx-canvas-grid-0.1.0.0...
    Preprocessing executable 'javafx-canvas-grid'
    Building executable 'javafx-canvas-grid'
    [1 of 6] Compiling JavaFX.Types
    [2 of 6] Compiling JavaFX.Methods
    [3 of 6] Compiling JavaFX.Core
    [4 of 6] Compiling JavaFX
    [5 of 6] Compiling CanvasGridApp
    [6 of 6] Compiling Main
    Linking dist/build/javafx-canvas-grid/javafx-canvas-grid.jar ...
    Running javafx-canvas-grid...
    https://github.com/filippovitale/eta-playground/tree/master/javafx-canvas-grid

    View Slide

  46. Old school Demoscene

    View Slide

  47. https://pouet.net/

    View Slide

  48. http://www.p01.org/

    View Slide

  49. http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/
    http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf
    Signed Distance Function
    http://www.p01.org/tea_storm/
    Here be
    Dragons

    View Slide

  50. start :: Stage -> Java TeaStormApp ()
    start primaryStage = do
    t0 <- nanoTime
    c <- newCanvas w h
    s <- (newGroup c) >>= newScene
    loop <- newAnimationLoop c t0 n u m
    loop <.> startAnimation
    primaryStage <.> (setTitle "Eta-JavaFX TeaStorm" >> setScene s >> show)
    where n = 96
    m = 10
    w = n * m
    h = n * m
    u = (min w h) / n
    src/TeaStormApp.hs
    https://github.com/filippovitale/eta-playground/tree/master/javafx-teastorm

    View Slide

  51. start :: Stage -> Java TeaStormApp ()
    start primaryStage = do
    t0 <- nanoTime
    c <- newCanvas w h
    s <- (newGroup c) >>= newScene
    loop <- newAnimationLoop c t0 n u m
    loop <.> startAnimation
    primaryStage <.> (setTitle "Eta-JavaFX TeaStorm" >> setScene s >> show)
    where n = 96
    m = 10
    w = n * m
    h = n * m
    u = (min w h) / n
    src/TeaStormApp.hs

    View Slide

  52. name: javafx-teastorm
    version: 0.1.0.0
    homepage: https://github.com/filippovitale/eta-playground/javafx-teastorm
    executable javafx-teastorm
    main-is: Main.hs
    java-sources: java/teastorm/AnimationLoop.java
    build-depends: base >=4.8 && <4.9
    hs-source-dirs: src
    default-language: Haskell2010
    javafx-teastorm.cabal

    View Slide

  53. public class AnimationLoop extends AnimationTimer {
    public AnimationLoop(Canvas c, long t0, double n, double u, double m) {...}
    private static double computeIntensity(final double x, final double y, final double s, final double t) {
    double intensity = 1;
    for (double d = intensity * 4, df = 1; .025 < df * intensity; intensity -= .025) {
    double X = d * x / s - d / 2;
    double Y = d * y / s - d / 2;
    double Z = d / 2 - 9;
    df = (X * X +
    Y * Y * Math.cos(t/6 + Math.cos(d - X - Y)) +
    Z * Z) / 12
    - 1 + Math.cos(X + t) * Math.cos(Y - t);
    d += df;
    }
    return intensity;
    }
    @Override
    public void handle(long currentNanoTime) {
    double t = (currentNanoTime - t0) / (500 * oneMillisecondInNanoTime);
    gc.clearRect(0, 0, w, h); // clear the Canvas
    for (int x = 0; x < n; x++) {
    for (int y = 0; y < n; y++) {
    double i = computeIntensity(x, y, n, t);
    gc.setGlobalAlpha(i);
    gc.fillOval(x * u, y * u, i * m * 1.4, i * m * 1.4);
    }
    }
    }
    }

    View Slide

  54. $ etlas run
    Resolving dependencies...
    Configuring javafx-teastorm-0.1.0.0...
    Preprocessing executable 'javafx-teastorm' for
    javafx-teastorm-0.1.0.0..
    Building executable 'javafx-teastorm' for javafx-teastorm-0.1.0.0..
    [1 of 6] Compiling JavaFX.Types
    [2 of 6] Compiling JavaFX.Methods
    [3 of 6] Compiling TeaStormApp
    [4 of 6] Compiling JavaFX.Core
    [5 of 6] Compiling JavaFX
    [6 of 6] Compiling Main
    Linking dist/build/javafx-teastorm/javafx-teastorm.jar ...
    Running javafx-teastorm...
    https://github.com/filippovitale/eta-playground/tree/master/javafx-teastorm

    View Slide

  55. Eta is embeddable:
    you can export Haskell
    functions to the JVM

    View Slide

  56. Source
    Sink

    View Slide

  57. Boba Fett
    WARAWHWHAHOR

    View Slide

  58. FileIO.fromPath(jsonPath)
    .via(gunzip())
    .via(lineSplitter)
    .map(_.utf8String)
    .via(extractNameFlow)
    .via(wookieeFlow)
    .runWith(Sink.foreach(println))
    extractNameFlow
    wookieeFlow
    https://github.com/filippovitale/eta-playground/tree/master/scala-akka-stream-eta-wookiee

    View Slide

  59. name: scala-akka-stream-eta-wookiee
    version: 0.1.0.0
    cabal-version: >=1.10
    executable scala-akka-stream-eta-wookiee
    main-is: Main.hs
    build-depends: base >=4.8 && <4.9,
    bytestring,
    containers,
    aeson
    hs-source-dirs: src
    default-language: Haskell2010
    -- java-sources: lib/manually-downloaded-akka-stream-uber.jar

    View Slide

  60. name: scala-akka-stream-eta-wookiee
    version: 0.1.0.0
    cabal-version: >=1.10
    executable scala-akka-stream-eta-wookiee
    main-is: Main.hs
    build-depends: base >=4.8 && <4.9,
    bytestring,
    containers,
    aeson
    hs-source-dirs: src
    default-language: Haskell2010
    maven-depends: com.typesafe.akka:akka-stream_2.12:2.4.17

    View Slide

  61. name: scala-akka-stream-eta-wookiee
    version: 0.1.0.0
    cabal-version: >=1.10
    executable scala-akka-stream-eta-wookiee
    main-is: Main.hs
    build-depends: base >=4.8 && <4.9,
    bytestring,
    containers,
    aeson
    hs-source-dirs: src
    default-language: Haskell2010
    maven-depends: com.typesafe.akka:akka-stream_2.12:2.4.17

    View Slide

  62. src/AkkaStream/Exports.hs
    data {-# CLASS "stream.Example" #-} Example = Example (Object# Example)
    type JStringFlow = Flow JString JString NotUsed
    extractNameFlow :: Java Example JStringFlow
    extractNameFlow = undefined
    wookieeFlow :: Java Example JStringFlow
    wookieeFlow = undefined
    foreign export java extractNameFlow :: Java Example JStringFlow
    foreign export java wookieeFlow :: Java Example JStringFlow

    View Slide

  63. src/AkkaStream/Exports.hs
    data {-# CLASS "stream.Example" #-} Example = Example (Object# Example)
    type JStringFlow = Flow JString JString NotUsed
    extractNameFlow :: Java Example JStringFlow
    extractNameFlow = flowFromFunction $ applyFunction f
    where
    f js = undefined
    wookieeFlow :: Java Example JStringFlow
    wookieeFlow = flowFromFunction $ applyFunction f
    where
    f js = undefined
    foreign export java extractNameFlow :: Java Example JStringFlow
    foreign export java wookieeFlow :: Java Example JStringFlow
    akka.stream.javadsl.Flow.fromFunction
    static Flow fromFunction(Function f)

    View Slide

  64. src/AkkaStream/Exports.hs
    data {-# CLASS "stream.Example" #-} Example = Example (Object# Example)
    type JStringFlow = Flow JString JString NotUsed
    extractNameFlow :: Java Example JStringFlow
    extractNameFlow = flowFromFunction $ applyFunction f
    where
    f js = undefined
    wookieeFlow :: Java Example JStringFlow
    wookieeFlow = flowFromFunction $ applyFunction f
    where
    f js = undefined
    foreign export java extractNameFlow :: Java Example JStringFlow
    foreign export java wookieeFlow :: Java Example JStringFlow
    akka.japi.function.Function
    trait Function[-T, +R] { def apply(param: T): R }

    View Slide

  65. src/AkkaStream/Exports.hs
    data {-# CLASS "stream.Example" #-} Example = Example (Object# Example)
    type JStringFlow = Flow JString JString NotUsed
    extractNameFlow :: Java Example JStringFlow
    extractNameFlow = flowFromFunction $ applyFunction f
    where
    f js = return (toJava $ g $ pack (fromJava js :: [Char]))
    g s = (fromMaybe empty (decode s :: Maybe (Map String String))) ! "name"
    wookieeFlow :: Java Example JStringFlow
    wookieeFlow = flowFromFunction $ applyFunction f
    where
    f js = return (toJava $ (fromJava js :: [Char]) >>= wookiee)
    foreign export java extractNameFlow :: Java Example JStringFlow
    foreign export java wookieeFlow :: Java Example JStringFlow

    View Slide

  66. src/main/scala/stream/Main.scala
    object Main extends App {
    val e = new Example()
    val extractNameFlow = e.extractNameFlow()
    val wookieeFlow = e.wookieeFlow()
    val jsonURL = getClass.getResource("/all_characters.json-stream.gz")
    val jsonPath = Paths.get(jsonURL.toURI)
    val lineSplitter = Framing.delimiter(ByteString("\n"), Int.MaxValue)
    FileIO.fromPath(jsonPath)
    .via(gunzip())
    .via(lineSplitter)
    .map(_.utf8String)
    .via(extractNameFlow)
    .via(wookieeFlow)
    .runWith(Sink.foreach(println))
    .onComplete(_ => system.terminate())
    }

    View Slide

  67. https://github.com/filippovitale/eta-playground/tree/master/scala-akka-stream-eta-wookiee

    View Slide

  68. Where Eta is going?

    View Slide

  69. - Interactive REPL
    - Java FFI imports aid / helpers
    - Hot-code reloading as JVM has “built-in dynamism”
    - GraalVM on JDK9
    - New JIT Compiler and
    - Polyglot Runtime for the JVM
    - Stability
    - Support for the fundamental Hackage libraries
    Eta active development areas

    View Slide

  70. May 2017
    @filippovitale
    Thanks!

    View Slide

  71. May 2017
    @filippovitale
    $ tail -f questions

    View Slide