News for hackers. Stuff that matters.
Re:Functional Python Programming by raphaelj on Friday June 09, 2023 @10:15AM (#36258125)
Sadly, Python is a pretty poor functional language.

The core of functional programming is about avoiding mutable states, not much about anonymous functions or passing functions as data.

To do proper functional programming in Python, there should be IMO:

- a way to enforce non-mutable variables/objects;

- non-mutable collections;

- proper support for recursion and tail-recursion optimization;

- a better syntax for anonymous functions than single statement lambdas.

Generators are nice, but do not have much to do with functional programming.

Re:Functional Python Programming by linkdd on Friday June 09, 2023 @10:29AM (#36258340)
For tail recursion, you can use this snippet of code:

  class Recurse(Exception):
      def __init__(self, *args, **kwargs):
          self.args = args
          self.kwargs = kwargs
  
  class Terminate(Exception):
      def __init__(self, retval):
          self.retval = retval

  def tailrec(func):
      def wrapper(*args, **kwargs):
          while True:
              try:
                  func(*args, **kwargs)

              except Recurse as r:
                  args = r.args
                  kwargs = r.kwargs

              except Terminate as t:
                  return t.retval

      return wrapper

  @tailrec
  def fact(n, acc=1):
      if n == 0:
          raise Terminate(acc)

      else:
          raise Recurse(n - 1, acc * n)
Of course, it will be slow because it relies on exceptions :P
Re:Functional Python Programming by _aavaa_ on Friday June 09, 2023 @12:56PM (#36260670)
You can do a similar thing (that's around 2-3x faster) with a trampoline:

  def factorial(n):
      res = fac(n)
      while callable(res):
          res = res()

      return res

  def fac(n, acc=1):
      if n == 1:
          return acc
      else:
          return lambda: fac(n-1, n*acc)
Re:Functional Python Programming by qbasic_forever on Friday June 09, 2023 @10:22AM (#36258230)
I agree but it's not so dire, the tuple type (and variants like namedtuple) is pretty powerful, non-mutable and often my first choice for data structure in python. Everything else can be built on top of it if you're really motivated.
Re:Functional Python Programming by amanj41 on Friday June 09, 2023 @10:39AM (#36258513)
I would add frozenset as the other immutable collection. The other points are well taken though
Re:Functional Python Programming by odyssey7 on Friday June 09, 2023 @10:48AM (#36258664)
Agreed, Python is designed for something other than functional programming, so a functional programming enthusiast would get better mileage out of something else. Even if you were to write all of your Python programs against the grain in a functional style, you'd still need to operate in a community of modules that don't provide referential transparency.
Re:Functional Python Programming by theLiminator on Friday June 09, 2023 @04:33PM (#36263794)
Even worse when some modules have global mutable state like matplotlib and co.
Re:Functional Python Programming by tayo42 on Friday June 09, 2023 @11:01AM (#36258861)
Why do you consider anonymous functions so important? Regular functions can be used the same way?
Re:Functional Python Programming by sodapopcan on Friday June 09, 2023 @11:17AM (#36259113)
OP said anonymous functions are NOT as important as immutable data.
Re:Functional Python Programming by tayo42 on Friday June 09, 2023 @11:21AM (#36259182)
its in the list they provided of improvements python needs...
Re:Functional Python Programming by sodapopcan on Friday June 09, 2023 @11:30AM (#36259320)
Oh... either that was added in an edit or I had a brain blip that caused me to skip the bulleted list. Apologies.
Re:Functional Python Programming by profunctor on Friday June 09, 2023 @11:25AM (#36259246)
It's not a list of improvements python needs. It's a list of things python already does / has.
Re:Functional Python Programming by tayo42 on Friday June 09, 2023 @11:27AM (#36259277)
do I have bots responding to me? whats hard about comprehending this?

> To do proper functional programming in Python, there should be IMO:

> ...

> - a better syntax for anonymous functions than single statement lambdas.

Re:Functional Python Programming by gnufx on Friday June 09, 2023 @11:24AM (#36259231)
You want tail call optimization, not just tail-recursion, i.e. mutually recursive functions.
Re:Functional Python Programming by carapace on Friday June 09, 2023 @03:01PM (#36262467)
Syntactically maybe, but I find it has a quite workable functional subset.

Integers, floats, tuples, named tuples, and frozensets are all immutable, functions are values, etc. E.g.: https://joypy.osdn.io/notebooks/Derivatives_of_Regular_Expre... -or- https://github.com/calroc/xerblin/blob/master/xerblin/btree....

It's not fantastic, but it's not that bad.

Re:Functional Python Programming by gnulinux on Friday June 09, 2023 @04:20PM (#36263627)
I love both python and functional programming and I do write functional style python routinely. One barrier I hit is there is no immutable dict type. There is MappingProxyType but it's insufficient. I prefer using custom dataclass like objects built with pydantic and type checked with mypy. It's better than dict and can be made immutable but requires tons of boilerplate code which is a bit unpythonic.
Re:Functional Python Programming by carapace on Friday June 09, 2023 @04:54PM (#36264048)
> there is no immutable dict type

Does the namedtuple not suffice? Apologies if I'm being dense.

- - - -

It's not an immutable dict type (for one thing, this has linear lookup, the BTree would be better) but it's fun:

https://stackoverflow.com/questions/13708701/how-to-implemen...

In Python:

    from functools import partial

    def empty_dict(key):
        raise KeyError

    def _dict_add(dictionary, key, value, lookup):
        return value if key == lookup else dictionary(lookup)

    def dict_add(d, key, value):
        return partial(_dict_add, d, key, value)


    d = empty_dict
    d = dict_add(d, 'key0', 23)
    d = dict_add(d, 'key1', 18)

And then...

    >>> d('key0')
    23
    >>> d('key1')
    18
    >>> d('keyn')
    Traceback (most recent call last):
      File "<pyshell#8>", line 1, in <module>
        d('keyn')
      File "/usr/home/sforman/tmp_fn_dict.py", line 7, in _dict_add
        return value if key == lookup else dictionary(lookup)
      File "/usr/home/sforman/tmp_fn_dict.py", line 7, in _dict_add
        return value if key == lookup else dictionary(lookup)
      File "/usr/home/sforman/tmp_fn_dict.py", line 4, in empty_dict
        raise KeyError
    KeyError


- - - -

> objects built with pydantic and type checked with mypy

FWIW, after ~15 years of professional Python development, I'm not into types [in Python]. My attitude is that if you really need them you should switch to e.g. OCaml or something that does them right. I love Python but I wouldn't use it anymore for anything other than scripts and maybe prototyping.

Re:Functional Python Programming by gnulinux on Friday June 09, 2023 @07:01PM (#36265490)
> My attitude is that if you really need them you should switch to e.g. OCaml or something that does them right.

I strongly disagree. I personally think there is no programming problem where types aren't useful. When I write code, I think in terms of types, and rarely in terms of anything else. Python is useful in tons of problems OCaml isn't such as data science, statistics etc. Besides python has a very large ecosystem which matters in order not to reinvent the wheel.

Re:Functional Python Programming by carapace on Saturday June 10, 2023 @05:32PM (#36275357)
> I personally think there is no programming problem where types aren't useful.

I'd have to disagree with that just on first principles: no absolutes. (Note that that's an absolute.) :)

Anyway, I'm not trying to argue that types are not useful, they are. What I'm saying is that Python's loose approach to typing is useful "in the small" so to speak, but as projects grow larger you want "harder" types, checked by machine. Same thing with DB schema: No-SQL only makes sense in the small domains where the schema can be ignored or treated as an afterthought. Above a certain size and you grow a schema again and might as well do it right.

Re:Functional Python Programming by linkdd on Saturday June 10, 2023 @06:27AM (#36269289)
> I'm not into types [in Python]

In Python type hints are just that: hints.

mypy is a very poor static analyzer, and a lot of Python code (especially in frameworks like Django) is inherently dynamic and cannot be type-checked. And that's ok.

Though, documenting your API with type-hints really helps, especially with VSCode (via pyright) popovers when you hover a symbol/function.

Re:Functional Python Programming by pjmlp on Friday June 09, 2023 @05:25PM (#36264358)
Not for Lisp or some ML derived languages, FP isn't whatever Haskell does.
Re:Functional Python Programming by archarios on Friday June 09, 2023 @07:20PM (#36265672)
Not having immutability isn't the worst thing IMO. I guess if you can't trust your coworkers to not modify their inputs, it's a different story.
Re:Functional Python Programming by harry8 on Friday June 09, 2023 @07:25PM (#36265716)
> The core of functional programming is about avoiding mutable states,

I can't keep up, does this mean scheme is not a functional language anymore by modern definition?

Re:Functional Python Programming by znafelrif on Friday June 09, 2023 @07:43PM (#36265877)
> The core of functional programming is about avoiding mutable states, not much about anonymous functions or passing functions as data.

I disagree since any paradigm can be done either with or without mutable state. So it is not something that defines functional programming.

In any case you can also use immutable data types with python anyway.

The main annoyance with python is in my opinion your last point: The lambda syntax is too limited. So it is necessary to define lots of nested small functions instead.

Also python syntax is not as nice in chaining function calls over multiple lines.

Re:Functional Python Programming by elesiuta on Saturday June 10, 2023 @05:24PM (#36275265)
> Also python syntax is not as nice in chaining function calls over multiple lines.

Not sure if this is exactly what you meant, but I implemented something like this in reply to a similar comment a few months ago which may be of interest.

https://news.ycombinator.com/item?id=35105298

Re:Functional Python Programming by tpoacher on Saturday June 10, 2023 @06:23PM (#36275812)
I use this approach [0]. Works well enough for me and is visually adequate for "piping"-style code.

0. https://sr.ht/~tpapastylianou/chain-ops-python/

Re:Functional Python Programming by chlorion on Friday June 09, 2023 @10:59PM (#36267155)
I do not think functional programming is about mutable state at all.

It's about functions being first class values, nothing more.

Lisp and Scheme are examples of functional languages that do not restrict mutability.

The term for what you are talking about is pure functional programming!

Re:Functional Python Programming by kazinator on Friday June 09, 2023 @11:31PM (#36267322)
I don't think you are correct. Programming languages with support for functional programming are not always pure functional languages. However, functional programming per se is always pure by definition; if you're mutating anything, it's not functional.

(You can have "quasi functional" if you mutate only local variables, such that the black box view of your functions appears pure. Nobody knows whether the map function in (map f list) internally contains a loop or tail recursion.)

Languages which support functional programming and other paradigms are not called functional; it is not correct to call Common Lisp and Scheme functional.

Not only do these have mutation, they have sequencing via strict evaluation: doing one thing that has a side effect, followed by another. Side effects like I/O and mutation are easily obtained and ordered, just like in Fortran or Java.

Re:Functional Python Programming by chlorion on Saturday June 10, 2023 @07:56PM (#36276580)
Pure functional programming is always about purity, functional programming is about first class functions. Pure functional programming is a subset of functional programming, not the other way around.

I'm not really sure where you are getting your information from but everything that I have read disagrees with this idea that functional programming is about purity.

https://en.wikipedia.org/wiki/Functional_programming

I think in recent times the term functional programming has been overloaded to mean what you describe, and many people use it that way, but I don't think it should be used that way.

Maybe we should just say "non pure functional" or "pure functional" so it's always clear what we are talking about!

Re:Functional Python Programming by kazinator on Monday June 12, 2023 @06:15PM (#36302039)
Many mainstream programming languages implement procedures and functions with the same syntax, and call procedures functions. Procedures can take arguments and return a value, like functions, but also have side effects. Nobody asked for this terminology mixup; it just happened in the reference manuals of programming languages. Lisp calls procedures functions; so does C.

Programming with procedures isn't functional programming; it is procedural programming. This is true even when the procedures are first-class procedures, and are used in declarative patterns like mapping, reducing and so on. There is no word which refers to programming with first-class procedures in a declarative style. It is different from "Fortran-like procedural", and is rooted in OOP. First class procedures are objects; and in fact in many languages you can take a solution based on first class procedures and replace those procedures with objects. Mutated lexical variables become member variables (or slots) and so on.

The rhetoric in this area conflates two meanings of "pure" and "purely", causing equivocation.

- "pure X" as in "consisting of nothing but X" and "purely X" meaning "solely X"

- "pure" as in having no side effects: a pure expression can be replaced by its value without a change in meaning.

A "not purely functional language" uses "purely" in the former sense. The language emphasizes functional features, but has procedural features also. It doesn't refer to a language which emphasizes declarative programming patterns around first-class procedures, though such a language can fit the description.

A "not purely functional program" likewise: it emphasizes functional programming but has procedural bits in there. It doesn't refer to the program being composed entirely of the declarative use of higher order procedures, like mapping over collections while doing I/O or mutation and such.

If we take the value of a variable and then filter it through functional stages, only to then assign the transformed value into the same variable by assignment, that is an example of "not purely functional". The data transformation is functional; the assignment isn't.