Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #67493 > unrolled thread

Re: Functional programming

Started byNed Batchelder <ned@nedbatchelder.com>
First post2014-03-02 20:27 -0500
Last post2014-03-03 16:35 -0800
Articles 20 on this page of 60 — 15 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Functional programming Ned Batchelder <ned@nedbatchelder.com> - 2014-03-02 20:27 -0500
    Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 03:45 -0800
      Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-03 23:20 +1100
        Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 05:48 -0800
          Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 05:51 -0800
          Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-04 01:00 +1100
            Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 06:08 -0800
              Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-04 01:23 +1100
                Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 06:38 -0800
                  Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-04 02:01 +1100
                    Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 07:28 -0800
                    Re: Functional programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-03 17:27 +0000
                      Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-04 05:37 +1100
                        Re: Functional programming Steven D'Aprano <steve@pearwood.info> - 2014-03-04 05:35 +0000
                          Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 21:59 -0800
                          Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-04 17:04 +1100
                            Re: Functional programming Rustom Mody <rustompmody@gmail.com> - 2014-03-03 22:20 -0800
                            Re: Functional programming Steven D'Aprano <steve@pearwood.info> - 2014-03-04 08:56 +0000
                              Re: Functional programming Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2014-03-04 11:56 +0100
                                Re: Functional programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-04 11:47 +0000
                                  Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 00:01 +1100
                                    OT Sine Rule [was Re: Functional programming] Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-04 14:25 +0000
                                      Re: OT Sine Rule [was Re: Functional programming] Tim Chase <python.list@tim.thechases.com> - 2014-03-04 08:37 -0600
                                      Re: OT Sine Rule [was Re: Functional programming] Mark Lawrence <breamoreboy@yahoo.co.uk> - 2014-03-04 14:42 +0000
                                      Re: OT Sine Rule [was Re: Functional programming] Chris Angelico <rosuav@gmail.com> - 2014-03-05 02:06 +1100
                                      Re: OT Sine Rule [was Re: Functional programming] Tim Chase <python.list@tim.thechases.com> - 2014-03-04 09:21 -0600
                                  Re: Functional programming Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2014-03-05 09:59 +0100
                                Re: Functional programming Marko Rauhamaa <marko@pacujo.net> - 2014-03-04 21:49 +0200
                                  Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 07:01 +1100
                                    Re: Functional programming Marko Rauhamaa <marko@pacujo.net> - 2014-03-04 22:50 +0200
                                      Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 08:06 +1100
                                        Re: Functional programming Marko Rauhamaa <marko@pacujo.net> - 2014-03-04 23:21 +0200
                                          Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 08:26 +1100
                                            Re: Functional programming Marko Rauhamaa <marko@pacujo.net> - 2014-03-04 23:43 +0200
                                              Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 08:52 +1100
                                              Re: Functional programming Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-03-05 12:57 +1300
                                                Re: Functional programming Marko Rauhamaa <marko@pacujo.net> - 2014-03-05 02:11 +0200
                              Re: Functional programming "BartC" <bc@freeuk.com> - 2014-03-04 13:30 +0000
                                Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 00:47 +1100
                                Re: Functional programming Mark Lawrence <breamoreboy@yahoo.co.uk> - 2014-03-04 14:05 +0000
                                  Re: Functional programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-04 14:55 +0000
                                    Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 02:13 +1100
                                    Re: Functional programming MRAB <python@mrabarnett.plus.com> - 2014-03-04 17:07 +0000
                                Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 01:17 +1100
                                Re: Functional programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-04 15:18 +0000
                                  Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 02:28 +1100
                                    Re: Functional programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-04 15:45 +0000
                                      Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 03:04 +1100
                                  Re: Functional programming Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2014-03-05 10:09 +0100
                                  Re: Functional programming "BartC" <bc@freeuk.com> - 2014-03-05 11:28 +0000
                                    Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-05 23:04 +1100
                                      Re: Functional programming Marko Rauhamaa <marko@pacujo.net> - 2014-03-05 14:11 +0200
                      Re: Functional programming Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-03-04 11:06 +1300
                        Re: Functional programming Ben Finney <ben+python@benfinney.id.au> - 2014-03-04 09:31 +1100
                          Re: Functional programming Grant Edwards <invalid@invalid.invalid> - 2014-03-04 14:59 +0000
                            Re: Functional programming Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-03-04 15:22 +0000
                        Re: Functional programming Chris Angelico <rosuav@gmail.com> - 2014-03-04 09:42 +1100
                        Re: Functional programming Ben Finney <ben+python@benfinney.id.au> - 2014-03-04 10:52 +1100
                      Re: Functional programming "BartC" <bc@freeuk.com> - 2014-03-04 09:41 +0000
              Re: Functional programming 88888 Dihedral <dihedral88888@gmail.com> - 2014-03-03 16:35 -0800

Page 1 of 3  [1] 2 3  Next page →


#67493 — Re: Functional programming

FromNed Batchelder <ned@nedbatchelder.com>
Date2014-03-02 20:27 -0500
SubjectRe: Functional programming
Message-ID<mailman.7612.1393810048.18130.python-list@python.org>
On 3/2/14 6:14 PM, musicdenotation@gmail.com wrote:
> If Python is not a fnctional language, then which programming paradigmis dominant?
>

is_a_functional_language() is not a binary condition, yes or no.  It's a 
continuum.  Python has more functional constructs than Pascal, and fewer 
than Haskell.

-- 
Ned Batchelder, http://nedbatchelder.com

[toc] | [next] | [standalone]


#67527

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 03:45 -0800
Message-ID<4c7dbc57-eef9-4582-aecd-aac13a39b45f@googlegroups.com>
In reply to#67493
On Monday, March 3, 2014 6:57:15 AM UTC+5:30, Ned Batchelder wrote:
> On 3/2/14 6:14 PM, musicdenotation wrote:
> > If Python is not a fnctional language, then which programming paradigmis dominant?

> is_a_functional_language() is not a binary condition, yes or no.  It's a 
> continuum.  Python has more functional constructs than Pascal, and fewer 
> than Haskell.

I find this the most agreeable answer. I would add:

There are really two continuaa:
the 'CAN' and the 'CANNOT' (sounds 180 deg apart but they are actually
rather independent)

As Ned says on the CAN spectrum python sits between standard
imperative languages like C,Pascal and Haskell, in fact coming quite close
to Haskell.

However it is also useful to consider the CANNOT spectrum for
beginners/pedagogical purposes.

If you start a beginner on a language like Haskell which CANNOT:
- express iteration except with recursion
- cannot have assignments (and therefore anything remotely like a normal
program variable; variables are only ever math variables)
- cannot do a 'type-incorrect' expression like
>>> [1,2] + [[3,4],[5]]
[1, 2, [3, 4], [5]]

the beginner will develop a significantly different mind-set than
starting from a python-like language

[toc] | [prev] | [next] | [standalone]


#67529

FromChris Angelico <rosuav@gmail.com>
Date2014-03-03 23:20 +1100
Message-ID<mailman.7633.1393849247.18130.python-list@python.org>
In reply to#67527
On Mon, Mar 3, 2014 at 10:45 PM, Rustom Mody <rustompmody@gmail.com> wrote:
> - cannot do a 'type-incorrect' expression like
>>>> [1,2] + [[3,4],[5]]
> [1, 2, [3, 4], [5]]

What do you mean by "type-incorrect"? This is adding two lists and
getting back a list. Seems perfectly correct to me.

ChrisA

[toc] | [prev] | [next] | [standalone]


#67543

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 05:48 -0800
Message-ID<3b54a279-03a1-4a81-a428-ecad6eb16036@googlegroups.com>
In reply to#67529
On Monday, March 3, 2014 5:50:37 PM UTC+5:30, Chris Angelico wrote:
> On Mon, Mar 3, 2014 at 10:45 PM, Rustom Mody  wrote:
> > - cannot do a 'type-incorrect' expression like
> >>>> [1,2] + [[3,4],[5]]
> > [1, 2, [3, 4], [5]]

> What do you mean by "type-incorrect"? This is adding two lists and
> getting back a list. Seems perfectly correct to me.


Here's the behavior from an (old version of) haskell.

Unfortunately modern versions give a less helpful error message
'++' is list-append, '?' is the prompt

? [1,2] + [[3,4],[5]]                   
ERROR: Type error in application
*** expression     : [1,2] + [[3,4],[5]]
*** term           : [1,2]
*** type           : [Int]
*** does not match : [[Int]]

IOW [1,2,[3,4],[5]]
is a type-wise ill-formed expression just as in python
[[1,2])
is syntax-wise ill-formed

Is it worth having such a restriction?
Thats a different argument...

[toc] | [prev] | [next] | [standalone]


#67544

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 05:51 -0800
Message-ID<3a913df5-5034-4d9c-985a-a46a7015d6cd@googlegroups.com>
In reply to#67543
On Monday, March 3, 2014 7:18:00 PM UTC+5:30, Rustom Mody wrote:

> Unfortunately modern versions give a less helpful error message
> '++' is list-append, '?' is the prompt

> ? [1,2] + [[3,4],[5]]                   

Whoops Wrong cut-paste!

? [1,2] ++ [[3,4],[5]]
ERROR: Type error in application
*** expression     : [1,2] ++ [[3,4],[5]]
*** term           : [1,2]
*** type           : [Int]
*** does not match : [[Int]]

? 

[toc] | [prev] | [next] | [standalone]


#67546

FromChris Angelico <rosuav@gmail.com>
Date2014-03-04 01:00 +1100
Message-ID<mailman.7641.1393855219.18130.python-list@python.org>
In reply to#67543
On Tue, Mar 4, 2014 at 12:48 AM, Rustom Mody <rustompmody@gmail.com> wrote:
> ? [1,2] + [[3,4],[5]]
> ERROR: Type error in application
> *** expression     : [1,2] + [[3,4],[5]]
> *** term           : [1,2]
> *** type           : [Int]
> *** does not match : [[Int]]
>
> IOW [1,2,[3,4],[5]]
> is a type-wise ill-formed expression just as in python
> [[1,2])
> is syntax-wise ill-formed
>
> Is it worth having such a restriction?
> Thats a different argument...

How do you know that [1,2] is a list that must contain nothing but
integers? By extension, it's also a list that must contain positive
integers less than three, so adding [5] violates that. And [] is a
list that must contain nothing, ergo it can't be added to, although
(since it contains nothing) it can be added to anything.

Some languages do let you specify element types (Pike has an "array"
type that can hold anything, or you can say "array(int)" to restrict
it to integers; you could also say "array(int(1..2))" to specify what
I said above, if you actually intend that), but without a declaration
from the programmer, it's dangerous to assume there's an error.

ChrisA

[toc] | [prev] | [next] | [standalone]


#67547

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 06:08 -0800
Message-ID<216bb5f4-32c4-4f86-a9f4-1b0dd37a2a81@googlegroups.com>
In reply to#67546
On Monday, March 3, 2014 7:30:17 PM UTC+5:30, Chris Angelico wrote:
> On Tue, Mar 4, 2014 at 12:48 AM, Rustom Mody wrote:
> > ? [1,2] + [[3,4],[5]]
> > ERROR: Type error in application
> > *** expression     : [1,2] + [[3,4],[5]]
> > *** term           : [1,2]
> > *** type           : [Int]
> > *** does not match : [[Int]]
> > IOW [1,2,[3,4],[5]]
> > is a type-wise ill-formed expression just as in python
> > [[1,2])
> > is syntax-wise ill-formed
> > Is it worth having such a restriction?
> > Thats a different argument...

> How do you know that [1,2] is a list that must contain nothing but
> integers? By extension, it's also a list that must contain positive
> integers less than three, so adding [5] violates that. And [] is a
> list that must contain nothing, ergo it can't be added to, although
> (since it contains nothing) it can be added to anything.

If 'integer-less-than-3' were a type then yes there would be this
problem. More generally, if types could overlap then automatic
type-inference is impossible

Whether all thats good is as I earlier said a different argument

The OP asked about FP and so its appropriate to mention how python's
and standard FPL's choices differ

[toc] | [prev] | [next] | [standalone]


#67551

FromChris Angelico <rosuav@gmail.com>
Date2014-03-04 01:23 +1100
Message-ID<mailman.7644.1393856584.18130.python-list@python.org>
In reply to#67547
On Tue, Mar 4, 2014 at 1:08 AM, Rustom Mody <rustompmody@gmail.com> wrote:
>> How do you know that [1,2] is a list that must contain nothing but
>> integers? By extension, it's also a list that must contain positive
>> integers less than three, so adding [5] violates that. And [] is a
>> list that must contain nothing, ergo it can't be added to, although
>> (since it contains nothing) it can be added to anything.
>
> If 'integer-less-than-3' were a type then yes there would be this
> problem. More generally, if types could overlap then automatic
> type-inference is impossible
>

First, does Haskell allow this?

? [1,2,'foo'] ++ [3,4,'bar']

If not, then find some other form of the expression that has the same
point, and substitute in for the below. And then: which of these is
permitted?

? [1,2] ++ [3,4,'bar']
? [1,2,'foo'] ++ [3,4]
? [] ++ [3,4,'bar']
? [1,2,'foo'] ++ []
? ([1,2,'foo'] ++ []) ++ [3,4,'bar']
? [1,2,'foo'] ++ ([] ++ [3,4,'bar'])

If it's okay to have heterogeneous lists, how do you tell it that your
[1,2] is actually going to get strings in it later, and that it's okay
to combine it with one that has strings?

With Pike, that's all based on the variable type. (There is type
inference; the type of an array containing just 3 and 4 is
"array(int(3..4))", but it's acceptable to add that to an array
containing the string "asdf", which itself has type
"array(string(97..115))" - the combination would be "array(int(3..4) |
string(97..115))", which gets a bit wordy.) I can't assign an
array(string) to a variable that's been declared as taking array(int).
But I can assign an array(int) to a variable declared as accepting
array(int|string), and then I can append a string to it, because
that's legal based on the destination.

ChrisA

[toc] | [prev] | [next] | [standalone]


#67556

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 06:38 -0800
Message-ID<0129a5b9-b85f-4ad5-b5e2-bfb2a48041d5@googlegroups.com>
In reply to#67551
On Monday, March 3, 2014 7:53:01 PM UTC+5:30, Chris Angelico wrote:
> On Tue, Mar 4, 2014 at 1:08 AM, Rustom Mody wrote:
> >> How do you know that [1,2] is a list that must contain nothing but
> >> integers? By extension, it's also a list that must contain positive
> >> integers less than three, so adding [5] violates that. And [] is a
> >> list that must contain nothing, ergo it can't be added to, although
> >> (since it contains nothing) it can be added to anything.
> > If 'integer-less-than-3' were a type then yes there would be this
> > problem. More generally, if types could overlap then automatic
> > type-inference is impossible

> First, does Haskell allow this?

> ? [1,2,'foo'] ++ [3,4,'bar']

> If not, then find some other form of the expression that has the same
> point, and substitute in for the below. And then: which of these is
> permitted?


Dunno what you mean/whats the 'point'


> ? [1,2] ++ [3,4,'bar']
> ? [1,2,'foo'] ++ [3,4]
> ? [] ++ [3,4,'bar']
> ? [1,2,'foo'] ++ []
> ? ([1,2,'foo'] ++ []) ++ [3,4,'bar']
> ? [1,2,'foo'] ++ ([] ++ [3,4,'bar'])

> If it's okay to have heterogeneous lists, 

Its not.  None of the above work

If you want the (semantic) equivalent of python's [1,2,'foo']
you need to make an explicit union Int and String and its that
*single* union type's elements that must go in.

In all cases its always a single type. And so
sum([1,2,[3])
is a syntax error unlike python where its a runtime error

[toc] | [prev] | [next] | [standalone]


#67557

FromChris Angelico <rosuav@gmail.com>
Date2014-03-04 02:01 +1100
Message-ID<mailman.7647.1393858917.18130.python-list@python.org>
In reply to#67556
On Tue, Mar 4, 2014 at 1:38 AM, Rustom Mody <rustompmody@gmail.com> wrote:
> If you want the (semantic) equivalent of python's [1,2,'foo']
> you need to make an explicit union Int and String and its that
> *single* union type's elements that must go in.
>
> In all cases its always a single type. And so
> sum([1,2,[3])

Okay. That's how the declaration goes, then. So how do you tell it
that 1 isn't an Int, it's a member of the union of Int and String? How
do you create a list which has [Int_String(1), Int_String(2)] and is
therefore allowed to be added to [Int_String('foo')] ? Can you do that
with literals?

This is why it's tricky to put rules in based on type inference. The
programmer's intent isn't in the picture. If Python ever acquires that
kind of restriction ("here's a list that can contain only this type /
these types of object"), I would hope that it's left up to the
programmer, not the compiler, to stipulate. That's how it is with Pike
(if you just say "array", it can take anything), and that's the only
way to be sure the programmer doesn't have to fight the language.

You said earlier

>> On Tue, Mar 4, 2014 at 1:08 AM, Rustom Mody wrote:
>> > If 'integer-less-than-3' were a type then yes there would be this
>> > problem. More generally, if types could overlap then automatic
>> > type-inference is impossible

The type "Int" overlaps with the type "Union of Int and String". How
is that resolved? Type inference ignores unions? That's the only way I
can think of. Hence the original difficulty of type-inferring on a
list that isn't complete yet.

ChrisA

[toc] | [prev] | [next] | [standalone]


#67560

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 07:28 -0800
Message-ID<8dbc91d9-42e5-4404-ba10-7a6d8e404986@googlegroups.com>
In reply to#67557
On Monday, March 3, 2014 8:31:47 PM UTC+5:30, Chris Angelico wrote:
> On Tue, Mar 4, 2014 at 1:38 AM, Rustom Mody  wrote:
> > If you want the (semantic) equivalent of python's [1,2,'foo']
> > you need to make an explicit union Int and String and its that
> > *single* union type's elements that must go in.
> > In all cases its always a single type. And so
> > sum([1,2,[3])

> Okay. That's how the declaration goes, then. So how do you tell it
> that 1 isn't an Int, it's a member of the union of Int and String? How
> do you create a list which has [Int_String(1), Int_String(2)] and is
> therefore allowed to be added to [Int_String('foo')] ? Can you do that
> with literals?

Mmmm This is getting a bit OT for a python list
Anyway here goes
The Union type is called Either.
Its got two constructors -- Left and Right -- better to think of them as
tags to not confuse with OO constructors.
The names Left and Right seem to be a bit meaningless because the Either
type is completely generic -- any types S and T can be 'unioned' as
Either S T
where the S components look like Left x for x : S
and the T components look like Right x for x : T

So python's [1,2,"foo"] is
written as
[Left 1, Left 2, Right "foo"]

> This is why it's tricky to put rules in based on type inference. The
> programmer's intent isn't in the picture. If Python ever acquires that
> kind of restriction ("here's a list that can contain only this type /
> these types of object"), I would hope that it's left up to the
> programmer, not the compiler, to stipulate. That's how it is with Pike
> (if you just say "array", it can take anything), and that's the only
> way to be sure the programmer doesn't have to fight the language.

> You said earlier

> >> On Tue, Mar 4, 2014 at 1:08 AM, Rustom Mody wrote:
> >> > If 'integer-less-than-3' were a type then yes there would be this
> >> > problem. More generally, if types could overlap then automatic
> >> > type-inference is impossible

> The type "Int" overlaps with the type "Union of Int and String". How
> is that resolved? 

By decreeing "no overlap!" :-)

Left 1 : Either Int String
whereas 1 : Int

Strictly speaking 'union' should be called 'disjoint union' but this is
so universal in programming that its dropped as redundant.

Heck even C's union is disjoint! If we have

union u
{ 
  int i;
  char c;
};

union u x;

Now you cant interchange the usages of x x.i and x.c

[toc] | [prev] | [next] | [standalone]


#67568

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-03-03 17:27 +0000
Message-ID<5314bb96$0$29985$c3e8da3$5496439d@news.astraweb.com>
In reply to#67557
On Tue, 04 Mar 2014 02:01:47 +1100, Chris Angelico wrote:

> This is why it's tricky to put rules in based on type inference. The
> programmer's intent isn't in the picture. 

Of course it is. If I assign 23 to variable x, that signals my intent to 
assign an int to x. By Occam's razor, it is reasonable to extrapolate 
that intent to mean "x is an int", rather than "an int, or a list" or "an 
odd int larger than 7 but smaller than 25", or "any int except 13". Type 
inference picks the type which involves the fewest additional 
assumptions. The programmer can always over-ride the type inference by 
explicitly stating the type.

It works really well in practice, because most of the time you don't need 
a lot of type dynamism. Or even any.

Think about the sort of type declarations you have to do in (say) Pascal, 
and consider how stupid the compiler must be:

function add_one(x: integer):integer;
  begin
    add_one := x+1;
  end;

Given that x is an integer, and that you add 1 (also an integer) to it, 
is it really necessary to tell the compiler that add_one returns an 
integer? What else could the output type be?

This was state of the art back in 1970, but these days, if the compiler 
cannot *at least* infer the type of the return result of a function given 
the argument types, the static type system is too dumb to bother with. A 
good static type system can even detect infinite loops at compile time:

http://perl.plover.com/yak/typing/notes.html

This is not cutting edge technology: ML dates back to the 1990s, if not 
older.


> If Python ever acquires that
> kind of restriction ("here's a list that can contain only this type /
> these types of object"), I would hope that it's left up to the
> programmer, not the compiler, to stipulate.

That's not type inference. That's ancient and annoying obligatory type 
declarations as used by ancient languages with primitive type systems, 
like Pascal and C.


> That's how it is with Pike
> (if you just say "array", it can take anything), and that's the only way
> to be sure the programmer doesn't have to fight the language.

To be sure, any form of static typing is going to restrict what you can 
do. This isn't intended to imply that static typing is better than 
dynamic typing. But if you have static typing, there's *no point* to it 
if the type system cannot detect bugs, and having to declare types is 
like having to calculate your own GOTO addresses. With a good type system 
like ML or Haskell have, you're not fighting the compiler, *every* type 
error you get is a real, actual bug in your code.



-- 
Steven D'Aprano
http://import-that.dreamwidth.org/

[toc] | [prev] | [next] | [standalone]


#67570

FromChris Angelico <rosuav@gmail.com>
Date2014-03-04 05:37 +1100
Message-ID<mailman.7651.1393871851.18130.python-list@python.org>
In reply to#67568
On Tue, Mar 4, 2014 at 4:27 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> On Tue, 04 Mar 2014 02:01:47 +1100, Chris Angelico wrote:
>
>> This is why it's tricky to put rules in based on type inference. The
>> programmer's intent isn't in the picture.
>
> Of course it is. If I assign 23 to variable x, that signals my intent to
> assign an int to x. By Occam's razor, it is reasonable to extrapolate
> that intent to mean "x is an int", rather than "an int, or a list" or "an
> odd int larger than 7 but smaller than 25", or "any int except 13". Type
> inference picks the type which involves the fewest additional
> assumptions. The programmer can always over-ride the type inference by
> explicitly stating the type.

Yes, and that's fine for most purposes. The problem isn't the
inference, the problem is when rules are created based on that kind of
guess - when the programmer's subsequent actions are governed by a
guess the compiler takes.

x = 23 # Compiler goes: Okay, x takes ints.
x += 5 # Compiler: No prob, int += int --> int
x = str(x) # Compiler: NO WAY! str(int) --> str, not allowed!

It's fine and correct to infer that x is an int, x is an int, x is a
str. It's *not* okay to make the third line a SyntaxError because you
just put a str into an int variable.

>> If Python ever acquires that
>> kind of restriction ("here's a list that can contain only this type /
>> these types of object"), I would hope that it's left up to the
>> programmer, not the compiler, to stipulate.
>
> That's not type inference. That's ancient and annoying obligatory type
> declarations as used by ancient languages with primitive type systems,
> like Pascal and C.

And that's exactly what Haskell apparently has, with homogeneous lists
and no easy way to say that it can take more types.

Python's handling is: A list can hold anything.

Pike's handling is: An array can hold anything, unless you specify
otherwise. You can specify whatever you can code:
array(int(1000..2000) | string('a'..'z') | float) foo = ({1234,
"abcd", 1.2});

Haskell's handling apparently is: A list/array can hold one thing and
one thing only. That 'thing' can be a union, but then you need to be
REALLY explicit about which side is which. It's not possible to
sub-specify a type (like the "string('a'..'x')" type in Pike that will
take only strings with nothing but the first 24 lower-case letters -
not that I've ever needed that), but the compiler can work out
everything else.

The way I see it, Python's form is fully dynamic and open, Pike's is
fully dynamic and the programmer's allowed to explicitly close things,
and Haskell's is rigidly tight. That's not to say that tight is a bad
thing (it's probably good for learning under), but personally, I'd
rather have the freedom.

ChrisA

[toc] | [prev] | [next] | [standalone]


#67646

FromSteven D'Aprano <steve@pearwood.info>
Date2014-03-04 05:35 +0000
Message-ID<5315661c$0$2923$c3e8da3$76491128@news.astraweb.com>
In reply to#67570
On Tue, 04 Mar 2014 05:37:27 +1100, Chris Angelico wrote:

> On Tue, Mar 4, 2014 at 4:27 AM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> On Tue, 04 Mar 2014 02:01:47 +1100, Chris Angelico wrote:
>>
>>> This is why it's tricky to put rules in based on type inference. The
>>> programmer's intent isn't in the picture.
>>
>> Of course it is. If I assign 23 to variable x, that signals my intent
>> to assign an int to x. By Occam's razor, it is reasonable to
>> extrapolate that intent to mean "x is an int", rather than "an int, or
>> a list" or "an odd int larger than 7 but smaller than 25", or "any int
>> except 13". Type inference picks the type which involves the fewest
>> additional assumptions. The programmer can always over-ride the type
>> inference by explicitly stating the type.
> 
> Yes, and that's fine for most purposes. The problem isn't the inference,
> the problem is when rules are created based on that kind of guess - when
> the programmer's subsequent actions are governed by a guess the compiler
> takes.
> 
> x = 23 # Compiler goes: Okay, x takes ints. x += 5 # Compiler: No prob,
> int += int --> int x = str(x) # Compiler: NO WAY! str(int) --> str, not
> allowed!
> 
> It's fine and correct to infer that x is an int, x is an int, x is a
> str. It's *not* okay to make the third line a SyntaxError because you
> just put a str into an int variable.

It won't be a Syntax Error, it will be a compile-time Type Error. And, 
yes, it is fine. That's the point of static typing! The tradeoff of being 
able to detect a whole lot of errors *at compile time* is that you give 
up the ability to re-use the same variable for different types in a 
single scope. (You can have an x which is a string elsewhere, just not in 
this scope where it is an int.)

It's okay if you personally prefer the flexibility and freedom of dynamic 
typing. The cost of this choice is that you become responsible for 
writing unit tests that ensure that code behaves safely when given 
unexpected types. If you choose static typing instead, you get a whole 
lot of error checking done at compile time, and likely a lot of compiler 
optimizations. But the cost is that you can't write:

x = 23
x += 5
x = str(x)

and instead have to write:

x = 23
x += 5
s = str(x)


You should, I think, read this:

http://cdsmith.wordpress.com/2011/01/09/an-old-article-i-wrote/


[...]
>> That's not type inference. That's ancient and annoying obligatory type
>> declarations as used by ancient languages with primitive type systems,
>> like Pascal and C.
> 
> And that's exactly what Haskell apparently has, with homogeneous lists
> and no easy way to say that it can take more types.

That Haskell has homogeneous lists is not a property of the type system, 
but a design choice. I'm sure Haskell will also have a tuple or record 
type that allows fields of different types.


> Python's handling is: A list can hold anything.
[...]
> Haskell's handling apparently is: A list/array can hold one thing and
> one thing only. That 'thing' can be a union, but then you need to be
> REALLY explicit about which side is which. 

Yes. 


> It's not possible to
> sub-specify a type (like the "string('a'..'x')" type in Pike that will
> take only strings with nothing but the first 24 lower-case letters - not
> that I've ever needed that), but the compiler can work out everything
> else.

I have not used Haskell enough to tell you whether you can specify 
subtypes. I know that, at least for numeric (integer) types, venerable 
old Pascal allows you to define subtypes based on integer ranges, so I'd 
be surprised if you couldn't do the same thing in Haskell.

The flexibility of the type system -- its ability to create subtypes and 
union types -- is independent of whether it is explicitly declared or 
uses type inference.


> The way I see it, Python's form is fully dynamic and open, Pike's is
> fully dynamic and the programmer's allowed to explicitly close things,
> and Haskell's is rigidly tight. That's not to say that tight is a bad
> thing (it's probably good for learning under), but personally, I'd
> rather have the freedom.

Hey, I'm a Python programmer! You don't have to sell me on the benefits 
of dynamic typing. Before Python, my language of choice was Apple's 
Hyperscript, which is untyped -- everything, and I mean everything, is a 
string in Hyperscript. It works remarkably well, so long as you don't 
care about speed. But even in the late 80s or early 1990s, on single-core 
CPUs running at a piddly 7.8 MHz (compared to about 1000 MHz for desktops 
today), you could get acceptable performance for a remarkable range of 
applications.

But don't be fooled, those benefits aren't free. Static typing has 
benefits too.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#67648

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 21:59 -0800
Message-ID<596a3756-808c-4d66-995f-a9db13effb9a@googlegroups.com>
In reply to#67646
On Tuesday, March 4, 2014 11:05:24 AM UTC+5:30, Steven D'Aprano wrote:
> On Tue, 04 Mar 2014 05:37:27 +1100, Chris Angelico wrote:

> > It's not possible to
> > sub-specify a type (like the "string('a'..'x')" type in Pike that will
> > take only strings with nothing but the first 24 lower-case letters - not
> > that I've ever needed that), but the compiler can work out everything
> > else.

> I have not used Haskell enough to tell you whether you can specify 
> subtypes. I know that, at least for numeric (integer) types, venerable 
> old Pascal allows you to define subtypes based on integer ranges, so I'd 
> be surprised if you couldn't do the same thing in Haskell.

Its a bit murkier. See
http://lambda-the-ultimate.org/node/4771

Especially see the scala choices comment

Also this comment by Peyton Jones is telling

Damas-Milner* is on a cusp: 
Can infer most-general types without any type annotations at all
But virtually any extension destroys this property

from www.cs.nott.ac.uk/~gmh/appsem-slides/peytonjones.ppt

* The functional programming type inference algorithm

[toc] | [prev] | [next] | [standalone]


#67649

FromChris Angelico <rosuav@gmail.com>
Date2014-03-04 17:04 +1100
Message-ID<mailman.7695.1393913099.18130.python-list@python.org>
In reply to#67646
On Tue, Mar 4, 2014 at 4:35 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> On Tue, 04 Mar 2014 05:37:27 +1100, Chris Angelico wrote:
>> x = 23 # Compiler goes: Okay, x takes ints. x += 5 # Compiler: No prob,
>> int += int --> int x = str(x) # Compiler: NO WAY! str(int) --> str, not
>> allowed!
>>
>> It's fine and correct to infer that x is an int, x is an int, x is a
>> str. It's *not* okay to make the third line a SyntaxError because you
>> just put a str into an int variable.
>
> It won't be a Syntax Error, it will be a compile-time Type Error. And,
> yes, it is fine. That's the point of static typing! The tradeoff of being
> able to detect a whole lot of errors *at compile time* is that you give
> up the ability to re-use the same variable for different types in a
> single scope. (You can have an x which is a string elsewhere, just not in
> this scope where it is an int.)

Okay, a compile-type type error, same difference. What I'm saying is
that the auto-detection can't know what else you plan to do. If you
explicitly say that this is an int, then yes, that should be
disallowed; if you explicitly say that it's either an int or a float,
then you should be able to have either, but not a string. (C does this
with explicitly tagged unions, usually. Python and Pike do it by
simply allowing multiple types in the same slot.)

> That Haskell has homogeneous lists is not a property of the type system,
> but a design choice. I'm sure Haskell will also have a tuple or record
> type that allows fields of different types.

If it's not the list type, pick some other. It's not uncommon to want
to have a record that has different types (C does this with struct,
C++ has a few more ways to do it); what I'm finding odd is that
whatever goes into it first is specifying for everything else.

> I have not used Haskell enough to tell you whether you can specify
> subtypes. I know that, at least for numeric (integer) types, venerable
> old Pascal allows you to define subtypes based on integer ranges, so I'd
> be surprised if you couldn't do the same thing in Haskell.
>
> The flexibility of the type system -- its ability to create subtypes and
> union types -- is independent of whether it is explicitly declared or
> uses type inference.

I'm not sure how you could have type inference with subtypes. How does
the compiler figure out what subtype of integers is acceptable, such
that it can reject some?

x = 5
x = 7
x = 11
x = 17
x = 27

Should the last one be rejected because it's not prime? How can it
know that I actually wanted that to be int(3..20)? That's why I see
them as connected. All sorts of flexibilities are possible when the
programmer explicitly tells the compiler what the rules are.

> Hey, I'm a Python programmer! You don't have to sell me on the benefits
> of dynamic typing. Before Python, my language of choice was Apple's
> Hyperscript, which is untyped -- everything, and I mean everything, is a
> string in Hyperscript. It works remarkably well, so long as you don't
> care about speed. But even in the late 80s or early 1990s, on single-core
> CPUs running at a piddly 7.8 MHz (compared to about 1000 MHz for desktops
> today), you could get acceptable performance for a remarkable range of
> applications.
>
> But don't be fooled, those benefits aren't free. Static typing has
> benefits too.

For me, that untyped language was REXX. One data type (the string),
and a special feature of variable names to handle what most people
would do with arrays/lists/mappings/dicts/etc/etc/etc. (Or, of course,
you do what you'd presumably do in Hyperscript, and implement an array
of words as a string that you separate on ' '. VX-REXX had a neat
'initializer format' where you simply prefix every element with the
separator - that is to say, the first character of the string is the
separator. It nests perfectly and is pretty convenient to type. A
little obscure for most people, though.) Was also my first taste of
arbitrary-precision arithmetic. C could cream it as long as I didn't
need anything over 2**32 or anything I can't do in a double-precision
float, but I could calculate 200! with clean brute-force code and it'd
work perfectly.

Static and dynamic typing both have their uses. But when I use static
typing, I want to specify the types myself. I'm aware that's a matter
of opinion, but I don't like the idea of the compiler rejecting code
based on inferred types.

ChrisA

[toc] | [prev] | [next] | [standalone]


#67650

FromRustom Mody <rustompmody@gmail.com>
Date2014-03-03 22:20 -0800
Message-ID<c5987af5-fc51-435a-a161-9a258c1f97d6@googlegroups.com>
In reply to#67649
On Tuesday, March 4, 2014 11:34:55 AM UTC+5:30, Chris Angelico wrote:
> On Tue, Mar 4, 2014 at 4:35 PM, Steven D'Aprano wrote:
> > I have not used Haskell enough to tell you whether you can specify
> > subtypes. I know that, at least for numeric (integer) types, venerable
> > old Pascal allows you to define subtypes based on integer ranges, so I'd
> > be surprised if you couldn't do the same thing in Haskell.
> > The flexibility of the type system -- its ability to create subtypes and
> > union types -- is independent of whether it is explicitly declared or
> > uses type inference.

> I'm not sure how you could have type inference with subtypes.

Short answer: You cant [Yeah Some folks dont like my short answers :-) ]

Long answer: See the links I posted above

Intermediate answer:
Types (for a modern FPL) are like math sets except that:
- set-membership is in general hard and in principle undecidable
- type-membership had better be decidable and preferably linear-time if its 
to be part of an implementation (and not a philosophical discussion over a cuppa
chai)
- Which means that...

> Static and dynamic typing both have their uses. But when I use static
> typing, I want to specify the types myself. I'm aware that's a matter
> of opinion, but I don't like the idea of the compiler rejecting code
> based on inferred types.

...Type inference is strictly (aka mathematically) syntax even though
in the implementation, the parsing phase and the type checking/inferencing phase
are sequenced

In short: An important flavor of the FP koolaid is the Damas-Milner
type-inferencing algorithm. Damas-Milner + Subtyping is the recipe for
a severe headache -- An important reason why FP and OOP are incompatible

[toc] | [prev] | [next] | [standalone]


#67652

FromSteven D'Aprano <steve@pearwood.info>
Date2014-03-04 08:56 +0000
Message-ID<53159540$0$2923$c3e8da3$76491128@news.astraweb.com>
In reply to#67649
On Tue, 04 Mar 2014 17:04:55 +1100, Chris Angelico wrote:

> On Tue, Mar 4, 2014 at 4:35 PM, Steven D'Aprano <steve@pearwood.info>
> wrote:
>> On Tue, 04 Mar 2014 05:37:27 +1100, Chris Angelico wrote:
>>> x = 23 # Compiler goes: Okay, x takes ints. x += 5 # Compiler: No
>>> prob, int += int --> int x = str(x) # Compiler: NO WAY! str(int) -->
>>> str, not allowed!
>>>
>>> It's fine and correct to infer that x is an int, x is an int, x is a
>>> str. It's *not* okay to make the third line a SyntaxError because you
>>> just put a str into an int variable.
>>
>> It won't be a Syntax Error, it will be a compile-time Type Error. And,
>> yes, it is fine. That's the point of static typing! The tradeoff of
>> being able to detect a whole lot of errors *at compile time* is that
>> you give up the ability to re-use the same variable for different types
>> in a single scope. (You can have an x which is a string elsewhere, just
>> not in this scope where it is an int.)
> 
> Okay, a compile-type type error, same difference. What I'm saying is
> that the auto-detection can't know what else you plan to do. 

Obviously it can't see the code you haven't written yet, but it can see 
what you *do* do.


> If you
> explicitly say that this is an int, then yes, that should be disallowed;

It's that "explicitly" part that doesn't follow. Having to manage types 
is the most tedious, boring, annoying, *unproductive* part of languages 
like Java, C and Pascal. Almost always, you're telling the compiler stuff 
that it can work out for itself.

In the same way that managing jumps for GOTO has been automated with for 
loops, while, etc., and managing memory has been automated, there's no 
good reason not to allow the compiler to manage types. Dynamically typed 
languages like Python do so at runtime. Type inference simply allows 
statically typed languages to do the same only at compile time.


[...]
>> That Haskell has homogeneous lists is not a property of the type
>> system, but a design choice. I'm sure Haskell will also have a tuple or
>> record type that allows fields of different types.
> 
> If it's not the list type, pick some other. It's not uncommon to want to
> have a record that has different types (C does this with struct, C++ has
> a few more ways to do it); what I'm finding odd is that whatever goes
> into it first is specifying for everything else.

That's because in Haskell the design was made that lists *must* be used 
for homogeneous data. If you read Python documentation from back in the 
1.5 and early 2.x days, there was a *very* strong recommendation that 
lists be used for homogeneous data only and tuples for heterogeneous 
data. This recommendation goes all the way up to Guido.

# Yes
[1, 3, 4, 2, 5, 9]
(1, "hello", None, 3.5)

# No
[1, "hello", None, 3.5]


That is, lists are for collections of data of arbitrary length, tuples 
are for records or structs with dedicated fields.

That convention is a bit weaker these days than it used to be. Tuples now 
have list-like methods, and we have namedtuple for record/struct-like 
objects with named fields. But still, it is normal to use lists with 
homogeneous data, where there is an arbitrary number of "things" with 
different values, but all the same kind of thing.

In the case of Haskell, that's more than a mere convention, it's a rule, 
but that's not terribly different from (say) Pascal where you can have an 
array of integer but not an array of integer-or-real.

The thing is though, how often do you really have a situation where you 
have a bunch of arbitrary data, or unknown length, where you don't know 
what type of data it is? Sure, in the interactive interpreter it is 
useful to be able to write

[1, "spam", None, [], {}, 0.1, set()]

and I write unit tests with that sort of thing all the time:

for obj in list_of_arbitrary_objects:
    self.assertRaises(TypeError, func, obj)

kind of thing. But that doesn't have to be a *list*. It just needs to 
have convenient syntax.


>> I have not used Haskell enough to tell you whether you can specify
>> subtypes. I know that, at least for numeric (integer) types, venerable
>> old Pascal allows you to define subtypes based on integer ranges, so
>> I'd be surprised if you couldn't do the same thing in Haskell.
>>
>> The flexibility of the type system -- its ability to create subtypes
>> and union types -- is independent of whether it is explicitly declared
>> or uses type inference.
> 
> I'm not sure how you could have type inference with subtypes. How does
> the compiler figure out what subtype of integers is acceptable, such
> that it can reject some?

You seem to be under the impression that type inference means "guess what 
the programmer wants", or even "read the programmer's mind". Take this 
example:

> x = 5
> x = 7
> x = 11
> x = 17
> x = 27
> 
> Should the last one be rejected because it's not prime? How can it know
> that I actually wanted that to be int(3..20)? 

It can't, of course, any more than I could, or anyone other than you. But 
if you asked a hundred people what all those values of x had in common, 
93 of them would say "they're all integers", 6 would say "they're all 
positive integers", and 1 would say "they're all positive odd integers".

[Disclaimer: percentages plucked out of thin air.]

No type system can, or should, try to guess whatever bizarre subtype you 
*might* want. ("Only numbers spelled with the letter V.") If you want 
something stupid^W weird^W unusual, it's your responsibility to work 
within the constraints of the programming language to get that, whether 
you are using Python, Pascal or Haskell.


> That's why I see them as
> connected. All sorts of flexibilities are possible when the programmer
> explicitly tells the compiler what the rules are.

And you can still do that, *when you need to*. Assuming the type system 
has a way of specifying "integers that include the letter V", you can 
specify it when you want it. 


> Static and dynamic typing both have their uses. But when I use static
> typing, I want to specify the types myself. I'm aware that's a matter of
> opinion, but I don't like the idea of the compiler rejecting code based
> on inferred types.

Well, so long as you admit it's an irrational preference :-)

The bottom line is, if the compiler rejects code, it's because it has a 
bug. There's *no difference* between the compiler telling you that you 
can't add a string and an int when you've explicitly declared the types, 
and the compiler telling you that you can't add a string and an int when 
it has determined for itself that they are the types because that's all 
that they can be.




-- 
Steven

[toc] | [prev] | [next] | [standalone]


#67658

FromAntoon Pardon <antoon.pardon@rece.vub.ac.be>
Date2014-03-04 11:56 +0100
Message-ID<mailman.7700.1393930643.18130.python-list@python.org>
In reply to#67652
Op 04-03-14 09:56, Steven D'Aprano schreef:

>
>
>> If you
>> explicitly say that this is an int, then yes, that should be disallowed;
> It's that "explicitly" part that doesn't follow. Having to manage types 
> is the most tedious, boring, annoying, *unproductive* part of languages 
> like Java, C and Pascal. Almost always, you're telling the compiler stuff 
> that it can work out for itself.

In the same way writing unit tests is the most tedious, boring, annoying,
*unproductive* part. Amost always you are giving the program results
it can work out for itself.

-- 

Antoon Pardon

[toc] | [prev] | [next] | [standalone]


#67664

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-03-04 11:47 +0000
Message-ID<5315bd68$0$29985$c3e8da3$5496439d@news.astraweb.com>
In reply to#67658
On Tue, 04 Mar 2014 11:56:07 +0100, Antoon Pardon wrote:

> Op 04-03-14 09:56, Steven D'Aprano schreef:
> 
> 
>>
>>> If you
>>> explicitly say that this is an int, then yes, that should be
>>> disallowed;
>> It's that "explicitly" part that doesn't follow. Having to manage types
>> is the most tedious, boring, annoying, *unproductive* part of languages
>> like Java, C and Pascal. Almost always, you're telling the compiler
>> stuff that it can work out for itself.
> 
> In the same way writing unit tests is the most tedious, boring,
> annoying, *unproductive* part. 

Actually, I like writing unit tests. How do you know what the function 
does until you test it? I'm not a TDD fanatic, but often I write tests 
before I write the code, and there's really nothing nicer than seeing a 
whole lot of failing unit tests suddenly start working.

Well, maybe a nice BLT sandwich, when the bacon is nice and lean and the 
lettuce crisp and the tomato flavourful and not too soggy. But other than 
that, writing unit tests and seeing them pass is great.

On the other hand, writing

    int n, m
    double x, y

and similar three hundred times throughout your program is not terribly 
exciting. Even when it compiles, it doesn't mean it works.

> Amost always you are giving the program 
> results it can work out for itself.

Not even close. I'd like to see the compiler that can work out for itself 
that this function is buggy:

def sine_rule(side_a, side_b, angle_a):
    """Return the angle opposite side_b."""
    return math.sin(side_b/side_a)*angle_a


If you don't remember your Sine Rule from trigonometry, that's okay. 
Trust me, the function is badly wrong. It's rubbish really. But short of 
some really impressive AI coupled with a Mathematica-level of maths 
knowledge, how is the compiler supposed to know that?

Static type testing, while valuable, cannot tell you that the program 
does what you wanted it to do.



-- 
Steven D'Aprano
http://import-that.dreamwidth.org/

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | comp.lang.python


csiph-web