[Haskell-cafe] PEP622

Olaf Klinke olf at aatal-apotheke.de
Sun Jun 28 21:14:53 UTC 2020


On Sun, 2020-06-28 at 19:13 +0300, Ba Ge wrote:
> Interesting PEP. Actually it reminds me Crystal language ‘case’. But
> I have some comments
>  
> > An excerpt from PEP622 [1]:
>  
> > Let us start from some anecdotal evidence: isinstance() is one of
> the
> > most called functions in large scale Python code-bases (by static
> > call count). In particular, when analyzing some multi-million line
> > production code base, it was discovered that isinstance() is the
> > second most called builtin function (after len()). Even taking into
> > account builtin classes, it is still in the top ten. Most of such
> > calls are followed by specific attribute access.
> >
> > There are two possible conclusions that can be drawn from this
> > information:
> >
> > *    Handling of heterogeneous data (i.e. situations where a
> variable
> > can take values of multiple types) is common in real world code.
>  
> It can be handled with modern Python’ types.

Yes, obviously it is possible to handle with today's language
constructs. But that is not the point of the proposal. 

>  
> > *    Python doesn't have expressive ways of destructuring object
> data
> > (i.e. separating the content of an object into multiple variables).
> >
>  
> Actually the second reason when isinstance() is used (related to
> “destructuring”) is the case with inheritance. So the isinstance()
> switches cases between different successors of some base class. And
> there would be such a kind of “destructuring”:
>  
> if isinstance(something, Window): return something.handle
> elif isinstance(something, Button): return something.wnd_hnd
> else: raise SomeError(“blah-blah”)

See, these nested if-statements is what the proposal is aiming to
replace. 

>  
> which is anti-pattern sure: in the case of inheritance, the getters
> must be delegated to concrete implementations.
>  
> > I just want to say a big thank you to the Haskell creators for
> giving
> > us a tool to efficiently write real world code (as it is called
> above).
>  
> The reason why ML family languages have pattern-matching is:
>  
>            data X = X1 Int Int | X2 String
>  
> Python and similar languages don’t support algebraic data types
> directly (and usually you simulate it with inheritance), so you don’t
> need pattern-matching and such a way of “destructuring” at all. What
> is
>  
>            case x of X1 n m -> …
>  
> ? It’s a leak of abstraction. 
Good point, sounds logical. No ADTs, no need for pattern match. And yet
the cited frequency of isinstance() indicates there is a need
nevertheless. 
By the way, any language that has lambda calculus embedded (i.e.
anonymous functions as first-class citizens) can emulate algebraic data
types and pattern matching via Scott encoding. In that respect, Python
does have ADTs. See this recent talk: 

https://bobkonf.de/2020/thoma.html
 
For example in Haskell you avoid pattern matching on a Maybe via the
function 
maybe :: r -> (a -> r) -> Maybe a -> r 
because maybe is doing the pattern match for you. In Python the Scott
encoding would be something like:

class Maybe:
    def __init__(self,content=None):
        if content is None:
            self.nothing()
        else:
            self.just(content) 
    def nothing(self):
        self.maybe = lambda(r,f): r
    def just(self,a):
        self.maybe = lambda(r,f): f(a)

> A leak of knowledge about INTERNAL structure, internal representation
> of the object, which is bad. So, if you think that pattern-matching
> is very good (aka “real world”) , IMHO you are not right here. So C#
> designers added EXPLICIT support of deconstruct:
>  
> private static (string, int, double) QueryCityData(string name) {…}
So I need to write this function myself? That is just unnecessary
boilerplate from the functional programmer's point of view, isn't it?

>  
> so you don’t leak information about internal representation of your
> data and use just common external general representation like tuples,
> for example. 

Since you argued that Python as it is can do all this already, I'll
argue that Haskell can do all this already: One can always choose to
not export an ADT's constructors and provide other accessors to pattern
match on. 

> The second helper in C# is a new `switch` syntax, which is very close
> to pattern-matching, but again: it’s limited with public fields, so
> only a developer decides which part of his class will be available
> for matching, and no any leak again. This idea was crystallized in
> Perl: you don’t know what is the object but do know that it can be
> used in scalar context/list context/hash context and so on. In OOP,
> for example, you don’t know what is the object but you know that you
> can use it as a container of items, which can be
> enumerable/modifiable-in-place/whatever… This is a right solution
> from a language designer point of view, but not a ML-style pattern
> matching.
You were just describing Haskell's type classes. 

>  
> And this understanding is often used in Haskell too – some types are
> “hidden” for the user: you have only smart constructors/getters but
> not knowledge about inner structure of the object. IMHO ML-style
> pattern matching is outdated feature, more typical for 70-80s
> languages.
Wow, that's a strong statement. We shall see how outdated it is when
the adoption of PEP622 is decided upon. It would not be the first time
that a mainstream language adopted an old FP construct after many
years. 

>  
> ---
> Best regards, Paul
>  
>  

I posted this initially because of the techniques used to arrive at the
proposal: Sift through large codebases and look for patterns that seem
to be workarounds caused by some shortcoming of the language. I don't
know the evolution of Haskell very well. Has this ever been done with
Haskell?

Olaf



More information about the Haskell-Cafe mailing list