Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Haskell-beginners] represent data sturcture using function

1 view
Skip to first unread message

Raeck chiu

unread,
Dec 29, 2008, 12:04:45 AM12/29/08
to Beginners Haskell, Cafe Haskell

Merry Christmas!
Hope everybody is enjoying the Christmas!

I am doing some readings and I found something seems to be interesting.

People sometime will try to represent a quantity-regard-only data structure
(such a order-regadless List) using functions instead of ta concrete data
structure (like the haskell build-in []), any particular reason for this?

For example,
> data Sex = Male | Female
> classA :: Sex -> Int
> classA Male = 100
> classA Female = 200

when I should prefer the above solution instead of using a concrete data structure
such as [] to represent the classA members?

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?

Thank you very much!

Best wishes,
Raeck


_________________________________________________________________
It’s the same Hotmail®. If by “same” you mean up to 70% faster.
http://windowslive.com/online/hotmail?ocid=TXT_TAGLM_WL_hotmail_acq_broad1_122008

David Menendez

unread,
Dec 29, 2008, 1:14:21 AM12/29/08
to Raeck chiu, Beginners Haskell, Cafe Haskell
2008/12/29 Raeck chiu <ra...@msn.com>:

> People sometime will try to represent a quantity-regard-only data structure
> (such a order-regadless List) using functions instead of ta concrete data
> structure (like the haskell build-in []), any particular reason for this?
>
> For example,
>> data Sex = Male | Female
>> classA :: Sex -> Int
>> classA Male = 100
>> classA Female = 200
>
> when I should prefer the above solution instead of using a concrete data
> structure such as [] to represent the classA members?

One important difference between Sex -> Int and [(Sex,Int)] is that
the first guarantees exactly one Int per Sex and has no underlying
order. (That is, [(Male,100),(Female,200)] and
[(Female,200),(Male,100)] are distinct lists but represent the same
map.)

> 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)

--
Dave Menendez <da...@zednenem.com>
<http://www.eyrie.org/~zednenem/>
_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Ryan Ingram

unread,
Dec 29, 2008, 4:49:18 AM12/29/08
to David Menendez, Raeck chiu, Beginners Haskell, Cafe Haskell
On Sun, Dec 28, 2008 at 10:13 PM, David Menendez <da...@zednenem.com> wrote:
> 2008/12/29 Raeck chiu <ra...@msn.com>:

>> 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

Ryan Ingram

unread,
Dec 29, 2008, 4:50:26 AM12/29/08
to David Menendez, Raeck chiu, Beginners Haskell, Cafe Haskell
Bonus points if you find the stupid bug in my code :)

-- ryan

David Menendez

unread,
Dec 29, 2008, 1:26:37 PM12/29/08
to Ryan Ingram, Raeck chiu, Beginners Haskell, Cafe Haskell
On Mon, Dec 29, 2008 at 4:48 AM, Ryan Ingram <ryani...@gmail.com> wrote:
> On Sun, Dec 28, 2008 at 10:13 PM, David Menendez <da...@zednenem.com> wrote:
>> Here's the simplest way:
>>
>> update k v map = \k' -> if k' == k then v else map k'

> 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.

Sure. It's slow, too. If you want a map that you can update, you're
usually much better off with a concrete data structure.

Ryan Ingram

unread,
Dec 29, 2008, 6:16:05 PM12/29/08
to ra...@msn.com, haskel...@haskell.org, begi...@haskell.org
On Mon, Dec 29, 2008 at 4:29 AM, <ra...@msn.com> 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.

ra...@msn.com

unread,
Dec 29, 2008, 8:24:41 PM12/29/08
to Beginners Haskell, Cafe Haskell
Are there anyway to express the "iterating" of a user-defined data type in
Haskell?

For example, in

> data Shape = Square | Circle | Triangle

how can I 'iterate' them and apply them all to the same function without
indicating them explicitly?
such as [func Square, func Circle, func Triangle].
Can I use a form similar to the following case in a list instead:

> Numbers = [1,2,3,4,5]

> [func x | x <- Numbers ]

Actually what I want is to obtain all the possible values of a data type
(Shape).

Thank you very much!

Best wishes,

Raeck

_______________________________________________
Beginners mailing list
Begi...@haskell.org
http://www.haskell.org/mailman/listinfo/beginners

Luke Palmer

unread,
Dec 29, 2008, 8:29:13 PM12/29/08
to ra...@msn.com, Beginners Haskell, Cafe Haskell
On Mon, Dec 29, 2008 at 6:24 PM, <ra...@msn.com> wrote:

> Are there anyway to express the "iterating" of a user-defined data type in
> Haskell?
>
> For example, in
>
> data Shape = Square | Circle | Triangle
>>
>
> how can I 'iterate' them and apply them all to the same function without
> indicating them explicitly?
> such as [func Square, func Circle, func Triangle].
> Can I use a form similar to the following case in a list instead:
>
> Numbers = [1,2,3,4,5]
>>
>
> [func x | x <- Numbers ]
>>
>
> Actually what I want is to obtain all the possible values of a data type
> (Shape).


For "enum" style data, where all the constructors have no arguments, you can
do deriving (Bounded, Enum), so:

data Shape = Square | Circle | Triangle

deriving (Bounded,Enum)

Then:

numbers = [minBound..maxBound] :: [Shape]

Luke

Paul Visschers

unread,
Dec 30, 2008, 5:30:16 AM12/30/08
to ra...@msn.com, begi...@haskell.org
You actually have two different questions. The first about iteration can
be done by the function map in the following way:

Instead of [func Square, func Circle, func Triangle] you use:
map func [Square, Circle, Triangle].

The list comprehensions should also work:
[func x | x <- [Square, Circle, Triangle]]

Now as for obtaining/generating all values of Shape, the easiest way is
to make Shape an instance of Enum, like this:
data Shape = Square | Circle | Triangle deriving Enum

You can then generate a list of all the values by:
enumFrom Square

You use Square here because it is the first constructor of Shape, and
you want to enumerate them all.

I hope this helps,

Paul

ra...@msn.com

unread,
Dec 30, 2008, 12:12:49 PM12/30/08
to haskel...@haskell.org, begi...@haskell.org
Hi, how can I make the following code work? (show all the possible values of
a type 'a')

> showAll :: (Eq a, Bounded a, Enum a) => a -> [a]
> showAll a = [minBound..maxBound]::[a]

it keeps saying that I could fix the problem by adding (Enum a) and (Bounded
a) the the context, but I failed when I try.

anything goes wrong?

Thanks!

Philippa Cowderoy

unread,
Dec 30, 2008, 12:17:54 PM12/30/08
to ra...@msn.com, begi...@haskell.org
[-cafe left out]

On Tue, 2008-12-30 at 17:12 +0000, ra...@msn.com wrote:
> Hi, how can I make the following code work? (show all the possible values of
> a type 'a')
>
> > showAll :: (Eq a, Bounded a, Enum a) => a -> [a]
> > showAll a = [minBound..maxBound]::[a]
>
> it keeps saying that I could fix the problem by adding (Enum a) and (Bounded
> a) the the context, but I failed when I try.
>

The problem is the inner annotation, ::[a]. It's not the same a as in
(Eq a, Bounded a, Enum a) => a -> [a], and in Haskell98 it can't be. I'm
not surprised that's confused you! If you remove the inner annotation it
should work fine though.

You can go a step further and make showAll a value rather than a
function:

showAll = [minBound..maxBound]

(I've left out the type annotations, but you can put ":t
[minBound..maxBound]" into ghci or hugs if you want one)

--
Philippa Cowderoy <fli...@flippac.org>
I left the snappy .sigs on the other computer

Derek Elkins

unread,
Dec 30, 2008, 12:23:06 PM12/30/08
to ra...@msn.com, begi...@haskell.org, haskel...@haskell.org
On Tue, 2008-12-30 at 17:12 +0000, ra...@msn.com wrote:
> Hi, how can I make the following code work? (show all the possible values of
> a type 'a')
>

> > showAll :: (Eq a, Bounded a, Enum a) => a -> [a]
> > showAll a = [minBound..maxBound]::[a]

The bottom 'a' has nothing to do with the 'a' in the type signature.
Your code is equivalent to


> > showAll :: (Eq a, Bounded a, Enum a) => a -> [a]

> > showAll a = [minBound..maxBound]::[b]

Which is not type correct as [minBound..maxBound] :: (Bounded a, Enum a) => [a]
You don't need that type annotation (or the type signature for that matter), so just omit it.

Robert Greayer

unread,
Dec 30, 2008, 12:45:58 PM12/30/08
to ra...@msn.com, haskel...@haskell.org, begi...@haskell.org
Raeck said:

> Hi, how can I make the following code work? (show all the possible values of a type 'a')

>> showAll :: (Eq a, Bounded a, Enum a) => a -> [a]
>> showAll a = [minBound..maxBound]::[a]

What you are really looking for, I think, is a polymorphic value of type [a], where a is some enumerable, bounded type.

allValues :: (Enum a, Bounded a) => [a]
allValues = [minBound .. maxBound]

You can omit the type signature, but then you'll run into the monomorphism restriction (which you'll can turn off with, e.g. -XNoMonomorphismRestriction)

Paul Visschers

unread,
Dec 30, 2008, 12:50:18 PM12/30/08
to ra...@msn.com, begi...@haskell.org
You seem to be having some trouble with the type system, not just in
this instance. I found when I was learning Haskell that when this
happens, it is useful to not add type annotations, then load it up in
GHCi and see what it comes up with (with the aforementions :t option).
Then you can see why that makes sense and possibly change the function.
Once you're happy with the function and are confident you understand its
type, go ahead and put the type annotation back into your source code.

I also found it useful to play around with various expressions and see
what their types where. Especially with things like partial application,
function composition and monadic functions.

Paul

Philippa Cowderoy wrote:
> [-cafe left out]
>
> On Tue, 2008-12-30 at 17:12 +0000, ra...@msn.com wrote:
>> Hi, how can I make the following code work? (show all the possible values of
>> a type 'a')
>>
>>> showAll :: (Eq a, Bounded a, Enum a) => a -> [a]
>>> showAll a = [minBound..maxBound]::[a]
>> it keeps saying that I could fix the problem by adding (Enum a) and (Bounded
>> a) the the context, but I failed when I try.
>>
>
> The problem is the inner annotation, ::[a]. It's not the same a as in
> (Eq a, Bounded a, Enum a) => a -> [a], and in Haskell98 it can't be. I'm
> not surprised that's confused you! If you remove the inner annotation it
> should work fine though.
>
> You can go a step further and make showAll a value rather than a
> function:
>
> showAll = [minBound..maxBound]
>
> (I've left out the type annotations, but you can put ":t
> [minBound..maxBound]" into ghci or hugs if you want one)
>

0 new messages