Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1.  Collapsing multiple case branches? (Colin Paul Adams)
   2. Re:  Collapsing multiple case branches? (Thomas Davie)
   3. Re:  Collapsing multiple case branches? (Colin Paul Adams)
   4. Re:  Collapsing multiple case branches? (Alexander Dunlap)
   5.  Re: [Haskell-cafe] represent data sturcture      using function
      (Ryan Ingram)
   6.  Re: [Haskell-cafe] represent data sturcture      using function
      (Ryan Ingram)
   7.  Re: [Haskell-cafe] represent data sturcture      using function
      (Ryan Ingram)


----------------------------------------------------------------------

Message: 1
Date: Sat, 03 Jan 2009 19:56:07 +0000
From: Colin Paul Adams <[email protected]>
Subject: [Haskell-beginners] Collapsing multiple case branches?
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii

I have the following function:

northern_range:: Piece_type -> Int
northern_range piece =
    case piece of
      Lance -> 11
      Reverse_chariot -> 11
      Vertical_mover -> 11
      White_horse -> 11
      Rook -> 11
      Promoted_rook -> 11
      Promoted_gold_general -> 11
      Promoted_silver_general -> 11
      Free_king -> 11
      Promoted_phoenix -> 11
      Flying_stag -> 11
      Flying_ox -> 11
      Whale -> 11
      Dragon_king -> 11
      Soaring_eagle -> 11
      Bishop -> 0
      Kylin -> 0
      Lion -> 0
      Promoted_kylin -> 0
      Blind_tiger -> 0
      Promoted_ferocious_leopard -> 0
      Free_boar -> 0
      Horned_falcon -> 0
      _ -> 1

I'd prefer to write this as just three lines (one for each of the
three resulting values), something like this:

northern_range:: Piece_type -> Int
northern_range piece =
    case piece of
      Lance, Reverse_chariot, Vertical_mover, etc. -> 11
      Bishop, Kylin, etc. -> 0
      _ -> 1

Is there some syntax to do this sort of thing?
-- 
Colin Adams
Preston Lancashire


------------------------------

Message: 2
Date: Sat, 3 Jan 2009 21:04:49 +0100
From: Thomas Davie <[email protected]>
Subject: Re: [Haskell-beginners] Collapsing multiple case branches?
To: Colin Paul Adams <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=WINDOWS-1252; format=flowed;
        delsp=yes

Hi Colin,

northernRange :: PieceType > Int -- note the camel case, that's  
traditional in Haskell circles
northernRange p
   | p `elem` [Lance, ReverseChariot, VerticalMover ....] = 11
   | p `elem` [Bishop, Kylin,....] = 0
   | otherwise = 1

These are called "pattern guards" – you can put any boolean expression  
in them.

Of note, if you provide an Enum instance for PieceType you may really  
be able to do this:

northernRange p
   | p `elem` [Lance..SoaringEagle] = 11
   | p `elem` [Bishop..HornedFalcon] = 0
   | otherwise = 1

Finally, my guess is that you probably want a much more general type  
for PieceType that doesn't need extended every time you add a Piece to  
your game (and similarly doesn't need every function in your program  
extended at the same time).  Perhaps something like this:

data Piece = Piece { name :: String, northernRange :: Int }

With elements like:

lance = Piece "Lance" 11

or like:

reverseChariot = Piece {name = "Reverse chariot", northernRange = 11}


Bob

On 3 Jan 2009, at 20:56, Colin Paul Adams wrote:

> I have the following function:
>
> northern_range:: Piece_type -> Int
> northern_range piece =
>    case piece of
>      Lance -> 11
>      Reverse_chariot -> 11
>      Vertical_mover -> 11
>      White_horse -> 11
>      Rook -> 11
>      Promoted_rook -> 11
>      Promoted_gold_general -> 11
>      Promoted_silver_general -> 11
>      Free_king -> 11
>      Promoted_phoenix -> 11
>      Flying_stag -> 11
>      Flying_ox -> 11
>      Whale -> 11
>      Dragon_king -> 11
>      Soaring_eagle -> 11
>      Bishop -> 0
>      Kylin -> 0
>      Lion -> 0
>      Promoted_kylin -> 0
>      Blind_tiger -> 0
>      Promoted_ferocious_leopard -> 0
>      Free_boar -> 0
>      Horned_falcon -> 0
>      _ -> 1
>
> I'd prefer to write this as just three lines (one for each of the
> three resulting values), something like this:
>
> northern_range:: Piece_type -> Int
> northern_range piece =
>    case piece of
>      Lance, Reverse_chariot, Vertical_mover, etc. -> 11
>      Bishop, Kylin, etc. -> 0
>      _ -> 1
>
> Is there some syntax to do this sort of thing?
> -- 
> Colin Adams
> Preston Lancashire
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners



------------------------------

Message: 3
Date: Sat, 03 Jan 2009 20:11:44 +0000
From: Colin Paul Adams <[email protected]>
Subject: Re: [Haskell-beginners] Collapsing multiple case branches?
To: Thomas Davie <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8

>>>>> "Thomas" == Thomas Davie <[email protected]> writes:

    Thomas> Hi Colin, northernRange :: PieceType > Int -- note the
    Thomas> camel case, that's traditional in Haskell circles

I know, but I find it vile.

    Thomas> northernRange p | p `elem` [Lance, ReverseChariot,
    Thomas> VerticalMover ....] = 11 | p `elem` [Bishop, Kylin,....] =
    Thomas> 0 | otherwise = 1

    Thomas> These are called "pattern guards" – you can put any
    Thomas> boolean expression in them.

Ah, thanks, that will do nicely.

    Thomas> Of note, if you provide an Enum instance for PieceType you
    Thomas> may really be able to do this:

    Thomas> northernRange p | p `elem` [Lance..SoaringEagle] = 11 | p
    Thomas> `elem` [Bishop..HornedFalcon] = 0 | otherwise = 1

I thought of that, but there are additional functions to do where the
required ordering would be different.

    Thomas> Finally, my guess is that you probably want a much more
    Thomas> general type for PieceType that doesn't need extended
    Thomas> every time you add a Piece to your game (and similarly
    Thomas> doesn't need every function in your program extended at
    Thomas> the same time).  Perhaps something like this:

    Thomas> data Piece = Piece { name :: String, northernRange ::
    Thomas> Int }

A reasonable guess, but as the pieces types are fixed (it's an ancient
game) I preferred to write it this way.

BTW is this (as it looks to me) a classic space-time trade-off?
-- 
Colin Adams
Preston Lancashire


------------------------------

Message: 4
Date: Sat, 3 Jan 2009 12:33:36 -0800
From: "Alexander Dunlap" <[email protected]>
Subject: Re: [Haskell-beginners] Collapsing multiple case branches?
To: "Thomas Davie" <[email protected]>
Cc: [email protected]
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=WINDOWS-1252

On Sat, Jan 3, 2009 at 12:04 PM, Thomas Davie <[email protected]> wrote:
> Hi Colin,
...snip...
> These are called "pattern guards" – you can put any boolean expression in
> them.
...snip...

Technically, those are just called "guards." "Pattern guards" are when
you also bind a pattern; it's a GHC extension. They look like this,
for example:

foo x
  | Just y <- bar x = y + 1 -- this is the pattern guard. If bar x can
be matched with Just y, then y is bound and that guard path is taken.
Otherwise, evaluation falls through to the next guard option.
  | otherwise = 0

Alex


------------------------------

Message: 5
Date: Mon, 29 Dec 2008 01:48:50 -0800
From: "Ryan Ingram" <[email protected]>
Subject: [Haskell-beginners] Re: [Haskell-cafe] represent data
        sturcture       using function
To: "David Menendez" <[email protected]>
Cc: Raeck chiu <[email protected]>, Beginners Haskell
        <[email protected]>,        Cafe Haskell <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

On Sun, Dec 28, 2008 at 10:13 PM, David Menendez <[email protected]> wrote:
> 2008/12/29 Raeck chiu <[email protected]>:
>> It seems to be very difficult to change the number of Male or Female if a
>> concrete data structure is not used. Is it possible change the number of 
>> Male in classA
>> when represent classA using function?
>
> Here's the simplest way:
>
>    update k v map = \k' -> if k' == k then v else map k'
>
> Note that it requires an Eq instance for Sex.
>
>    let classA' = update Male 150 classA
>    in (classA' Male, classA' Female)
> =
>    (150,200)

Of course this version of update leaks crazy amounts of memory:

> let bigmap = iterate (update Male 150) classA !! 100000
> bigmap Male

"bigmap" leaves a huge chain of thunks pointing at each other, which
can never be freed.

Using functions is mathematically more elegant than some concrete data
structure (which might require Eq or Ord or other constraints, and
have multiple observable representations for the same map, or have
maps that don't include every element).

However, "generic maps" have been improving a lot recently, especially
with data families in the new GHC.   You use an abstract type (k :->
v) to represent the map; this type is semantically equivalent to (k ->
v) via some observation function for generic maps, but has a compact
representation.  For example:

> class MapKey k where
>    data k :-> v
>    newMap :: (k -> v) -> (k :-> v)
>    fetch :: (k :-> v) -> (k -> v)
>    update :: (k,v) -> (k :-> v) -> (k :-> v)
>    empty :: v -> (k :-> v)
>    empty = newMap (const v)

> instance MapKey Bool where
>    data Bool :-> v = BoolMap v v
>    newMap f = BoolMap (f False) (f True)
>    fetch (Boolmap t f) v = if v then t else f
>    update (True, t) (BoolMap _ f) = Boolmap t f
>    update (False, f) (BoolMap t _) = Boolmap t f

"fetch" converts this representation of a total function over k, into
an actual function.  The representation of k :-> v might vary
depending on k; Int might use IntMap, (k1,k2) can compose maps:

> instance (MapKey k1, MapKey k2) => MapKey (k1,k2) where
>    newtype (k1,k2) :-> v = PairMap (k1 :-> (k2 :-> v))
>    ...

> instance (MapKey k1, MapKey k2) => MapKey (Either k1 k2) where
>    data (Either k1 k2) :-> v = EitherMap (k1 :-> v) (k2 :-> v)
>    ...

This gives you the same benefits as the function approach but without
the terrible performance issues.  You do need to write instances for
your types, though, although most can be easily derived from the
instances for pairs, Either, and Integer.

See http://www.haskell.org/haskellwiki/GHC/Indexed_types for more.

  -- ryan


------------------------------

Message: 6
Date: Mon, 29 Dec 2008 15:15:38 -0800
From: "Ryan Ingram" <[email protected]>
Subject: [Haskell-beginners] Re: [Haskell-cafe] represent data
        sturcture       using function
To: [email protected], [email protected], [email protected]
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Dec 29, 2008 at 4:29 AM,  <[email protected]> wrote:
> Would you please give me a complete example of code that I could have more
> information
> on the idea?

Sure, I put up an example at http://ryani.freeshell.org/haskell/gmap.hs

class MapKey k where
    data (:->) k :: * -> *
    newMap :: (k -> v) -> (k :-> v)
    fetch  :: (k :-> v) -> (k -> v)
    update :: k -> (v -> v) -> (k :-> v) -> (k :-> v)
    assign :: k -> v -> (k :-> v) -> (k :-> v)
    assign k v m = update k (const v) m
    empty  :: v -> (k :-> v)
    empty = newMap . const

with instances & associated data types:

instance MapKey () where
    -- A single value
    newtype () :-> v = UMap v

instance MapKey Bool where
    -- A value for False and True
    data Bool :-> v = BMap v v

instance (MapKey k1, MapKey k2) => MapKey (k1,k2) where
    -- A "curried" map
    newtype (k1,k2) :-> v = PMap (k1 :-> k2 :-> v)

instance (MapKey k1, MapKey k2) => MapKey (Either k1 k2) where
    -- sub-maps for Left k1 and Right k2
    data (Either k1 k2 :-> v) = EMap (k1 :-> v) (k2 :-> v)

instance MapKey k => MapKey (Maybe k) where
    -- Now we can build up from existing structures!
    newtype (Maybe k) :-> v = MaybeM (Either () k :-> v)

instance MapKey k => MapKey [k] where
    -- Value for [] and map for (head:tail)
    --
    -- Note that this includes a recursive ([k] :-> v) map
    -- in the pair map (k,[k]) :-> v
    data [k] :-> v = ListM v ((k,[k]) :-> v)

instance MapKey Positive where
    -- We just convert a positive number into
    -- a list of Bools, then make a map of those
    newtype Positive :-> v = PosMap ([Bool] :-> v)

instance MapKey Integer where
    -- Now an integer is either negative, zero, or positive.
    -- So we store a map for negative numbers, a zero value,
    -- and a map for positive numbers.
    data Integer :-> v = IntMap (Positive :-> v) v (Positive :-> v)

The rest of the class functions are reasonably easy to derive from
their type and these data types.

  -- ryan


------------------------------

Message: 7
Date: Mon, 29 Dec 2008 01:50:02 -0800
From: "Ryan Ingram" <[email protected]>
Subject: [Haskell-beginners] Re: [Haskell-cafe] represent data
        sturcture       using function
To: "David Menendez" <[email protected]>
Cc: Raeck chiu <[email protected]>, Beginners Haskell
        <[email protected]>,        Cafe Haskell <[email protected]>
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1

Bonus points if you find the stupid bug in my code :)

  -- ryan

On Mon, Dec 29, 2008 at 1:48 AM, Ryan Ingram <[email protected]> wrote:
> On Sun, Dec 28, 2008 at 10:13 PM, David Menendez <[email protected]> wrote:
>> 2008/12/29 Raeck chiu <[email protected]>:
>>> It seems to be very difficult to change the number of Male or Female if a
>>> concrete data structure is not used. Is it possible change the number of 
>>> Male in classA
>>> when represent classA using function?
>>
>> Here's the simplest way:
>>
>>    update k v map = \k' -> if k' == k then v else map k'
>>
>> Note that it requires an Eq instance for Sex.
>>
>>    let classA' = update Male 150 classA
>>    in (classA' Male, classA' Female)
>> =
>>    (150,200)
>
> Of course this version of update leaks crazy amounts of memory:
>
>> let bigmap = iterate (update Male 150) classA !! 100000
>> bigmap Male
>
> "bigmap" leaves a huge chain of thunks pointing at each other, which
> can never be freed.
>
> Using functions is mathematically more elegant than some concrete data
> structure (which might require Eq or Ord or other constraints, and
> have multiple observable representations for the same map, or have
> maps that don't include every element).
>
> However, "generic maps" have been improving a lot recently, especially
> with data families in the new GHC.   You use an abstract type (k :->
> v) to represent the map; this type is semantically equivalent to (k ->
> v) via some observation function for generic maps, but has a compact
> representation.  For example:
>
>> class MapKey k where
>>    data k :-> v
>>    newMap :: (k -> v) -> (k :-> v)
>>    fetch :: (k :-> v) -> (k -> v)
>>    update :: (k,v) -> (k :-> v) -> (k :-> v)
>>    empty :: v -> (k :-> v)
>>    empty = newMap (const v)
>
>> instance MapKey Bool where
>>    data Bool :-> v = BoolMap v v
>>    newMap f = BoolMap (f False) (f True)
>>    fetch (Boolmap t f) v = if v then t else f
>>    update (True, t) (BoolMap _ f) = Boolmap t f
>>    update (False, f) (BoolMap t _) = Boolmap t f
>
> "fetch" converts this representation of a total function over k, into
> an actual function.  The representation of k :-> v might vary
> depending on k; Int might use IntMap, (k1,k2) can compose maps:
>
>> instance (MapKey k1, MapKey k2) => MapKey (k1,k2) where
>>    newtype (k1,k2) :-> v = PairMap (k1 :-> (k2 :-> v))
>>    ...
>
>> instance (MapKey k1, MapKey k2) => MapKey (Either k1 k2) where
>>    data (Either k1 k2) :-> v = EitherMap (k1 :-> v) (k2 :-> v)
>>    ...
>
> This gives you the same benefits as the function approach but without
> the terrible performance issues.  You do need to write instances for
> your types, though, although most can be easily derived from the
> instances for pairs, Either, and Integer.
>
> See http://www.haskell.org/haskellwiki/GHC/Indexed_types for more.
>
>  -- ryan
>


------------------------------

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 7, Issue 3
***************************************

Reply via email to