Syntactic Cheat Sheet

Translating from TypeScript to Haskell

Basics

Comments

TypeScript
Haskell
TypeScript
// This is a TypeScript comment
/*
Need more space?
No problem!
This is a multi-line TypeScript comment :)
*/
/**
* In TS, you write documentation like this for TypeDoc
*/
const id = a => a
Haskell
-- This is a Haskell comment
{-
Need more space?
No problem!
This is a multi-line Haskell comment :)
-}
--| Add a pipe for a short function description
-- You can keep talking about is afterwards
-- These will turn into formatted documentation with Haddock
id a = a
{-| You can use a multi-line comment for Haddock, too
The same rules apply.
-}
swap (a, b) -> (b, a)

Assignment

Implicit Type

TypeScript
Haskell
TypeScript
const hi = "Hello World"
Haskell
hi = "Hello World"

Explicit Type

TypeScript
Haskell
Haskell (Local Clarification Variant)
TypeScript
const hi: string = 'Hello World'
Haskell
hi :: Text
hi = "Hello World"
Haskell (Local Clarification Variant)
hi = ("Hello World" :: Text)

Functions

Anonymous

TypeScript
Haskell
Haskell (Shorthand)
TypeScript
a => a * 2
Haskell
\a -> a * 2
-- NOTE: `\` is an easier to type lambda `λ`
Haskell (Shorthand)
(*2)

Named

TypeScript
Haskell
Haskell (Shorthand)
TypeScript
const double = (a : number) => a * 2
Haskell
double :: Int -> Int
double a = a * 2
Haskell (Shorthand)
double :: Int -> Int
double = (*2)

Infix

TypeScript
Haskell
TypeScript
// Does not exist
Haskell
(*&) :: Int -> String -> String
num *& str = show num ++ str
-- NOTE: `show` turns values into strings

Argument Application

TypeScript
Haskell
TypeScript
const result = doTheThing(1, 2, ["a", "b"], 1.1)
Haskell
result = doTheThing 1 2 ["a", "b"] 1.1

Side-Effectful

TypeScript
Haskell
TypeScript
fireTheMissiles()
Haskell
fireTheMissiles

Inner Scope

TypeScript
Haskell (let...in)
Haskell (where)
TypeScript
const withInner = (toLog: string): void => {
const innerValue = 'That is the question!'
console.log(`${toLog}? Or not ${toLog}? ${innerValue}`)
}
Haskell (let...in)
withInner' toLog =
let
innerValue = "That is the question!"
msg = toLog <> "? Or not " <> toLog <> "? " <> innerValue
in
logInfo msg
Haskell (where)
withInner toLog = logInfo msg
where
msg = toLog <> "? Or not " <> toLog <> "? " <> innerValue
innerValue = "That is the question!"

Nested Application

TypeScript
Haskell (parens)
Haskell (applied with $)
Haskell (Piped with &)
TypeScript
const result = triple(prod(1, double(1), 3))
/* i.e.
const two = double(1)
const six = prod(1, two, 3)
const result = triple(six)
*/
Haskell (parens)
result = triple (prod 1 (double 1) 3)
Haskell (applied with $)
result = triple $ prod 1 (double 1) 3
Haskell (Piped with &)
result = 3
& prod 1 (double 1)
& triple

Composition

TypeScript
Haskell
TypeScript
const timesSix = (a: number): number => triple(double(a))
Haskell
timesSix :: Int -> Int
timeSix = triple . double

Partial Application

TypeScript
Haskell
Haskell (Point-Free Style)
TypeScript
const math = (n: number, m: number): number =
triple(prod(10, double(1), n), m)
Haskell
math :: Int -> Int -> Int
math n m = triple (prod 10 (double 1) n) m
Haskell (Point-Free Style)
math :: Int -> Int -> Int
math = triple . prod 10 (double 1)

Modules

TypeScript
Haskell
TypeScript
import * from "./GetEverything"
import * as HL from "./HelperLib";
import { foo, bar } from "./SomeLib"
const id = a => a
const swap = ([a, b]) => [b, a]
const hiddenValue = HL.downcase("not exported")
export {
id,
swap
}
export { toReExport } from "./ExternalLib"
Haskell
module MyModule
( id
, swap
, toReExport
) where
import GetEverything
import SomeLib (foo, bar)
import ExternalLib (toReExport)
import qualified HelperLib as HL
id a = a
swap (a, b) = (b, a)
hiddenValue = HL.downcase "not exported"

Types & Data

Type Alias

TypeScript
Haskell
TypeScript
type Name = string
type Balance = number
Haskell
type Name = Text
type Balance = Int

Sum / Enum / Coproduct

TypeScript
Haskell
TypeScript
type TrafficLight = 'RED' | 'YELLOW' | 'GREEN'
Haskell
data TrafficLight
= Red
| Yellow
| Green

Product

TypeScript
Haskell
TypeScript
type GearRatio = [number, number] // [big gear, little gear]
type Bike = [string, GearRatio] // [bikeName, gear ratio]
Haskell
data GearRatio = GearRatio Int Int
data Bike = Bike Text GearRatio

Interfaces & Classes → Records

TypeScript (Interface)
TypeScript (Class)
Haskell
TypeScript (Interface)
interface GearRatio {
big: number
little: number
}
interface Bike {
name: string
gear: GearRatio
}
TypeScript (Class)
class Geared {
big: number
little: number
constructor(gbr: number, lgr: number) {
big = bgr
little = lgr
}
}
class Bike extends Geared {
name: string
constructor(bgr: number, lgr: number, bikeName: string) {
name = bikeName
super(bgr, lgr)
}
}
Haskell
data Gear = GearRatio
{ _big :: Natural
, _little :: Natural
}
data Bike = Bike
{ _name :: Text
, _gear :: Gear
}

Constructors

TypeScript (Direct)
TypeScript (Class)
Haskell
TypeScript (Direct)
const makeGear = (big, little): GearRatio => ({ big, little })
const makeBike = (big, little, name): Bike => ({
name,
gear = makeGear(big, little)
})
TypeScript (Class)
/*
Included in the `class` delcaration. For example:
constructor(bgr: number, lgr: number) {
big = bgr
little = lgr
}
*/
Haskell
{-
Constructors are the capitalized word on
the right of the `=` in the `data` declaration
It auto-generates constructor functions
with the folling type signatures:
GearRatio :: Natural -> Natural -> Geared
Bike :: Text -> GearRatio -> Bike
-}

Instantiation

TypeScript (Direct)
TypeScript (Class)
Haskell
Haskell (Record Style)
Haskell (Wildcard Style)
TypeScript (Direct)
const myBike = makeBike(2, 5, '10 Speeder')
TypeScript (Class)
const myBike = new Bike(2, 5, '10 Speeder')
Haskell
myBike = Bike "10 Speeder" (GearRatio 2 5)
Haskell (Record Style)
myBike = Bike
{ _name = "10 Speeder" -- Use named fields
, _gear = GearRatio 2 5 -- Or just ordered values
}
Haskell (Wildcard Style)
myBike :: Bike
myBike =
let
_big = 2
_little = 5
_name = "10 Speeder"
_gear = GearRatio {..}
in
Bike {..}

Getters

TypeScript (Dot Syntax)
TypeScript (Destructuring)
Haskell (Destructuring)
Haskell (Wildcard Style)
Haskell (Lenses)
TypeScript (Dot Syntax)
const big: number = myGears.big
const little = myBike.gear.little
TypeScript (Destructuring)
const { bigGear } = myGears
const getBig = ({ big }) => big
const ratio = ({ big, little }) => big / little
Haskell (Destructuring)
GearRatio big _ = myGears
getBig (GearRatio {_big}) = _big
ratio (GearRatio {_big, _little}) = _big / _little
Haskell (Wildcard Style)
ratio (GearRatio {..}) = _big / _little
Haskell (Lenses)
import Control.Lens.TH
$(makeLenses ''Gear)
$(makeLenses ''Bike)
myGear ^. big -- NOTE: lenses have no underscores!
-- Nested
myBike ^. gear . little

Updating with Setters

TypeScript
Haskell (Record Syntax)
Haskell (Lenses)
TypeScript
// Preamble
const myGear = new GearRatio(2, 5)
const myBike = new Bike('10 Speeder', myGear)
// Mutable Update
myGear.littleGear = 6
myBike.name = '12 Speeder'
// Immutable Update
const upgradedGear = Object.assign({}, myGear)
const upgradedBike = Object.assign({}, myBike, {gear: upgradedGear})
Haskell (Record Syntax)
-- Preamble
myGear = GearRatio 2 5
myBike = Bike "10 Speeder" myGear
-- Immutable Update
upgradedBike = myBike
{ _name = "12 Speeder"
, _gear = myGear { _littleGear = 6 }
}
Haskell (Lenses)
-- Preamble
import Control.Lens.TH
makeLenses ''Gear
makeLenses ''Bike
myGear = GearRatio 2 5
myBike = Bike "10 Speeder" myGear
-- Immutable Update
upgradedBike = myBike & name .~ "12 Speeder"
& gear.littleGear .~ 6

Branching

If...Else

TypeScript
TypeScript Ternary
Haskell
TypeScript
if (condition) {
branchA
} else {
branchB
}
TypeScript Ternary
condition ? branchA : branchB
Haskell
if condition
then branchA
else branchB

If...Else If...Else

TypeScript
Haskell
TypeScript
if (percent >= 90 || student.paidBribe) {
return GRADES.A
} else if (percent >= 75) {
return GRADES.B
} else if (percent >= 60) {
return GRADES.C
} else if (percent >= 50) {
return GRADES.D
} else {
return GRADES.F
}
Haskell
if | percent >= 90 || paidBribe student = A
| percent >= 75 = B
| percent >= 60 = C
| percent >= 50 = D
| otherwise = F

Switch/Case

TypeScript
Haskell
TypeScript
let nextAction
switch (lightState) {
case LIGHT.RED:
nextAction = ACTION.STOP
break
case LIGHT.YELLOW:
nextAction = ACTION.SLOW
break
case LIGHT.GREEN:
nextAction = ACTION.DRIVE
break
default:
nextAction = currentAction
}
Haskell
nextAction =
case lightState of
Red -> Stop
Yellow -> Slow
Green -> Drive
_ -> currentAction