Nim for Haskell Programmers - nim-lang/Nim GitHub Wiki
| Feature | Haskell | Nim | 
|---|---|---|
| Comments | -- single line,{- multiline -}(nestable) | # single line,#[multiline]#(nestable) | 
| Blocks | Uses space and tab or C-like | Uses indents like Python, another option is statement list expression | 
| Operators | operator is function (use (+) a b, ora + b), Operator has precedence, infix by default, Unicode syntax | command call syntax unicode operators | 
| Operator overloading | None | Operators are user defined except =and., can overload: subscripts, curly subscriptsa{b}, experimental call and dot operators | 
| If/else statement | None | if a: foo() else: bar() | 
| If/else expression | if test then a else b | if test: a else: b | 
| case expression | case t of m1 -> a    otherwise -> b | case tof m1: aelse: b | 
| Exception | many ways, use Control.Monad, | try: foo() except Exception as ex: bar() finally: bar()- can omitas exorException as ex | 
| Procedure definition | id a = a,id::a->afor declare | proc foo(a: U, b: S): T = discardin module | 
| Method definition | None | method foo(obj: Obj, a: U, b: S): T = discardin module | 
| Calling procedure | func a b, or a `func` b | foo(a, b),foo a, b,a.foo(b),a.foo b | 
| Calling method | None | foo(obj, a, b),foo obj, a, b,obj.foo(a, b),obj.foo a, b | 
| Method/procedure declarations are order-agnostic | Yes | No, can use forward declarations, experimental code reordering | 
| String literals | "str" | "str","""str""",foo"str"(raw string literals) | 
| Collection literals | list comprehension [(a, b) | b <- ['a'..'z'], a <- [1..50], even a], Overloaded string and list | array [1, 2, 3], seq@[1, 2, 3], set{1, 2, 3}, tuple(1, 2, 3), table constructor | 
| compiler output | hiinterface file, native assembly or llvm | translate to C, C++, Objective C , JavaScript | 
| major compiler | ghc | nim | 
| major REPL | ghci | inim | 
| stability | old | young | 
| meta-programming | template-haskell | macrokeyword | 
| template | use {-# LANGUAGE CPP #-} | templatekeyword | 
| pure function | IO Monad | funckeyword ornoSideEffectpragma | 
Haskell is a pure functional language, variables are immutable.
However, you can use State Monad or IORef to get a mutable-like behaviour.
let behaves like create new immutable variable
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
  let smaller = quicksort [a | a<-xs, a<=x]
      bigger  = quicksort [a | a<-xs, a>x]
  in  smaller ++ [x] ++ biggerIn addition, where is the same
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = smaller ++ [x] ++ bigger
    where
       smaller = quicksort [a | a<-xs, a<=x]
       bigger  = quicksort [a | a<-xs, a>x]var for mutable
let for immutable
const for compile-time symbol
var mutable = "some"
mutable &= " string"
let shadow_copy = mutable
const flags = ["--run", "--hints:off"]Basic types present in Haskell and Nim:
| Haskell | Nim | 
|---|---|
| Int8 | int8 | 
| Int16 | int16 | 
| Int32 | int32 | 
| Int64 | int64 | 
| Word8 | uint8 | 
| Word16 | uint16 | 
| Word32 | uint32 | 
| Word64 | uint64 | 
| Double | float or float64 (same meaning) | 
| Float | float32 | 
| Ptr | pointer | 
| Bool | bool | 
Available only in Haskell:
| Haskell | meaning | 
|---|---|
| Integer | Arbitrary precision integers | 
| Ratio a | numerator and denominator in type a | 
| Rational | aka Ratio Integer | 
| Char | represent Unicode code points | 
| Complex a | real and image number in type a | 
| [a] | List with element in type a | 
| String | aka [Char] | 
Only in Nim:
| Nim | meaning | 
|---|---|
| char | 1 byte character | 
| string | mutable chars | 
| cstring | pointer to memory, const char* | 
| ptr[T] | untraced pointer | 
| ref[T] | traced pointer | 
| byte | aka uint8 | 
Nim has many additional types that enable the programmer to interface with C.
for Example: csize_t, cint, cshort
Both Haskell and Nim is static typed
Haskell's most widely used compiler (GHC) has strong type inference to determine what expression's type is
For example
Prelude> :t 25
25:: Num a => a
Prelude> add a b = a+b
Prelude> :t add
add :: Num a => a -> a -> a
Prelude> add 1 2
3
Prelude> add 1.0 2.0
3.0
Prelude> (add 1 2)::Int
3
Prelude> (add 1 2)::Integer
3
Prelude> (add 1 2)::Float
3.0
Prelude> (add 1 2)::Double
3.0The + function' signature is Num a => a -> a -> a, so add's parameter a and b must instance of Num.
Int, Integer, Float, Double are instances of Num type classes.
Use ::Type to tell explicitly the compiler the type of an expression.
Prelude> :{
Prelude| repr::(Show a)=>a->String
Prelude| repr a = "repr " ++ (show a)
Prelude| :}
Prelude> repr 23
"repr 23"
Prelude> repr [1..5]
"repr [1,2,3,4,5]"
Prelude> repr (return ()::IO ())
<interactive>:7:1: error:
    * No instance for (Show (IO ())) arising from a use of `repr'
    * In the expression: repr (return () :: IO ())
      In an equation for `it': it = repr (return () :: IO ())show's signature is Show a->String, we can say repr's parameter a must be an instance of the Show typeclass.
Prelude> a = []
Prelude> :t a
a :: [a]
Prelude> a ++ ['a'..'d']
"abcd"
Prelude> a ++ [1..5]
[1,2,3,4,5]a :: [a] means a can be any type
Nim doesn't accept any type,
var arr: seq[int]
for i in 0..5:
  arr.add i
echo $arrIn Haskell, you can pass an expression to a function, and it's un-evaluated.
If you have an infinite list, you can take the first five elements, and calculate the result.
main = do
    let a = [0..]::[Int]
    print $ take 5 aIn Nim, an expression will be evaluated and passed to a function, so to pass large data to a function, you can pass by a pointer.
List example
type List[T] = object
   data: T
   next: ref List[T]
func fromArray[T](a: openarray[T]): ref List[T] = 
   new(result)
   var tmp = result
   tmp[].data = a[0]
   for i in 1..<len(a):
      new(tmp[].next)
      tmp = tmp.next
      tmp[].data = a[i]
   tmp.next = nil
   return result
proc `$`[T](a: ref List[T]): string = 
   result = "["
   var tmp = a
   while true:
     result.add($ tmp.data)
     if tmp.next==nil:
        break
     result.add ", "
     tmp = tmp.next
   result.add "]"
let a = fromArray [12, 45, 27, 64, 1024, 4096]
echo a| Feature | Haskell | Nim | 
|---|---|---|
| IDE support | use Haskell Language Server, see | VS Code, see editor support | 
| Package manager | cabal, stack, ghc-pkg | Nimble | 
| Library format | hssource,hiinterface,oobject, see | Source code, unused code is not included in binary (dead code elimination), can also compile to a shared library or static library | 
| Style guide | see | NEP-1 | 
| Doc generator | haddock | nim doc,nim rst2html,nim tex,nim jsondoc,nim doc2tex | 
| Unit testing | HTF QuickCheck HUnit | Standard library unittest module | 
Haskell
main = do
  print "enter your name"
  a <- getLine
  print $ "hello " ++ acompile
ghc Main.hs
./Main 
# or runghc Main.hsNim
echo "enter your name"
let a = stdin.readLine()
echo "hello " & acompile
nim c Main.nim
./Main
# or nim c --run Main.nimHaskell
case expression
case (parse "<string>" number "45") of (Right x) -> x
                                       (Left err) -> print err >> fail "parse error"pattern matching
fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fibs::[Integer]
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
main = print $ take 10 fibsNim
var 
  a = 0
  b = 0
  res: int
let s = "+"
case s:
of "+": res = a + b 
of "-": res = a - b
else: res = -1Haskell
data Value = IVal Integer | FVal Double deriving (Show, Eq)
data Expr
  = Var String
  | Lit Value
  | App Expr Expr
  | Lam String Expr
  deriving (Eq, Show)Nim
type 
  ExprKind = enum
    Var, Lit, Lam, App
  Expr = ref object
    case kind: ExprKind
    of Var:
      name: string
    of Lit:
      val: float
    of App:
      a, b: Expr
    of Lam:
      n: string
      e: Expr
func eval(e: Expr): Expr = 
   case e.kind:
   of Var: ...{-# LANGUAGE Unsafe #-} -- since Unsafe.Coerce is unsafe, use LANGUAGE pragma to mark this module unsafe
module Main (hello) where -- expose hello function
import Unsafe.Coerce -- expose all symbols
import qualified Control.Monad.Writer as W -- W is the new name
import Data.ByteString hiding (putStrLn) -- readFile is not visible
import Data.Semigroup ((<>), Semigroup) -- import (<>) function and Semigroup typeclass
hello::String -- hello is type String, aka [Char]
{-# INLINABLE hello #-} -- tell ghc hello is inlinable
hello = "Hello "<>"world" -- the function body
main::IO () -- main is the entry point of the program, main is an empty tuple inside the IO Monad
main = putStrLn hello -- call putStrLn
{-
  {-
    multi-line comment
  -}
-}Nim
import System # exposes all symbols
import System as S # S W is the new name
from System import create # import create
import System except int # import all symbols except int
import system as S except int # S is the new name, int is not imported
# hello is a procedure, return some string
proc hello(): string {.inline.} = "hello " & "world"
# three ways to call
# they are the same
echo hello()
hello().echo
echo(hello())
#[
  #[
       multi-line comment
  ]#
]#
var mutable = "Win32"
mutable &= "API"
let immutable = ["Nim", "PlayGround", "C"]
const compileTime = 2 shl 1024
echo $mutable, $immutable, $compileTimeHaskell
{-# LANGUAGE CPP #-}
#define bind(a, f) a <- f
#define COUNT 5
main::IO ()
main = do
  putStrLn "enter a number->"
  bind(s, getLine)
  bind(num, readIO s)::IO Integer
  print $ scanl (+) 0 (take COUNT $ repeat num)nim
template curry(a, b, c) = 
  a (b, c)
curry(echo, 1, 2)Haskell
Macro.hs
{-# LANGUAGE TemplateHaskell #-}
module Macro
  ( duplicate )
where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
duplicate :: String -> Q Exp
duplicate s = do
  [| fromString s++s |]Main.hs
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Macro
main :: IO ()
main = putStrLn $(duplicate "<>")Nim
import macros
macro readContent(path: static[string]): untyped = 
  let c = staticRead path
  result = newLit c
stdout.write readContent("Main.nim")Haskell
module Main where
import Prelude hiding (sin)
import Foreign.C.Types
-- stdcall in windows
foreign import ccall "math.h sin"
    sin::CDouble->CDouble
main = print $ map sin (take 50 (scanl (+) 0 (repeat 0.001)))Nim
proc sin(a: cdouble): cdouble {.importc, header: "math.h", nodecl.}
var i = 0.cdouble
while i < 0.05:
  echo sin(i)
  i += 0.001