You can program functionally in Python. It doesn't really gets in way of doing that, which cannot be said about functional languages, they are often designed to prevent you programming imperatively.
Dynamically typed languages can be understood as having only one type, so it's in a sense a type system that encompasses all the other type systems. For fans of typing, Python added optional type annotations, again, as a very conservative choice.
Interpreted - again, it's probably easier to write interpreter than compiler. Once you get into compiling, you have to make some more choices, which Python conservatively forfeits.
That is not to say that these choices aren't cultural (for example, most people are more familiar with infix notation, although even here there may be pragmatic reasons - the exactly right amount of parentheses). Just that it tries to encompass various tastes and be conservative about it.
It's not easier. Interpreters are much more complex and much less robust than compilers.
Don't do it. Compile into a higher level representation and reuse and existing machine code generator (LLVM, even plain C), or compile into a higher level VM with threaded code implementation (Forth and alike). Although even a full compiler with a native codegen is still much simpler than an interpreter.
> 2) optimizations scare me every time
As if you don't have to optimise in an interpreter. Not to mention that even an unoptimised compiler would produce much faster code than your average "easy" interpreter.
Compilation is nothing but a sequence of trivial term rewriting passes. Each can be as simple as you want, doing one trivial thing at a time. Easy to understand, easy to write in a fully declarative way, easy to reason about, easy to debug and maintain. You don't even need a Turing-complete language to do it.
And an interpreter is always a pile of convoluted mess, leaking multiple abstractions in between layers (if you're lucky enough to even get any distinct layers at all). I always wondered how people can even compare interpreters to compilers.
What makes you think interpreters are more complex?
Still far too complex, and, what is worse, very convoluted. You cannot split such an interpreter into series of very small and easy to understand steps, it must do everything at once, in a single huge recursive visitor. Compare it to a simple compiler which will rewrite one distinct aspect of a language at a time.
Another awful property of interpreters is that you can't strip them away from the runtime, it must be woven into all the parts of the interpreter and cannot be abstracted away. While compiler can be isolated from all the runtime issues which should be implemented separately (or simply reused).
Fast? No, but it will be faster than that direct interpreter (some Basics of the '80s scanned a linked list to find target lines of goto's and gosub's. If you manage to get rid of that, tight loop can get a lot faster soon)
Python doesn't even have closures.
> Interpreted
Languages are neither interpreted nor compiled. Implementations are.
So what's this?
>>> x = 1
>>> def f(y): return y + x
...
>>> f(2)
3
EDIT: Note that my example works even if the definition of x and f appear within the definition of another function. If closed-over variables must be mutable then Haskell doesn't have closures!More over here - http://stackoverflow.com/a/23558809/171450
I.e.,
Python 3.4.3 (default, Apr 7 2015, 08:05:21)
>>> def mk_generator(initial):
... var = initial
... def increment(count=1):
... nonlocal var
... var += count
... return var
... return increment
...
>>> a = mk_generator(3)
>>> b = mk_generator(10)
>>> a(1)
4
>>> b
<function mk_generator.<locals>.increment at 0x1040a7d08>
>>> b()
11
>>> b()
12
>>> a(3)
7Closures define the set of variables whose lifetime extends the function they are in because of their use in another function.
For instance:
;; Function that returns a function that counts even numbers
(define (even)
(let ((x 0))
(lambda () (set! x (+ x 2)) x)))
(define count (even))
(count) ; → 2
(count) ; → 4
In Python: def even():
x = 0
def add():
x += 2
return x
return add
count = even()
count() # → UnboundLocalError: local variable 'x' referenced before assignment
That said, Python does support a less convenient style of closures — it works if the variable is a container (such as a list, a dictionary or an object). def add_double(n):
x = n * 2
def add(y):
return x + y
return add
f = add_double(1)
f(2) # -> 4
What python versions prior to 3 didn't support is rebinding a variable from an enclosing scope; not because of any fundamental feature of the implementation, but because there was no syntactic way to differentiate between a assigning to a variable in an enclosing scope, and creating a variable in the current scope. So x += 2 is short for x = x + 2, which python interprets as creating a new variable x in the current scope and then trying to access that variable before it's been assigned.Python 3 introduced a syntax to specify that you wanted to assign to a variable from an enclosing scope, the 'nonlocal' keyword. So your example would be:
def even():
x = 0
def add():
nonlocal x
x += 2
return x
return add
count = even()
count() # → 2
count() # → 4 #include <stdio.h>
int x = 1;
int f(int y) {
return x + y;
}
int
main(argv, argc) {
printf("f(2): %i\n", f(2));
}
The reason they are called closures is because they close over the, lexical, environment where the function was defined.Python doesn't have lexical scope, hence it doesn't have closures.
Can you explain why https://en.wikipedia.org/wiki/Python_syntax_and_semantics#Cl... says:
> Python has had support for lexical closures since version 2.2. ... Python's syntax, though, sometimes leads programmers of other languages to think that closures are not supported. Variable scope in Python is implicitly determined by the scope in which one assigns a value to the variable, unless scope is explicitly declared with global or nonlocal.
?
The usual reason people give for believing this is the inability to mutate closed-over variables.
If that's the case, then a strictly-immutable FP language similarly "wouldn't have closures" and thus could not be FP. Problem solved!
def some_function(val):
def say_stuff():
print("message is: {}".format(val))
def mutate_me(new_mutation):
nonlocal val
val = new_mutation
say_stuff.mutate_me = mutate_me
return say_stuff
if __name__ == '__main__': f = some_function("hello")
f.mutate_me("goodbye")
f()