Differences between revisions 1 and 19 (spanning 18 versions)
Revision 1 as of 2003-08-21 17:28:53
Size: 2687
Editor: host154
Comment:
Revision 19 as of 2006-08-19 00:33:28
Size: 8151
Editor: cache3-2
Comment: improved python, haskell and ctypes section with float conversion and others..
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
See also [LanguageComparisons].
Line 3: Line 5:
"real" projects (not just an experiment language) but is uncommon
in industry. More information can be found at http://www.haskell.org/.
"real" projects (not just an experiment language) but is uncommon but becoming
more common in industry. More information can be found at http://www.haskell.org/.
Line 15: Line 17:
Haskell is a true functional language, while Python offers tools for
a profusion of styles, including procedural and object-oriented. Python
Haskell is a lazy (evaluate by need), so-called pure functional (no assignments or side-effects) language. It supports parametric polymorphism (ala C++ templates, but more powerful), and ad-hoc polymorphism (e.g. operator overloading) through type classes (ala Java Interfaces). Python offers the programmer
a profusion of styles, including procedural, functional, and object-oriented. Lazy programming can be accomplished using generators and itertools. Python
Line 18: Line 20:
profusion of side effects and the lack of tail recursion (elimination
thereof), make it an awkward style to use in Python. A procedural style
is nearly impossible to use in Haskell.
profusion of side effects and the lack of built-in tail recursion optimization support, makes it an awkward style to use in Python. Haskell supports procedural programming through monads (from category theory) which are also Haskell's interface to the world of side effects (e.g. graphics, file systems, sockets, etc.). However, imperative programming is neither Haskell's intention nor strength (though this is debateable -- many Haskell coders have been known to state that Haskell is their favourite imperative language).
Line 23: Line 23:
Python is interpreted, while Haskell is compiled. The biggest
difference that this makes is in execution speed. Haskell is
surprisingly fast (surprising to those who think non-comercial languages
are necessarily slowpokes), while nearly all Python programmers suggest
that it's probably "fast enough", and that if it isn't, then the
critical sections should be re-written in C/C++.
Python's primary implementation is an interpreter. Haskell has a handful of
implementations, including some interpreters (hugs, ghci) and some native-code compilers (ghc, nhc98). Haskell is a high-level language like python, so
equal-to-C-or-asm performance should not be expected. The Haskell type system,
however, does provide more compile-time information than python's does, meaning
the optimizing native-code compilers have a speed advantage over python in
many cases.

The pythonic philosophy of dropping into C for critical sections applies
equally well to haskell. Through the foreign function interface, haskell
functions can call and be called from C code. As an alternative,
compiler-specific extensions (specifically, ghc's) and strictness annotations
can be used to get closer to the metal.
Line 31: Line 37:
Both Haskell and Python have strong (not weak) typing... instances
of a type can only be used as that type. But Haskell has static typing,
Both Haskell and Python have strong (not weak) typing, meaning instances
of a type cannot be cast into another type. Explicit conversions must be performed.
The difference is that Haskell has static typing,
Line 36: Line 43:
HAVE a type (the objects they refer to have types, but that isn't known
until runtime). Since typing is such a fundamental part of Haskell (it's
part of what makes the language easy to reason about), this difference
HAVE a type -- the objects they refer to have types, but that isn't known
until runtime, and objects can pretend to be different types by providing the correct functions, e.g. _ _ length _ _, etc. Since typing is such a fundamental part of Haskell (it's
part of what makes the language easy to reason about), this difference with Python
Line 40: Line 47:
think of typing "int i" before every variable use, take heart: Haskell
is often used as the example of "static typing done right", because it
has type inference... in most cases the compiler can figure out the type
for you, so declarations are ooptional, except where they carry actual
information.
think of typing "int i" before every variable use, take heart: Haskell's
compilers and interpreters are smart enough to infer the types of your
expressions almost all the time, so you don't have to type them. Type
inference is "static typing done right." For example, to assign a value of 5 to the identifier 'a', it's the exact same code in Python and Haskell:

{{{
a = 5
}}}

The fact that it's an integer is inferred by the Haskell compiler.
Line 53: Line 65:
=== Significant Whitespace: ===
Both use indentation as syntax. In Python, tabs/spaces ''are'' the syntax, whereas in Haskell, tabs/spaces are simply well-defined sugar for converting to the braces/semi-colon block syntax. Some would say that Haskell's way is an improvement on the idea of significant whitespace by allowing the optional use of explicit braces/semi-colons for blocks, saving certain amounts of headache, e.g. when copy-pasting from web-pages.

=== Learning Curve: ===
Haskell has a much steeper learning curve for programmers who are not used to
functional programming. In many cases, lazy evaluation seems counterintuitive
to an imperative-trained mind and you must unlearn techniques to prevent your
program from eating up memory.

For me (Nioate), learning [http://caml.inria.fr/ocaml/ OCaml] first smoothed the way into Haskell because ML
has a very similar (though less flexible) type system. After understanding the
type system, the jump to haskell is much less daunting: beyond new syntax, it
only involves learning to utilize lazy evaluation, type classes, and monads.
(Don't let monads scare you; learn about the list and Maybe monads first. The
[http://www.nomaware.com/monads/html/ tutorial at nomaware] is the best.)
Line 55: Line 83:
See also LanguageComparisons.
See also [LanguageComparisons].


== Using both Python & Haskell with ctypes (-; ==

Since, Python is the ultimate glue language (not counting Perl), these Python vs. XLang pages should be replaced with Python "and" XLang. This technique works for windows and ghc:

First a test haskell program (mylib.hs):

{{{
module Mylib where

import CString

adder :: Int -> Int -> IO Int
adder x y = return (x+y)

subtractor :: Float -> Float -> IO Float
subtractor x y = return (x - y)

fact :: Int -> Int
fact n =
    if n == 1 then 1 else (n * fact (n-1))

factorial :: Int -> IO Int
factorial n = return (fact n)


hello :: CString -> IO CString
hello w
 = do
   s <- peekCString w
   newCString (s ++ "World!")

mystring :: IO CString
mystring = newCString "hello world!"

foreign export stdcall adder :: Int -> Int -> IO Int
foreign export stdcall subtractor :: Float -> Float -> IO Float
foreign export stdcall factorial :: Int -> IO Int
foreign export stdcall hello :: CString -> IO CString
foreign export stdcall mystring :: IO CString
}}}

create file dllMain.c as entry point for the dll:

{{{
#include <windows.h>
#include <Rts.h>

extern void __stginit_Mylib(void);

static char* args[] = { "ghcDll", NULL };
                       /* N.B. argv arrays must end with NULL */
BOOL
STDCALL
DllMain
   ( HANDLE hModule
   , DWORD reason
   , void* reserved
   )
{
  if (reason == DLL_PROCESS_ATTACH) {
      /* By now, the RTS DLL should have been hoisted in, but we need to start it up. */
      startupHaskell(1, args, __stginit_Mylib);
      return TRUE;
  }
  return TRUE;
}


}}}


compile everything by running this batch file (build.bat):

{{{
REM test making haskell dll
ghc -c mylib.hs -fglasgow-exts
ghc -c dllMain.c
dlltool -A -z mylib.def mylib_stub.o --export-all-symbols
ghc --mk-dll -o mylib.dll mylib.o mylib_stub.o dllMain.o -optdll-def -optdll mylib.def

REM cleanup
rm mylib.o
rm mylib_stub.o
rm dllMain.o
rm mylib.hi
rm mylib_stub.c
rm mylib_stub.h
}}}

and then having installed ctypes, run the following python script (test_mylib.py) to test it:

{{{
from ctypes import *

lib = windll.mylib

api = {
    
# func name restype argtypes
    'adder' : (c_int, [c_int, c_int]),
    'subtractor': (c_float, [c_float, c_float]),
    'factorial' : (c_int, [c_int]),
    'hello' : (c_char_p, [c_char_p]),
    'mystring' : (c_char_p, []),
}
        

for func in api:
    f = getattr(lib, func)
    f.restype, f.argtypes = api[func]
    globals()[func] = f
    
print adder(1,2)
print subtractor(10.5, 2.5)
print factorial(10)
print hello('hello')
print mystring()
}}}

See also [LanguageComparisons].

Haskell

Haskell is a very modern functional language. It is used for some "real" projects (not just an experiment language) but is uncommon but becoming more common in industry. More information can be found at http://www.haskell.org/. (Please forgive or correct any errors here due to my not being very familiar with Haskell.)


Haskell and Python are a somewhat odd pair to compare, because they are so different in many ways. But what most users of both languages would agree they DO share is a certain elegance of design.

Functional vs Procedural:

Haskell is a lazy (evaluate by need), so-called pure functional (no assignments or side-effects) language. It supports parametric polymorphism (ala C++ templates, but more powerful), and ad-hoc polymorphism (e.g. operator overloading) through type classes (ala Java Interfaces). Python offers the programmer a profusion of styles, including procedural, functional, and object-oriented. Lazy programming can be accomplished using generators and itertools. Python has some support for a functional style of programming, but the profusion of side effects and the lack of built-in tail recursion optimization support, makes it an awkward style to use in Python. Haskell supports procedural programming through monads (from category theory) which are also Haskell's interface to the world of side effects (e.g. graphics, file systems, sockets, etc.). However, imperative programming is neither Haskell's intention nor strength (though this is debateable -- many Haskell coders have been known to state that Haskell is their favourite imperative language).

Compiled vs Interpreted:

Python's primary implementation is an interpreter. Haskell has a handful of implementations, including some interpreters (hugs, ghci) and some native-code compilers (ghc, nhc98). Haskell is a high-level language like python, so equal-to-C-or-asm performance should not be expected. The Haskell type system, however, does provide more compile-time information than python's does, meaning the optimizing native-code compilers have a speed advantage over python in many cases.

The pythonic philosophy of dropping into C for critical sections applies equally well to haskell. Through the foreign function interface, haskell functions can call and be called from C code. As an alternative, compiler-specific extensions (specifically, ghc's) and strictness annotations can be used to get closer to the metal.

Static vs Dynamic Typing:

Both Haskell and Python have strong (not weak) typing, meaning instances of a type cannot be cast into another type. Explicit conversions must be performed. The difference is that Haskell has static typing, while Python has dynamic typing. This means that in Haskell, the type of every expression and every variable is known at compile time (and strictly enforced), while in Python expressions and variables don't even HAVE a type -- the objects they refer to have types, but that isn't known until runtime, and objects can pretend to be different types by providing the correct functions, e.g. _ _ length _ _, etc. Since typing is such a fundamental part of Haskell (it's part of what makes the language easy to reason about), this difference with Python is a fundamental one. However, for those python users who shudder to think of typing "int i" before every variable use, take heart: Haskell's compilers and interpreters are smart enough to infer the types of your expressions almost all the time, so you don't have to type them. Type inference is "static typing done right." For example, to assign a value of 5 to the identifier 'a', it's the exact same code in Python and Haskell:

a = 5

The fact that it's an integer is inferred by the Haskell compiler.

There is also one similarity I feel compelled to point out:

List Comprehension Syntax:

Python's list comprehension syntax is taken (with trivial keyword/symbol modifications) directly from Haskell. The idea was just too good to pass up.

Significant Whitespace:

Both use indentation as syntax. In Python, tabs/spaces are the syntax, whereas in Haskell, tabs/spaces are simply well-defined sugar for converting to the braces/semi-colon block syntax. Some would say that Haskell's way is an improvement on the idea of significant whitespace by allowing the optional use of explicit braces/semi-colons for blocks, saving certain amounts of headache, e.g. when copy-pasting from web-pages.

Learning Curve:

Haskell has a much steeper learning curve for programmers who are not used to functional programming. In many cases, lazy evaluation seems counterintuitive to an imperative-trained mind and you must unlearn techniques to prevent your program from eating up memory.

For me (Nioate), learning [http://caml.inria.fr/ocaml/ OCaml] first smoothed the way into Haskell because ML has a very similar (though less flexible) type system. After understanding the type system, the jump to haskell is much less daunting: beyond new syntax, it only involves learning to utilize lazy evaluation, type classes, and monads. (Don't let monads scare you; learn about the list and Maybe monads first. The [http://www.nomaware.com/monads/html/ tutorial at nomaware] is the best.)

Contributors: MichaelChermside

See also [LanguageComparisons].

Using both Python & Haskell with ctypes (-;

Since, Python is the ultimate glue language (not counting Perl), these Python vs. XLang pages should be replaced with Python "and" XLang. This technique works for windows and ghc:

First a test haskell program (mylib.hs):

module Mylib where

import CString

adder :: Int -> Int -> IO Int
adder x y = return (x+y)

subtractor :: Float -> Float -> IO Float
subtractor x  y = return (x - y)

fact :: Int -> Int
fact n = 
    if n == 1 then 1 else (n * fact (n-1))

factorial :: Int -> IO Int
factorial n = return (fact n)


hello :: CString -> IO CString
hello w 
 = do
   s <- peekCString w       
   newCString (s ++ "World!")

mystring :: IO CString
mystring = newCString "hello world!"

foreign export stdcall adder :: Int -> Int -> IO Int
foreign export stdcall subtractor :: Float -> Float -> IO Float
foreign export stdcall factorial :: Int -> IO Int
foreign export stdcall hello :: CString -> IO CString
foreign export stdcall mystring :: IO CString

create file dllMain.c as entry point for the dll:

#include <windows.h>
#include <Rts.h>

extern void __stginit_Mylib(void);

static char* args[] = { "ghcDll", NULL };
                       /* N.B. argv arrays must end with NULL */
BOOL
STDCALL
DllMain
   ( HANDLE hModule
   , DWORD reason
   , void* reserved
   )
{
  if (reason == DLL_PROCESS_ATTACH) {
      /* By now, the RTS DLL should have been hoisted in, but we need to start it up. */
      startupHaskell(1, args, __stginit_Mylib);
      return TRUE;
  }
  return TRUE;
}

compile everything by running this batch file (build.bat):

REM test making haskell dll
ghc -c mylib.hs -fglasgow-exts
ghc -c dllMain.c
dlltool -A -z mylib.def mylib_stub.o --export-all-symbols
ghc --mk-dll -o mylib.dll mylib.o mylib_stub.o dllMain.o -optdll-def -optdll mylib.def 

REM cleanup
rm mylib.o
rm mylib_stub.o
rm dllMain.o
rm mylib.hi
rm mylib_stub.c
rm mylib_stub.h

and then having installed ctypes, run the following python script (test_mylib.py) to test it:

from ctypes import *

lib = windll.mylib

api = {
    
#   func name     restype    argtypes
    'adder'     : (c_int,    [c_int, c_int]),
    'subtractor': (c_float,  [c_float, c_float]),
    'factorial' : (c_int,    [c_int]),
    'hello'     : (c_char_p, [c_char_p]),
    'mystring'  : (c_char_p, []),
}
        

for func in api:
    f = getattr(lib, func)
    f.restype, f.argtypes  = api[func]
    globals()[func] = f
    
print adder(1,2)
print subtractor(10.5, 2.5)
print factorial(10)
print hello('hello')
print mystring()

PythonVsHaskell (last edited 2012-03-08 05:01:08 by 5ac434a8)

Unable to edit the page? See the FrontPage for instructions.