forked from Yingxue0323/SlackOffDocs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFrom JavaScript to Haskell.txt
More file actions
30 lines (29 loc) · 4.95 KB
/
From JavaScript to Haskell.txt
File metadata and controls
30 lines (29 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Learning Outcomes
• Compare a lambda-calculus inspired-Haskell-like language (PureScript) with the functional programming concepts explored earlier in JavaScript
• Understand how tail call optimisation is applied in languages which support it
Introduction
JavaScript is a multiparadigm language that—due to its support for functions as objects, closures and, therefore, higher-order functions —is able to be used in a functional programming style. However, if you are really enamoured with currying and combining higher-order functions , then it really makes a lot of sense to use a language that is actually designed for it.
There are a number of purpose-built Functional Programming languages. Lisp (as we have already discussed) is the original, but there are many others. Scheme is a Lisp derivative, as is (more recently) Clojure. SML and its derivatives (e.g. OCaml, F#, etc.) form another family of functional programming languages. However, the strongest effort to build a language that holds to the principles of lambda-calculus-inspired functional programming such as immutability (purity) is the Haskell family.
There are a number of efforts to bring Haskell-like purity to web programming, inspired by the potential benefits the functional style holds for managing complex state in asynchronous and distributed applications. Firstly, it is possible to compile Haskell code directly to JavaScript (using GHCJS) although the generated code is opaque and requires a runtime. Another promising and increasingly popular Haskell-inspired language for client-side web development is Elm, although this again requires a runtime. Also, Elm is rather specialised for creating interactive web apps.
The JavaScript-targeting Haskell derivative we are going to look at now is PureScript. The reason for this choice is that PureScript generates standalone and surprisingly readable JavaScript. For a full introduction to the language, the PureScript Book, written by the language’s creator, is available for free. However, in this unit we will only make a brief foray into PureScript as a segue from JavaScript to Haskell. To avoid overwhelming ourselves with minor syntactic differences we will also endeavour to stick to a subset of PureScript that is syntactically the same as Haskell.
Hello Functional Language
Without further ado, here is some PureScript code. Fibonacci number computation is often called the “hello world!” of functional programming:
fibs :: Int -> Int
fibs 0 = 1
fibs 1 = 1
fibs n = fibs (n-1) + fibs (n-2)
Woah! A function for Fibonacci numbers that is about as minimal as you can get! And the top line, which just declares the type of the function, is often optional—depending on whether the compiler can infer it from the context. Having said that, it’s good practice to include a type declaration, especially for top-level functions (functions defined without indentation and therefore in-scope everywhere in the file). This function takes an Int (integer) parameter and returns an Int. Note that the arrow shorthand for the function type definition is highly reminiscent of the JavaScript fat-arrow (=>) though skinnier.
The next three lines define the actual logic of the function, which very simply gives a recursive definition for the nth Fibonacci number. This definition uses a feature common to many functional programming languages: pattern matching. That is, we define the fibs function three times, with the first two definitions handling the base cases. It says, literally: “the 0th and 1st fibs are both 1”. The last line defines the general case, that the remaining Fibonacci numbers are each the sum of their two predecessors. Note, this definition is not perfect. Calling:
fibs -1
would be a bad idea. Good practice would be to add some exceptions for incorrect input to our function. In a perfect world we would have a compiler that would check types dependent on values (actually, languages that support dependent types exist, e.g. the Idris language is an interesting possible successor to Haskell in this space).
Python3.10+ has taken inspiration from this pattern, and has its own alternative to pattern matching, with a slightly more verbose syntax. This is semantically identical to the PureScript definition, where we use pattern matching against the inputs. For completeness, all functions should aim to provide the type definition, similar to what we did in the PureScript example.
def fibs(n: int) -> int:
match n:
case 0:
return 1
case 1:
return 1
case _:
return fibs(n - 1) + fibs(n-2)
print(fibs(12))
One thing you will have noticed by now is that Haskell-like languages are light on syntax: this is obvious when compared next to the Python alternative. Especially, use of brackets is minimal, and typically to be avoided when evaluation order can be inferred correctly by the compiler’s application of lambda-calculus-inspired precedence rules for function and operator application.