-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Nim for Haskell Programmers
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 , or a + 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 subscripts a{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 t of m1: a else: b
|
Exception |
many ways, use Control.Monad , |
try: foo() except Exception as ex: bar() finally: bar() - can omit as ex or Exception as ex
|
Procedure definition |
id a = a , id::a->a for declare |
proc foo(a: U, b: S): T = discard in module |
Method definition | None |
method foo(obj: Obj, a: U, b: S): T = discard in 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 |
compiler output |
hi interface file, native assembly or llvm |
translate to C, C++, Objective C , JavaScript |
major compiler | ghc | nim |
major REPL | ghci | nim secret |
stability | old | young |
meta-programming | template-haskell |
macro keyword |
template | use {-# LANGUAGE CPP #-}
|
template keyword |
pure function | IO Monad |
func keyword or noSideEffect pragma |
Haskell is pure functional language, variables are immutable
However, you can use State Monad or IORef to behave like mutable
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] ++ bigger
In 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"]
Haskell and Nim
Haskell | Nim |
---|---|
Int8 | int8 |
Int16 | int16 |
Int32 | int32 |
Int64 | int64 |
Word8 | uint8 |
Word16 | uint16 |
Word32 | uint32 |
Word64 | uint64 |
Ptr | pointer |
Bool | bool |
Only Haskell
Haskell | meaning |
---|---|
Integer | Arbitrary precision integers |
Double | Double-precision floating point numbers |
Float | Single-precision floating point numbers |
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 Nim
Nim | meaning |
---|---|
char | 1 byte character |
string | mutable chars |
cstring | pointer to memory, const char*
|
float | float number |
float32 | 32 bit float |
float64 | 64 bit float |
ptr[T] |
untraced pointer |
ref[T] |
traced pointer |
byte | aka uint8 |
Nim has many type to interfacing 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.0
the +
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 class
use ::Type
to explicit tell the compiler the type of 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 instance of 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 don't accept any type,
var arr: seq[int]
for i in 0..5:
arr.add i
echo $arr
Feature | Haskell | Nim |
---|---|---|
IDE support | use Haskell Language Server, see | VS Code, see editor support |
Package manager | cabal, stack, ghc-pkg | Nimble |
Library format |
hs source, hi interface, o object, 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 " ++ a
compile
ghc Main.hs
./Main
# or runghc Main.hs
Nim
echo "enter your name"
let a = stdin.readLine()
echo "hello " & a
compile
nim c Main.nim
./Main
# or nim c --run Main.nim
Haskell
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 fibs
Nim
var
a = 0
b = 0
res: int
let s = "+"
case s:
of "+": res = a + b
of "-": res = a - b
else: res = -1
Haskell
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 inlineable
hello = "Hello "<>"world" -- the function body
main::IO () -- main is entry point of program, main is a empty tuple inside the IO Monad
main = putStrLn hello -- call putStrLn
{-
{-
multi line comment
-}
-}
Nim
import System # expose 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, $compileTime
Haskell
{-# 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
Intro
Getting Started
- Install
- Docs
- Curated Packages
- Editor Support
- Unofficial FAQ
- Nim for C programmers
- Nim for Python programmers
- Nim for TypeScript programmers
- Nim for D programmers
- Nim for Java programmers
- Nim for Haskell programmers
Developing
- Build
- Contribute
- Creating a release
- Compiler module reference
- Consts defined by the compiler
- Debugging the compiler
- GitHub Actions/Travis CI/Circle CI/Appveyor
- GitLab CI setup
- Standard library and the JavaScript backend
Misc