Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #67493 > unrolled thread
| Started by | Ned Batchelder <ned@nedbatchelder.com> |
|---|---|
| First post | 2014-03-02 20:27 -0500 |
| Last post | 2014-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.
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 →
| From | Ned Batchelder <ned@nedbatchelder.com> |
|---|---|
| Date | 2014-03-02 20:27 -0500 |
| Subject | Re: 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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Rustom Mody <rustompmody@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2014-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]
| From | Antoon Pardon <antoon.pardon@rece.vub.ac.be> |
|---|---|
| Date | 2014-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2014-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