Agreed. While algebraic data types are obviously a good idea, the best way to use Python is to accept it for what it is: a dynamically typed object-oriented language that's not very good at manipulating user-defined values (or even defining them to begin with), but has some pretty cool tricks of its own, like runtime metaprogramming with decorators and metaclasses.
I think you place python in a much smaller box that it deserves. before it was object-oriented it was functional and procedural. For certain things I use it in a purely functional way but have never felt the need for one of these libraries to do so.
Python has always had procedures, of course, but was it ever a functional language? Let's do a bit of fact-checkcing:
(0) Functional programming is expressing computation as the evaluation of functions. A language is “functional” to the extent it allows you to do functional programming.
(1) A function is a mapping from values to values. To express computation as the evaluation of functions, you need a rich universe of values: not just primitive ones like integers and object references, but also tuples, lists, trees, etc.
(2) Values are timeless entities that are distinguished from each other structurally. For example, it makes no sense to distinguish “this list [1,2,3]” from “that list [1,2,3]”, because both have the same structure - the same parts. Thus, what Python calls “tuples” and “lists” are not really tuple values and list values.
---
@_9jgl
Let's see how equal they remain in a timeless fashion:
Turns out, the real equality testing operator in Python is `is`, not `==`. The only values Python gives you are object references.
---
@lmm
> This is by no means the only way to write Python
This is not the problem. The problem is that Python doesn't have compound values. Values are a matter of semantics, and semantics is a matter of how the language is defined, not how you choose to program in it.
Words are defined by consensus and use. To a lot of people "functional" means having first-class functions (in particular: functions can be defined anywhere (i.e. the language has closures) and functions are first-class values (i.e. functions can be passed as function parameters and returned from functions; function values can be expressed separately from assignment (i.e. the language has lambdas))) and programming in a style that makes use of map, reduce, and filter; more generally programming with immutable values and functions that return transformations of those values (as distinct from programming with pervasive state that is mutated). This is by no means the only way to write Python, but it's practical in Python to a much greater extent than it is in, say, Java.
> (2) Values are timeless entities that are distinguished from each other structurally. For example, it makes no sense to distinguish “this list [1,2,3]” from “that list [1,2,3]”, because both have the same structure - the same parts. Thus, what Python calls “tuples” and “lists” are not really tuple values and list values.
Would you mind expanding on this? I'm not sure I really understand what you mean – if we have two lists a = [1,2,3] and b = [1,2,3], then a == b, so I don't see how Python is distinguishing them from each other.
Sum types make very little sense in dynamically typed languages even with good manipulation of user-defined values. For instance Erlang does not have "formal" sum types, it wouldn't really bring anything useful to the table, the compiler does not typecheck by default (so the sum type would just be a complication with no benefits) and Dialyzer can simulate them by using type/value unions e.g.