A quick reference comparison for syntax and features between languages. Github
Comments
-- This is a comment
-- This is a comment
-- This is a comment
# This is a comment
Primitives
1 : Int
1.1 : Float
True : Bool
False : Bool
'c' : Char
"hello" : String
-- multi-line String
"""
This is useful for holding JSON or other
content that has "quotation marks".
"""
(1,'c') : (Int, Char)
Just 123 : Maybe Int
Nothing : Maybe a
Ok 123 : Result err Int
Err "Problem!" : Result String a
[ 1, 2, 3 ] : List Int
Array.fromList [ 1, 2, 3] : Array Int
Set.fromList [1, 2, 3] : Set Int
x : Dict Int Bool
x = Dict.fromList [ ( 1 , True ), ( 2, False ) ]
-- Unit type
() : ()
1 : Int
1.1 : Float
True : Bool
False : Bool
'c' : Char
"hello" : String
-- multi-line String
"""
This is useful for holding JSON or other
content that has "quotation marks".
"""
-- gren does not have tuples
Just 123 : Maybe Int
Nothing : Maybe a
Ok 123 : Result err Int
Err "Problem!" : Result String a
-- gren does not have a list type
[ 1, 2, 3 ] : Array Int
Set.fromArray [1, 2, 3] : Set Int
x : Dict Int Bool
x =
Dict.empty
|> Dict.set 1 True
|> Dict.set 2 False
-- Unit type
{} : {}
1 :: Int
1.1 :: Float
True :: Bool
False :: Bool
'c' :: Char
"hello" :: String
-- Requires raw-strings-qq package
{-# LANGUAGE QuasiQuotes #-}
import Text.RawString.QQ
[r|
This is useful for holding JSON or other
content that has "quotation marks".
|]
(1,'c') :: (Int, Char)
Just 123 :: Maybe Int
Nothing :: Maybe a
Right 123 :: Either err Int
Left "Problem!" :: Either String a
[1,2,3] :: [Int] -- Note: type List a = [a]
import qualified Data.Vector as Vector
Vector.fromList [1,2,3] :: Vector Int
import qualified Data.Set as Set
Set.fromList [1,2,3] : Set Int
import qualified Data.Map as Map
x :: Map Int Bool
x = Map.fromList [(1,True), (2, False)]
-- Unit type
() :: ()
1 : I32
1.1 : F64
True : Bool
False : Bool
'c' : U8
"hello" : Str
# multi-line String
"""
This is useful for holding JSON or other
content that has "quotation marks".
"""
# Roc does not have tuple syntax
# or a built-in Maybe type
Ok 123 : Result I32 *
Err "Problem!" : Result * Str
[ 1, 2, 3 ] : List I32
# Roc does not have an Array type,
# but List is implemented using
# a flat array instead of a linked list
[: 1, 2, 3 :] : Set Int
x : Dict I32 Bool
x = {: 1 => True, 2 => False :}
-- Unit type
{} : {}
Custom types
Note: Custom types are sometimes called tagged unions. Some communities call them ADTs.
type Status = Todo | Doing | Done
Todo : Status
Doing : Status
Done : Status
type Status = Todo | Doing | Done
Todo : Status
Doing : Status
Done : Status
data Status = Todo | Doing | Done
Todo :: Status
Doing :: Status
Done :: Status
Status : [ Todo, Doing, Done ]
Todo : Status
Doing : Status
Done : Status
Custom types can be polymorphic. Maybe a
is an example:
type Maybe a = Just a | Nothing
Just 123 : Maybe Int
Nothing : Maybe a
type Maybe a = Just a | Nothing
Just 123 : Maybe Int
Nothing : Maybe a
data Maybe a = Just a | Nothing
Just 123 :: Maybe Int
Nothing :: Maybe a
Maybe a : [ Just a, Nothing ]
Just 123 : Maybe Int
Nothing : Maybe *
Records
point = -- create a record
{ x = 3, y = 4 }
point.x -- access field
List.map .x [ point, { x = 0, y = 0 } ] -- field access function
{ point | x = 6 } -- update a field
{ point -- update many fields
| x = point.x + 1
, y = point.y + 1
}
dist { x, y } = -- pattern matching on fields
sqrt (x ^ 2 + y ^ 2)
type alias Location = -- type aliases for records
{ line : Int
, column : Int
}
point = -- create a record
{ x = 3, y = 4 }
point.x -- access field
Array.map .x [ point, { x = 0, y = 0 } ] -- field access function
{ point | x = 6 } -- update a field
{ point -- update many fields
| x = point.x + 1
, y = point.y + 1
}
dist { x, y } = -- pattern matching on fields
sqrt (x ^ 2 + y ^ 2)
type alias Location = -- type aliases for records
{ line : Int
, column : Int
}
-- Haskell has no anonymous records
x point
fmap x [point,point]
point { x = 6 }
point
{ x = (x point) + 1
, y = (y point) + 1
}
dist Point{..} = -- Requires RecordWildCards
sqrt (x^2 + y^2)
data Location =
Location
{ line : Int
, column : Int
}
point =
{ x: 3, y: 4 }
point.x
List.map [ point, { x: 0, y: 0 } ] .x
{ point & x: 6 }
{
point &
x: point.x + 1,
y: point.y + 1,
}
dist = \{ x, y } ->
sqrt (x ^ 2 + y ^ 2)
Location :
{
line : I32,
column : I32,
}
Functions
addOne : Int -> Int
addOne x = x + 1
add : Int -> Int -> Int
add x y = x + y
add : Int -> Int -> Int
add = (+)
poly : a -> Int
poly x = 14
addOne : Int -> Int
addOne x = x + 1
add : Int -> Int -> Int
add x y = x + y
add : Int -> Int -> Int
add = (+)
poly : a -> Int
poly x = 14
addOne :: Int -> Int
addOne x = x + 1
add :: Int -> Int -> Int
add x y = x + y
add :: Int -> Int -> Int
add = (+)
poly :: a -> Int
poly x = 14
addOne : I32 -> I32
addOne = \x -> x + 1
add : I32, I32 -> I32
add = \x, y -> x + y
add : I32, I32 -> I32
add = Num.add
# Roc does not have (+) syntax for operators;
# instead, operators desugar to
# plain function calls like Num.add
poly : * -> I32
poly = \x -> 14
Anonymous Functions
square =
\n -> n ^ 2
squares =
List.map (\n -> n ^ 2) (List.range 1 100)
square =
\n -> n ^ 2
squares =
Array.map (\n -> n ^ 2) (Array.range 1 100)
square =
\n -> n ^ 2
squares =
fmap (\n -> n ^ 2) [1..100]
square = \n ->
n ^ 2
squares =
List.map (List.range 1 100) \n -> n ^ 2
Function application & composition
All the following are equivalent.
viewNames names =
String.join ", " (List.sort names)
viewNames names =
String.join ", " <| List.sort names
viewNames names =
names
|> List.sort
|> String.join ", "
viewNames =
String.join ", " << List.sort
viewNames =
List.sort >> String.join ", "
viewNames names =
String.join ", " (Array.sort names)
viewNames names =
String.join ", " <| Array.sort names
viewNames names =
names
|> Array.sort
|> String.join ", "
viewNames =
String.join ", " << Array.sort
viewNames =
Array.sort >> String.join ", "
import qualified Data.List as List
import Data.Function ((&))
import Control.Arrow ((>>>))
viewNames names =
List.intercalate ", " (List.sort names)
viewNames names =
List.intercalate ", " $ List.sort names
viewNames names =
names
& List.sort
& (List.intercalate ", ")
viewNames =
List.intercalate ", " . List.sort
viewNames =
List.sort . List.intercalate ", "
viewNames = \names ->
Str.join (List.sort names Str.alphabetical) ", "
# Roc does not have an equivalent of
# the `<|` operator.
viewNames = \names ->
names
|> List.sort Str.alphabetical
|> Str.join ", "
# Roc does not have an equivalent of
# the `<<` operator
# or the `>>` operator.
Conditionals
if power > 9000 then "Wow!" else "Meh"
if key == 40 then
n + 1
else if key == 38 then
n - 1
else
n
if power > 9000 then "Wow!" else "Meh"
if key == 40 then
n + 1
else if key == 38 then
n - 1
else
n
if power > 9000 then "Wow!" else "Meh"
if key == 40 then
n + 1
else if key == 38 then
n - 1
else
n
if power > 9000 then "Wow!" else "Meh"
if key == 40 then
n + 1
else if key == 38 then
n - 1
else
n
Pattern matching
case maybe of
Just xs -> xs
Nothing -> []
case xs of
hd::tl -> Just (hd,tl)
[] -> Nothing
fib n =
case n of
0 -> 1
1 -> 1
_ -> fib (n-1) + fib (n-2)
case maybe of
Just xs -> xs
Nothing -> []
-- Gren does not have a cons (::) operator.
case args of
[] -> "No arguments provided"
[ "greet", name ] -> "Hello, " ++ name
_ -> "Unrecognized arguments"
fib n =
case n of
0 -> 1
1 -> 1
_ -> fib (n-1) + fib (n-2)
case maybe of
Just xs -> xs
Nothing -> []
case xs of
hd:tl -> Just (hd,tl)
[] -> Nothing
fib n =
case n of
0 -> 1
1 -> 1
_ -> fib (n-1) + fib (n-2)
when maybe is
Just xs -> xs
Nothing -> []
# Roc does not have special
# pattern matching syntax for lists
fib = \n ->
when n is
0 -> 1
1 -> 1
_ -> fib (n - 1) + fib (n - 2)
Let expressions
functionWithLetDecs =
let
( three, four ) =
( 3, 4 )
hypotenuse a b =
sqrt (a^2 + b^2)
in
hypotenuse three four
functionWithLetDecs =
let
{ three, four } =
{ three = 3, four = 4 }
hypotenuse a b =
sqrt (a^2 + b^2)
in
hypotenuse three four
functionWithLetDecs =
let
( three, four ) =
( 3, 4 )
hypotenuse a b =
sqrt (a^2 + b^2)
in
hypotenuse three four
functionWithLetDecs =
Pair three four =
Pair 3 4
hypotenuse = \a, b ->
Num.sqrt (a ^ 2 + b ^ 2)
hypotenuse three four
# No let/in required, indentation sensitive
Modules
module MyModule exposing (..)
-- qualified imports
import List -- List.map, List.foldl
import List as L -- L.map, L.foldl
-- open imports
import List exposing (..) -- map, foldl, concat, ...
import List exposing ( map, foldl ) -- map, foldl
import Maybe exposing ( Maybe ) -- Maybe
import Maybe exposing ( Maybe(..) ) -- Maybe, Just, Nothing
module MyModule exposing (..)
-- qualified imports
import Array -- Array.map, Array.foldl
import Array as A -- A.map, A.foldl
-- open imports
import Array exposing (..) -- map, foldl, concat, ...
import Array exposing ( map, foldl ) -- map, foldl
import Maybe exposing ( Maybe ) -- Maybe
import Maybe exposing ( Maybe(..) ) -- Maybe, Just, Nothing
module MyModule where
-- qualified imports
import qualified List -- List.map, List.foldl
import qualified List as L -- L.map, L.foldl
-- open imports
import List -- map, foldl, concat, ...
import List ( map, foldl ) -- map, foldl
import Maybe ( Maybe ) -- Maybe
import Maybe ( Maybe(..) ) -- Maybe, Just, Nothing
interface MyModule
# Roc has no "expose everything" syntax
exposes [ foo, blah ]
imports
[
# Qualified imports
List as L, # L.map, L.walk
# Open imports (Roc has no "expose everything" syntax)
List.{ map, walk },
# Imports the Result module and also the Result type
Result.{ Result },
]
Type Annotations
answer : Int
answer =
42
factorial : Int -> Int
factorial n =
List.product (List.range 1 n)
distance : { x : Float, y : Float } -> Float
distance {x,y} =
sqrt (x^2 + y^2)
answer : Int
answer =
42
factorial : Int -> Int
factorial n =
Array.foldl (*) 1 (Array.range 1 n)
distance : { x : Float, y : Float } -> Float
distance {x,y} =
sqrt (x^2 + y^2)
answer :: Int
answer =
42
factorial :: Int -> Int
factorial n =
List.product (List.range 1 n)
-- Haskell has no anonymous records
data Point = Point { x :: Float, y :: Float }
distance :: Point -> Float
distance Point{..} = -- Requires RecordWildCards
sqrt (x^2 + y^2)
answer : I32
answer =
42
factorial : I32 -> I32
factorial = \n ->
List.product (List.range 1 n)
distance : { x : F64, y : F64 } -> F64
distance = \{ x, y } ->
Num.sqrt (x ^ 2 + y ^ 2)
Type Aliases
type alias Name = String
type alias Age = Int
info : (Name, Age)
info =
("Steve", 28)
type alias Point = { x : Float, y : Float }
origin : Point
origin =
{ x = 0, y = 0 }
type alias Name = String
type alias Age = Int
info : { name : Name, age : Age }
info =
{ name = "Steve", age = 28 }
type alias Point = { x : Float, y : Float }
origin : Point
origin =
{ x = 0, y = 0 }
type Name = String
type Age = Int
info :: (Name, Age)
info =
("Steve", 28)
data Point = Point { x :: Float, y :: Float }
origin :: Point
origin =
Point { x = 0, y = 0 }
Name : Str
Age : I32
info : [ Pair Name Age ]*
info =
Pair "Steve" 28
Point : { x : F64, y : F64 }
origin : Point
origin =
{ x: 0, y: 0 }
String interpolation
In all cases `toEuros` must return a string.
-- None, use concatenation
costOnSale money =
"It cost " ++ toEuros money ++ " when on sale."
-- Alternatively, poor man's interpolation
costOnSale money =
"It cost $euros when on sale."
|> String.replace "$euros" (toEuros money)
-- None, use concatenation
costOnSale money =
"It cost " ++ toEuros money ++ " when on sale."
-- None, use concatenation
costOnSale money =
"It cost " ++ toEuros money ++ " when on sale."
-- Alternatively, with a QuasiQuotes package
{-# LANGUAGE QuasiQuotes #-}
import NeatInterpolation
costOnSale money =
let
euros = toEuros money
in
[text|
It cost ${euros} when on sale.
|]
costOnSale = \money ->
euros = toEuros money
"It cost \(euros) when on sale."