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."