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

Exploring Tailrec Through Time Until Kotlin

Exploring Tailrec Through Time Until Kotlin

This document is a presentation made for a YouTube video for my channel JESPROTECH about the evolution of tailrec through the years accross some of the most well known, and some not so known languages. The goal isn't to go through all languages ever invented, but to gain a prespective about tailrec that exists already in programming languages since the 1950's. The idea is to situate us in time and understand where we come from when we talk about tailrec and tail call optimization (TCO).

More Decks by João Filipe Sabino Esperancinha

Other Decks in Technology

Transcript

  1. Who am I? Overview Understanding the problems Project objective Target

    audience Market trends Cycle diagram João Esperancinha • Java • Kotlin • Groovy • Scala • Software Engineer 10+ years • JESPROTECH owner for 1 year • Kong Champion/Java Professional/Spring Professional Project timeline
  2. What is tailrec? • Recursivity No, not just any recursivity

    Any Recursivity? • Tail recursivity • The last function call! And then?
  3. What defines a tail recursive function? A recursive function is

    said to be tail recursive when: • The last function call is the call to the recursive function • The last function call doesn’t occur in combination with any calculated value or any other function call • In other words nothing should be stored per stack frame Awesome!
  4. When did Tailrec become a thing? 01 Lorem ipsum dolor

    sit amet, consectetur adipiscing elit. Curabitur eleifend a diam quis suscipit. Class aptent taciti sociosqu ad litora et nec torquent per conubia nostra. 02 Amet, consectetur adipiscing elit. Curabitur eleifend a diam quis suscipit. Class aptent taciti The ad litora torquent per conubia nostra.fd 03 Consectetur adipiscing elit. Curabitur eleifend lorem a diam quis suscipit. Class aptent taciti sociosqu ad litora torquent ipsum per conubia nostra. Late 1950’s computing studies showed that tail recursive algorithms could be easily reimplemented with iterative alternatives, making them more efficient No more usage of Stack Frames No need to hold values in memory for every iteration Tail Recursivity Became a thing! Space complexity reduced to O(1)
  5. The 1950’s 1957 - IBM Mathematical Formula Translating System, or

    Fortran. Created by John Backus team 1959 - COBOL by CODASYL (Conference/Committee on Data Systems Languages) 1958 - LISP by John McCarthy By Jooja CC BY-SA 4.0 DEED By PIerre.Lescanne CC BY-SA 4.0 DEED John Backus By WikiPedant CC BY-SA 2.0 DEED John McCarthy By Jonathan Schilling CC BY-SA 4.0 DEED COBOL punch cards
  6. The 1970’s to the 90’s • 1983-84 - Standard ML(Meta

    Language) by Robin Milner, Mads Tofte, and others at the University of Edinburgh • 1975 - Scheme by Gerald Jay Sussman and Guy L. Steele Jr • 1990 - Haskell named after Haskell Curry and released by committee of researchers and academics • 1986 - Erlang by Joe Armstrong, Robert Virding, and Mike Williams at Ericsson By Magnus Manske CC BY-SA 1.0 DEED Gerald Jay Sussman By George Ruban CC BY-SA 4.0 DEED Guy L. Steele Jr By Flavbeli CC BY 2.0 DEED University of Edinburgh
  7. The 1990’s to 2016 - JVM Evolution • 2007 Clojure

    by Rich Hickey • 1995 - Java by Sun Microsystems, however the invention of Java is attributed to James Gosling and colleagues Mike Sheridan, and Patrick Naughton • 2016 by the team led by Andrey Breslav • 2003 Scala by Martin Odersky James Gosling By Peter Campbell CC BY-SA 4.0 DEED Rich Hickey By Tapestry Dude - Flickr CC BY-SA 2.0 DEED Martin Odersky By LindaPoengPhotography CC BY 3.0 DEED By Lightbend, Inc. CC BY 4.0 DEED
  8. What was the whole point? • Function Simplification • Use

    recursivity without impacting performance • Make code easy to read • Avoid the usage of global variables • Adhere to immutability principles Much later on…
  9. A pseudo-code example function fibonacci(n) = { var result =

    0 var next = 1 var i = 0 while (i < n) { val temp = next next = result + next result = temp i += 1 } return result } Leonardo of Pisa By Hans-Peter Postel CC BY 2.5 DEED Statue of Fibonacci (1863) by Giovanni Paganucci in the Camposanto di Pisa Fibonacci Sequence 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 … etc F(n) = F(n-1) + F(n-2) Iterations • Efficient • Difficult to Read 👎 O(n) time / O(1) space By Romain CC BY-SA 4.0 DEED Graphical representation
  10. A pseudo-code example function fibonacci(n) { if (n <= 1)

    { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } Fibonacci Sequence 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 … etc F(n) = F(n-1) + F(n-2) Recursivity • Not very efficient 👎 • Easier to read 👍 O(2^n) time / O(2^n) space function fibonacci(n) { if (n <= 1) { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } function fibonacci(n) { if (n <= 1) { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } function fibonacci(n) { if (n <= 1) { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } function fibonacci(n) { if (n <= 1) { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } function fibonacci(n) { if (n <= 1) { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } function fibonacci(n) { if (n <= 1) { return n } else { return fibonacci(n - 1) + fibonacci(n - 2) } } (…) (…) (…) (…)
  11. A pseudo-code example Fibonacci Sequence 0, 1, 1, 2, 3,

    5, 8, 13, 21, 34 … etc F(n) = F(n-1) + F(n-2) Tail Recursivity • Back to being efficient 👍 • Still easy to read, but less 👎 O(n) time / O(1) space function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } • Efficiency isn’t 100% guaranteed 👎 function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } function fibonacci(n) { function fiboHelper(n, result, next) { if (n == 0) result else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } (…)
  12. Applying TCO Tail Call Optimization function fibonacci(n) { function fiboHelper(n,

    result, next) { if (n == 0) next else return fiboHelper(n - 1, next, result + next) } return fiboHelper(n, 0, 1) } function fibonacci(n) { function fiboHelper(n) = { var result = 0 var next = 1 var i = 0 while (i < n) { val temp = next next = result + next result = temp i += 1 } return result } } How we implement… … how we would have implemented in the result
  13. The Beginnings with Fortran - 1957 • Fortran I: 1957

    • Fortran II: 1958 • Fortran III: Not released • Fortran IV: 1962 • Fortran 66: 1966 • Fortran 77: 1977 • Fortran 90: 1991 • Fortran 95: 1997 • Fortran 2003: 2004 • Fortran 2008: 2010 • Fortran 2018: 2018 PROGRAM FIBONACCI INTEGER N, I REAL F1, F2, FIB N = 100 F1 = 0 F2 = 1 DO I = 2, N FIB = F1 + F2 F1 = F2 F2 = FIB END DO WRITE(*,*) FIB END PROGRAM RECURSIVE_FIBONACCI_REAL INTEGER N N = 100 DO I = 0, N - 1 CALL fibonacci_real(I, Result) END DO WRITE(*, *) Result CONTAINS RECURSIVE SUBROUTINE fibonacci_real(N, Result) INTEGER N REAL Result IF (N <= 1) THEN Result = REAL(N) ELSE CALL fibonacci_real(N - 1, Result1) CALL fibonacci_real(N - 2, Result2) Result = Result1 + Result2 END IF END SUBROUTINE fibonacci_real END Recursivity
  14. Fortran nowadays (since 1991) program Fibonacci implicit none integer ::

    n, i real :: fib_prev, fib_current, result n = 100 fib_prev = 0 fib_current = 1 do i = 1, n if (i <= 1) then result = i else result = fib_prev + fib_current fib_prev = fib_current fib_current = result end if end do print *, "The result is", result end program Fibonacci program FibonacciTailRecursive implicit none integer :: n, i real :: result n = 100 result = fibonacci(n) print *, "The result is", result contains recursive function fibonacci(n) result(fib) integer, intent(in) :: n integer :: fib if (n == 0) then fib = 0 else if (n == 1) then fib = 1 else fib = fibonacci(n - 1) + fibonacci(n - 2) end if end function fibonacci end program FibonacciTailRecursive program FibonacciTailRecursive implicit none integer :: n real :: result n = 100 result = fibonacci(n) print *, "The result is", result contains recursive function fibonacci(n) result(fib) integer, intent(in) :: n real :: fib if (n <= 1) then fib = n else fib = fibonacci_helper(n, 0.0, 1.0) end if end function fibonacci recursive function fibonacci_helper(n, a, b) result(fib) integer, intent(in) :: n real :: fib, a, b if (n == 0) then fib = a else if (n == 1) then fib = b else fib = fibonacci_helper(n - 1, b, a + b) end if end function fibonacci_helper end program FibonacciTailRecursive
  15. LISP 1958 (defun fibonacci-iterative (n) (if (<= n 1) n

    (fib-iter 0 1 n))) (defun fib-iter (a b count) (loop repeat (- count 1) do (setf (values a b) (values b (+ a b))) finally (return b))) (defun fibonacci-recursive (n) (if (<= n 1) n (+ (fibonacci-recursive (- n 1)) (fibonacci-recursive (- n 2))))) • Lisp: 1958 • Lisp 1.5: 1962 • MacLisp: Late 1960s • InterLisp: 1966 • Common Lisp: 1984 (defun fibonacci-tail-recursive (n) (if (<= n 1) n (fib-tail-recursive 0 1 n))) (defun fib-tail-recursive (a b count) (if (= count 0) a (fib-tail-recursive b (+ a b) (- count 1))))
  16. COBOL 1959 IDENTIFICATION DIVISION. PROGRAM-ID. Fibonacci. DATA DIVISION. WORKING-STORAGE SECTION.

    01 F1 PIC 9(21)V9(1) VALUE 0.0. 01 F2 PIC 9(21)V9(1) VALUE 1.0. 01 FIB PIC 9(21)V9(1). 01 N PIC 9(5) VALUE 100. 01 I PIC 9(5) VALUE 3. PROCEDURE DIVISION. MAIN-LOGIC. PERFORM VARYING I FROM 2 BY 1 UNTIL I > N COMPUTE FIB = F1 + F2 COMPUTE F1 = F2 COMPUTE F2 = FIB END-PERFORM. DISPLAY FIB. STOP RUN. IDENTIFICATION DIVISION. PROGRAM-ID. FibonacciRecursive. DATA DIVISION. WORKING-STORAGE SECTION. 01 F1 PIC 9(21)V9(1) VALUE 0.0. 01 F2 PIC 9(21)V9(1) VALUE 1.0. 01 FIB PIC 9(21)V9(1). 01 N PIC 9(5) VALUE 100. 01 I PIC 9(5) VALUE 0. PROCEDURE DIVISION. MOVE N TO I CALL 'FIBONACCI'. DISPLAY "Fibonacci of " I " is " F1. STOP RUN. ENTRY 'FIBONACCI'. IF N = 0 THEN EXIT PROGRAM ELSE COMPUTE FIB = F1 + F2 COMPUTE F1 = F2 COMPUTE F2 = FIB SUBTRACT 1 FROM N CALL 'FIBONACCI' END-IF. • COBOL 60 - 1960. • COBOL 61 - 1961. • COBOL 65 - 1965. • COBOL 68 - 1968 • COBOL 74 - 1974 • COBOL 85 - 1985 • COBOL 2002 - 2002 • COBOL 2014 - 2014 Recursivity
  17. Scheme - 1975 (define (fibonacci n) (fibonacci-iter n 0 1))

    (define (fibonacci-iter n a b) (do ((i n (- i 1)) (x a b) (y b (+ a b))) ((= i 0) x) (set! a x) (set! b y))) (define (fibonacci n) (if (or (= n 0) (= n 1)) n (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) (display (fibonacci 100)) • Scheme 75: 1975 • Scheme 84: 1984 • Several follow up releases until 2013 (define (fibonacci n) (define (fib-helper n a b) (if (= n 0) a (fib-helper (- n 1) b (+ a b)))) (fib-helper n 0 1)) (display (fibonacci 100))
  18. Standard Meta Language - 1983/84 • Moby: Moby - 1980’s

    • SML/NJ - 1983/1984 • MLton - 1999 • SML '90 - 1990 • SML '97 - 1997 • SML 2007 - 2007 • SML 2022 - 2022 fun fibonacci n = if n < 2 then n else fibonacci (n - 1) + fibonacci (n - 2); structure IntInf = IntInf fun fibonacci n = let fun fibIter n a b = if n = 0 then a else fibIter (n - 1) b (IntInf.+(a, b)) in fibIter n 0 1 end;
  19. Erlang - 1986 • Erlang 1986 - First proprietary release

    • Erlang/OTP R1 (1996) - First commercial release • Erlang/OTP 24 - Erlang until 2021 -module(fibonacci_recursive). -export([fib/1]). fib(0) -> 0; fib(1) -> 1; fib(N) when N > 1 -> fib(N - 1) + fib(N - 2). -module(fibonacci_recursive_tco). -export([fib/1]). fib(N) when N < 2 -> N; fib(N) -> fib_iter(N, 0, 1). fib_iter(0, A, _) -> A; fib_iter(N, A, B) -> fib_iter(N - 1, B, A + B).
  20. Haskell - 1990 • First draft - 1987 • Haskell

    1.0 - 1990 • Haskell 1.1 - 1991 • Haskell 1.2 - 1992 • Haskell 1.3 - 1996 • Haskell 1.4 - 1997 • Haskell 98 - 1998 • Haskell 2010 - 2010 • Haskell 2022 - 2022 fibonacci :: Integer -> Integer fibonacci 0 = 0 fibonacci 1 = 1 fibonacci n = fibonacci (n - 1) + fibonacci (n - 2) main :: IO () main = do let result = fibonacci 1000 putStrLn $ "Fibonacci of the order of 1000: " ++ show result fibonacciTailRec :: Integer -> Integer fibonacciTailRec n = fibonacciHelper n 0 1 where fibonacciHelper 0 a _ = a fibonacciHelper 1 _ b = b fibonacciHelper n a b = fibonacciHelper (n - 1) b (a + b) main :: IO () main = do let result = fibonacciTailRec 1000 putStrLn $ "Fibonacci of the order of 1000: " ++ show result
  21. About Java - 1995 Java deliberately doesn’t support Tail Call

    Optimization because: • Backward compatibility • It might not go well with the JVM architecture because of overhead and potential side-effects. • Performance and complexity • The iterative alternative is always possible • Not very clear if TCO is the best idea for Java But this didn’t stop JVM alternative languages to explore TCO possibilities...
  22. Scala - 2003 • Scala 1.0 - 2003 • Scala

    2.0 - 2006 • Scala 2.7 - 2009 • Scala 2.8 - 2010 • Scala 2.9 - 2011 • Scala 2.10 - 2012 • Scala 2.11 - 2014 • Scala 2.12 - 2016 • Scala 2.13 - 2019 • Scala 3 (previously known as Dotty) - 2020 def fibonacciIterative(n: Double): Double = { var a = 0f var b = 1f var i = 0f while (i < n) { val temp = b b = a + b a = temp i += 1 } a } def fibonacciRecursive(n: Double): Double = { if (n <= 1f) { n } else { fibonacciRecursive(n - 1f) + fibonacciRecursive(n - 2f) } } def fibonacciTailRec(n: Double): Double = { def fibHelper(n: Double, a: Double, b: Double): Double = { if (n == 0.0) a else fibHelper(n - 1.0, b, a + b) } fibHelper(n, 0.0, 1.0) }
  23. Scala - 2003 • Scala 1.0 - 2003 • Scala

    2.0 - 2006 • Scala 2.7 - 2009 • Scala 2.8 - 2010 • Scala 2.9 - 2011 • Scala 2.10 - 2012 • Scala 2.11 - 2014 • Scala 2.12 - 2016 • Scala 2.13 - 2019 • Scala 3 (previously known as Dotty) - 2020 def fibonacciTailRecTCO(n: Double): Double = { @annotation.tailrec def fibHelper(n: Double, a: Double, b: Double): Double = { if (n == 0f) a else fibHelper(n - 1f, b, a + b) } fibHelper(n, 0f, 1f) } def fibonacciTailRecManualTCO(n: Double): Double = { def fibHelper(n: Double, a: Double, b: Double): Double = { var a = 0f var b = 1f var i = 0f while (i < n) { val temp = b b = a + b a = temp i += 1 } a if (n == 0.0) a else fibHelper(n - 1.0, b, a + b) } fibHelper(n, 0.0, 1.0) }
  24. Scala - 2003 def fibonacciTailRecTCO(n: Double): Double = { @annotation.tailrec

    def fibHelper(n: Double, a: Double, b: Double): Double = { if (n == 0f) a else fibHelper(n - 1f, b, a + b) } fibHelper(n, 0f, 1f) } def factorialUnMarked(n: Double): Double = { def factorialHelper(n: Double): Double = { if (n <= 1f) 1f else n * factorialHelper(n - 1f) } factorialHelper(n) } public static double factorialUnMarked(double var0) { return Fibonacci$.MODULE$.factorialUnMarked(var0); } public double factorialUnMarked(final double n) { return this.factorialHelper$1(n); } private final double factorialHelper$1(final double n) { return n <= 1.0 ? 1.0 : n * this.factorialHelper$1(n - 1.0); } public static double fibonacciTailRecTCO(double var0) { return Fibonacci$.MODULE$.fibonacciTailRecTCO(var0); } public double fibonacciTailRecTCO(final double n) { return this.fibHelper$3(n, 0.0, 1.0); } private final double fibHelper$3(final double n, final double a, final double b) { while(n != 0.0) { double var7 = n - 1.0; double var11 = a + b; n = var7; a = b; b = var11; } return a; }
  25. Clojure - 2007 (defn fibonacci-iterative [n] (if (<= n 1)

    n (loop [a 0 b 1 i 1] (if (= i n) (+ a b) (recur b (+ a b) (inc i)))))) (defn fibonacci-recursive [n] (let [n (if (instance? String n) (Double/parseDouble n) n)] (if (<= n 1.0) n (+ (fibonacci-recursive (- n 1.0)) (fibonacci-recursive (- n 2.0)))))) (defn fibonacci-tail-rec [n] (let [n (if (instance? String n) (Double/parseDouble n) n)] (letfn [(fib-tail [n a b] (if (zero? n) a (fib-tail (dec n) b (+ a b))))] (fib-tail n 0.0 1.0)))) • First version - 2007 • Clojure 1.0 - 2009 • Clojure until 1.11.1 in 2022
  26. Clojure - 2007 • First version - 2007 • Clojure

    1.0 - 2009 • Clojure until 1.11.1 in 2022 (defn fibonacci-tail-rec-tco [n] (let [n (if (instance? String n) (Double/parseDouble n) n)] (letfn [(fib [n a b] (if (zero? n) a (recur (dec n) b (+ a b))))] (fib n 0.0 1.0))))
  27. Kotlin - 2016 • Kotlin 1.0 - 2016 • Kotlin

    1.1 - 2017 • Kotlin 1.2 - 2017 • Kotlin 1.3 - 2018 • Kotlin 1.4 - 2020 • Kotlin 1.5 - 2021 • Kotlin 1.6 - 2021 • Kotlin 1.7 - 2022 • Kotlin 1.8 - 2023 • Kotlin 1.9 - 2023 private fun fibonacciIterative(n: Int): Double { if (n <= 1) { return n.toDouble() } var a = 0.0 var b = 1.0 for (i in 2..n) { val temp = a + b a = b b = temp } return b } fun fibonacciRecursive(n: Int): Double = if (n <= 1) n.toDouble() else fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2) private fun fibonacciTailRecursive( n: Int, a: Double = 0.0, b: Double = 1.0 ): Double = if (n == 0) a else fibonacciTailRecursive(n - 1, b, a + b)
  28. Kotlin - 2016 private tailrec fun fibonacciTailRecursiveTCO( n: Int, a:

    Double = 0.0, b: Double = 1.0 ): Double = if (n == 0) a else fibonacciTailRecursiveTCO(n - 1, b, a + b) • Kotlin 1.0 - 2016 • Kotlin 1.1 - 2017 • Kotlin 1.2 - 2017 • Kotlin 1.3 - 2018 • Kotlin 1.4 - 2020 • Kotlin 1.5 - 2021 • Kotlin 1.6 - 2021 • Kotlin 1.7 - 2022 • Kotlin 1.8 - 2023 • Kotlin 1.9 - 2023
  29. Kotlin - 2016 private tailrec fun fibonacciTailRecursiveTCO( n: Int, a:

    Double = 0.0, b: Double = 1.0 ): Double = if (n == 0) a else fibonacciTailRecursiveTCO(n - 1, b, a + b) private fun fibonacciTailRecursive( n: Int, a: Double = 0.0, b: Double = 1.0 ): Double = if (n == 0) a else fibonacciTailRecursive(n - 1, b, a + b) private final double fibonacciTailRecursive(int n, double a, double b) { return n == 0 ? a : ((Companion)this).fibonacciTailRecursive(n - 1, b, a + b); } // $FF: synthetic method static double fibonacciTailRecursive$default(Companion var0, int var1, double var2, double var4, int var6, Object var7) { if ((var6 & 2) != 0) { var2 = 0.0; } if ((var6 & 4) != 0) { var4 = 1.0; } return var0.fibonacciTailRecursive(var1, var2, var4); } private final double fibonacciTailRecursiveTCO(int n, double a, double b) { while(n != 0) { Companion var10000 = (Companion)this; int var10001 = n - 1; double var10002 = b; b += a; a = var10002; n = var10001; } return a; } // $FF: synthetic method static double fibonacciTailRecursiveTCO$default(Companion var0, int var1, double var2, double var4, int var6, Object var7) { if ((var6 & 2) != 0) { var2 = 0.0; } if ((var6 & 4) != 0) { var4 = 1.0; } return var0.fibonacciTailRecursiveTCO(var1, var2, var4); }
  30. Conclusions • Which direction is this all taking? • Is

    programming still a challenge? • Why do we do software development? • Are we being forced into thinking recursively? • Is Mutability something to be completely removed from a programming language? • Productivity vs The Joy of Coding • What happens when we keep thinking only recursively when implementing algorithms? • Can we blindly rely on the TCO algorithms in the way that we already trust Garbage Collection? • Do we trust Garbage Collection? • Can we manually implement a better algorithm with better performance than TCO? • Would we still be able to do it, if we don’t practice? • Can we still produce without challenges in the long run?
  31. Resources for this presentation Image sources • https://commons.wikimedia.org/wiki/File:John_McCarthy_Stanford.jpg • https://commons.wikimedia.org/wiki/File:John_Backus_2.jpg

    • https://commons.wikimedia.org/wiki/File:Guy_Steele.jpg • https://commons.wikimedia.org/wiki/File:Jerry_Sussman.jpg • https://nl.wikipedia.org/wiki/Rij_van_Fibonacci#/media/Bestand:Fibonacci_Spiral.svg • https://en.wikipedia.org/wiki/File:Fortran_logo.svg • https://en.m.wikipedia.org/wiki/File:Lisp_logo.svg • https://commons.wikimedia.org/wiki/File:IBM_keypunch_deck_for_Cobol_student_program_at_New_York_Universit y_1979.jpg • https://commons.wikimedia.org/wiki/File:Lambda_lc.svg • https://commons.wikimedia.org/wiki/File:Informatics_Forum_Atrium_turned.jpg • https://commons.wikimedia.org/wiki/File:Ericsson_logo.svg • https://commons.wikimedia.org/wiki/File:Erlang_logo.png • https://en.wikipedia.org/wiki/File:Haskell-Logo.svg • https://commons.wikimedia.org/wiki/File:James_Gosling_2008.jpg • https://commons.wikimedia.org/wiki/File:Mark_Odersky_photo_by_Linda_Poeng.jpg • https://commons.wikimedia.org/wiki/File:Scala-full-color.svg • https://en.m.wikipedia.org/wiki/File:Clojure_logo.svg • https://commons.wikimedia.org/wiki/File:Kotlin_logo_2021.svg
  32. Resources for this presentation • https://www.smlnj.org/sml.html • https://en.wikibooks.org/wiki/Standard_ML_Programming/Types • https://en.wikipedia.org/wiki/Standard_ML

    • https://www.smlnj.org/ • https://www.scala-lang.org/ • https://kotlinlang.org/ • https://en.wikipedia.org/wiki/COBOL • https://fortran-lang.org/ • https://www.java.com/en/ • https://developer.ibm.com/languages/cobol/ • https://www.haskell.org/ • https://www.erlang.org/ • https://gcc.gnu.org/onlinedocs/gcc-13.2.0/gfortran/Code-Gen-Options.html Data sources
  33. About me • Homepage - https://joaofilipesabinoesperancinha.nl • LinkedIn - https://www.linkedin.com/in/joaoesperancinha/

    • YouTube - JESPROTECH ▪ https://www.youtube.com/channel/UCzS_JK7QsZ7ZH-zTc5kBX_g ▪ https://www.youtube.com/@jesprotech • Bluesky - https://bsky.app/profile/jesperancinha.bsky.social • Mastodon - https://masto.ai/@jesperancinha • GitHub - https://github.com/jesperancinha • Hackernoon - https://hackernoon.com/u/jesperancinha • DevTO - https://dev.to/jofisaes • Medium - https://medium.com/@jofisaes