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


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

Haskell -> Python

Started byfoster63@gmail.com
First post2012-11-02 12:19 -0700
Last post2012-11-03 22:16 -0700
Articles 10 — 6 participants

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


Contents

  Haskell -> Python foster63@gmail.com - 2012-11-02 12:19 -0700
    Re: Haskell -> Python Dave Angel <d@davea.name> - 2012-11-02 15:56 -0400
      Re: Haskell -> Python Simon Foster <simon.foster@inbox.com> - 2012-11-02 20:09 +0000
    Re: Haskell -> Python Ian Kelly <ian.g.kelly@gmail.com> - 2012-11-02 15:40 -0600
      Re: Haskell -> Python Duncan Booth <duncan.booth@invalid.invalid> - 2012-11-03 16:29 +0000
    Re: Haskell -> Python Ian Kelly <ian.g.kelly@gmail.com> - 2012-11-02 15:46 -0600
    Re: Haskell -> Python Dave Angel <d@davea.name> - 2012-11-02 18:24 -0400
    Re: Haskell -> Python Ian Kelly <ian.g.kelly@gmail.com> - 2012-11-02 16:27 -0600
    Re: Haskell -> Python Dave Angel <d@davea.name> - 2012-11-02 22:03 -0400
    Re: Haskell -> Python aahz@pythoncraft.com (Aahz) - 2012-11-03 22:16 -0700

#32651 — Haskell -> Python

Fromfoster63@gmail.com
Date2012-11-02 12:19 -0700
SubjectHaskell -> Python
Message-ID<b19e3922-d86f-426f-afb8-1f75b793f87b@googlegroups.com>
Hi All,

As part of a Nim solver I'm playing around with I'm trying to code this Haskell snippet:

  options [x] = zero : [ [y] | y <- [1..x - 1] ]
  options (x:xs) = map (++ xs) (options [x]) ++ map (x:) (options xs)

in Python.  So far I have this, which works OK, but somehow doesn't feel right:

def options( heaps ):

    if heaps == []: return []
    
    head, tail = heaps[:1], heaps[1:]
    
    # Calculate all possible moves which is the sum of 
    # prepending all possible head "moves" to the tail 
    # and appending all possible tail "moves" to the head
    
    return [ [h] + tail for h in range( head[0] ) ] \
         + [ head + t   for t in options( tail )  ]

Is there anything anyone could recommend to make it more "Pythonic" or more functional.  It looks clumsy next to the Haskell.

Regards

etc.

[toc] | [next] | [standalone]


#32654

FromDave Angel <d@davea.name>
Date2012-11-02 15:56 -0400
Message-ID<mailman.3217.1351886225.27098.python-list@python.org>
In reply to#32651
On 11/02/2012 03:19 PM, foster63@gmail.com wrote:
> Hi All,
>
> As part of a Nim solver I'm playing around with I'm trying to code this Haskell snippet:
>
>   options [x] = zero : [ [y] | y <- [1..x - 1] ]
>   options (x:xs) = map (++ xs) (options [x]) ++ map (x:) (options xs)
>
> in Python.  So far I have this, which works OK, but somehow doesn't feel right:
>
> def options( heaps ):
>
>     if heaps == []: return []
>     
>     head, tail = heaps[:1], heaps[1:]
>     
>     # Calculate all possible moves which is the sum of 
>     # prepending all possible head "moves" to the tail 
>     # and appending all possible tail "moves" to the head
>     
>     return [ [h] + tail for h in range( head[0] ) ] \
>          + [ head + t   for t in options( tail )  ]
>
> Is there anything anyone could recommend to make it more "Pythonic" or more functional.  It looks clumsy next to the Haskell.
>
> Regards
>
> etc.

You'd save people a lot of time if you'd specify that the parameter
heaps is a list of ints, perhaps initially [1,3,5,7]   or [3, 4, 5]
depending on which variation of Nim you're trying to.  There are many. 
One variant is that some versions of Nim say the winner is the player
who does NOT take the last piece.  I'll assume that the goal is to end
up with [0,0,0,0]

My main problem with studying your code is that brute force is totally
unnecessary;  there's a fairly simple strategy for winning at Nim. 
Certainly it's simple enough to have perfect strategy without any computer.

A "good" move is any one where the xor of all the items in the list ends
up as zero.  There is always at least one move for an "ungood" position
that results in a "good" one.  Thus the strategy is to go from good to
good, with the opponent always stuck on an ungood one.


-- 

DaveA

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


#32657

FromSimon Foster <simon.foster@inbox.com>
Date2012-11-02 20:09 +0000
Message-ID<1IWdnd9wkMbntQnNnZ2dnUVZ8ridnZ2d@brightview.co.uk>
In reply to#32654
On 02/11/12 19:56, Dave Angel wrote:
> On 11/02/2012 03:19 PM, foster63@gmail.com wrote:
>> Hi All,
>>
>> As part of a Nim solver I'm playing around with I'm trying to code this Haskell snippet:
>>
>>    options [x] = zero : [ [y] | y <- [1..x - 1] ]
>>    options (x:xs) = map (++ xs) (options [x]) ++ map (x:) (options xs)
>>
>> in Python.  So far I have this, which works OK, but somehow doesn't feel right:
>>
>> def options( heaps ):
>>
>>      if heaps == []: return []
>>
>>      head, tail = heaps[:1], heaps[1:]
>>
>>      # Calculate all possible moves which is the sum of
>>      # prepending all possible head "moves" to the tail
>>      # and appending all possible tail "moves" to the head
>>
>>      return [ [h] + tail for h in range( head[0] ) ] \
>>           + [ head + t   for t in options( tail )  ]
>>
>> Is there anything anyone could recommend to make it more "Pythonic" or more functional.  It looks clumsy next to the Haskell.
>>
>> Regards
>>
>> etc.
>
> You'd save people a lot of time if you'd specify that the parameter
> heaps is a list of ints, perhaps initially [1,3,5,7]   or [3, 4, 5]
> depending on which variation of Nim you're trying to.  There are many.
> One variant is that some versions of Nim say the winner is the player
> who does NOT take the last piece.  I'll assume that the goal is to end
> up with [0,0,0,0]
>
> My main problem with studying your code is that brute force is totally
> unnecessary;  there's a fairly simple strategy for winning at Nim.
> Certainly it's simple enough to have perfect strategy without any computer.
>
> A "good" move is any one where the xor of all the items in the list ends
> up as zero.  There is always at least one move for an "ungood" position
> that results in a "good" one.  Thus the strategy is to go from good to
> good, with the opponent always stuck on an ungood one.
>
>

Hi Dave,

Thanks for the comments.  Yes, I should have specified that the input is 
a list of ints giving the size of each heap, and the return value should 
be a list of all game positions reachable from the input position.

At the moment I'm not concentrating on any particular Nim flavour, just 
trying to enumerate all possible moves from a given position.

I know that there's an easier way to determine winning-losing positions, 
but my question was more about programming style than Nim strategy.

My code to calculate the "nim-value" looks like this:

def nim_val( heaps ):
     return functools.reduce( operator.xor, heaps, 0 )

Assuming that we're playing "non-misere" Nim then a zero nim-value is a 
lose for the player *about* to play.

Regards

Simon

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


#32661

FromIan Kelly <ian.g.kelly@gmail.com>
Date2012-11-02 15:40 -0600
Message-ID<mailman.3222.1351892486.27098.python-list@python.org>
In reply to#32651
On Fri, Nov 2, 2012 at 1:19 PM,  <foster63@gmail.com> wrote:
> Is there anything anyone could recommend to make it more "Pythonic" or more functional.  It looks clumsy next to the Haskell.

def options(heaps):
    for i, heap in enumerate(heaps):
        head = heaps[:i]
        tail = heaps[i+1:]
        yield from (head + [x] + tail for x in range(heap))

"yield from" is Python 3.3 syntax.  If you're not using Python 3.3,
then that line could be replaced by:

        for x in range(heap):
            yield head + [x] + tail

Cheers,
Ian

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


#32704

FromDuncan Booth <duncan.booth@invalid.invalid>
Date2012-11-03 16:29 +0000
Message-ID<XnsA100A7C85E1E5duncanbooth@127.0.0.1>
In reply to#32661
Ian Kelly <ian.g.kelly@gmail.com> wrote:

> On Fri, Nov 2, 2012 at 1:19 PM,  <foster63@gmail.com> wrote:
>> Is there anything anyone could recommend to make it more "Pythonic"
>> or more functional.  It looks clumsy next to the Haskell. 
> 
> def options(heaps):
>     for i, heap in enumerate(heaps):
>         head = heaps[:i]
>         tail = heaps[i+1:]
>         yield from (head + [x] + tail for x in range(heap))
> 
> "yield from" is Python 3.3 syntax.  If you're not using Python 3.3,
> then that line could be replaced by:
> 
>         for x in range(heap):
>             yield head + [x] + tail
> 
> Cheers,
> Ian

An alternative that is closer to foster63's original but still more 
"Pythonic" for some definitions of those words.

def options(heaps):
    if not heaps: return []
    head, *tail = heaps
    for h in range(head):
        yield [h]+tail
    for t in options(tail):
        yield [head]+t

For a more 'functional' version there is also the Python 3.3 variant:

def options(heaps):
    if not heaps: return []
    head, *tail = heaps
    yield from ([h]+tail for h in range(head))
    yield from ([head]+t for t in options(tail))

-- 
Duncan Booth http://kupuguy.blogspot.com

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


#32662

FromIan Kelly <ian.g.kelly@gmail.com>
Date2012-11-02 15:46 -0600
Message-ID<mailman.3223.1351892837.27098.python-list@python.org>
In reply to#32651
On Fri, Nov 2, 2012 at 3:40 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> On Fri, Nov 2, 2012 at 1:19 PM,  <foster63@gmail.com> wrote:
>> Is there anything anyone could recommend to make it more "Pythonic" or more functional.  It looks clumsy next to the Haskell.
>
> def options(heaps):
>     for i, heap in enumerate(heaps):
>         head = heaps[:i]
>         tail = heaps[i+1:]
>         yield from (head + [x] + tail for x in range(heap))
>
> "yield from" is Python 3.3 syntax.  If you're not using Python 3.3,
> then that line could be replaced by:
>
>         for x in range(heap):
>             yield head + [x] + tail

In fact, the more that I look at it, the more that I think the latter
might be preferable in any case.

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


#32669

FromDave Angel <d@davea.name>
Date2012-11-02 18:24 -0400
Message-ID<mailman.3225.1351895130.27098.python-list@python.org>
In reply to#32651
On 11/02/2012 05:40 PM, Ian Kelly wrote:
> On Fri, Nov 2, 2012 at 1:19 PM,  <foster63@gmail.com> wrote:
>> Is there anything anyone could recommend to make it more "Pythonic" or more functional.  It looks clumsy next to the Haskell.
> def options(heaps):
>     for i, heap in enumerate(heaps):
>         head = heaps[:i]
>         tail = heaps[i+1:]
>         yield from (head + [x] + tail for x in range(heap))
>
> "yield from" is Python 3.3 syntax.  If you're not using Python 3.3,
> then that line could be replaced by:
>
>         for x in range(heap):
>             yield head + [x] + tail
>
> Cheers,
> Ian
Perhaps range(heap) should be replaced by  range(len(heap))



-- 

DaveA

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


#32670

FromIan Kelly <ian.g.kelly@gmail.com>
Date2012-11-02 16:27 -0600
Message-ID<mailman.3226.1351895312.27098.python-list@python.org>
In reply to#32651
On Fri, Nov 2, 2012 at 4:24 PM, Dave Angel <d@davea.name> wrote:
> Perhaps range(heap) should be replaced by  range(len(heap))

"heaps" is a list of ints per the OP, so "heap" is an int.

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


#32679

FromDave Angel <d@davea.name>
Date2012-11-02 22:03 -0400
Message-ID<mailman.3229.1351908225.27098.python-list@python.org>
In reply to#32651
On 11/02/2012 06:27 PM, Ian Kelly wrote:
> On Fri, Nov 2, 2012 at 4:24 PM, Dave Angel <d@davea.name> wrote:
>> Perhaps range(heap) should be replaced by  range(len(heap))
> "heaps" is a list of ints per the OP, so "heap" is an int.

You're right of course <blush>.  I was distracted by the fact that a
heap is normally a collection of thing, and didn't notice that here it
is a count of those things.

-- 

DaveA

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


#32720

Fromaahz@pythoncraft.com (Aahz)
Date2012-11-03 22:16 -0700
Message-ID<k74tne$qrk$1@panix5.panix.com>
In reply to#32651
In article <b19e3922-d86f-426f-afb8-1f75b793f87b@googlegroups.com>,
 <foster63@gmail.com> wrote:
>
>def options( heaps ):
>
>    if heaps == []: return []
>    
>    head, tail = heaps[:1], heaps[1:]
>    
>    # Calculate all possible moves which is the sum of 
>    # prepending all possible head "moves" to the tail 
>    # and appending all possible tail "moves" to the head
>    
>    return [ [h] + tail for h in range( head[0] ) ] \
>         + [ head + t   for t in options( tail )  ]
>
>Is there anything anyone could recommend to make it more "Pythonic" or
>more functional.  It looks clumsy next to the Haskell.

If you want more Pythonic, follow PEP8 in your formatting.  ;-)
-- 
Aahz (aahz@pythoncraft.com)           <*>         http://www.pythoncraft.com/

"....Normal is what cuts off your sixth finger and your tail..."  --Siobhan

[toc] | [prev] | [standalone]


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


csiph-web