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. Re: accessor function scope (Michael Mossey)
2. Re: accessor function scope (John Dorsey)
3. Re: accessor function scope (Daniel Fischer)
4. Re: accessor function scope (Brandon S. Allbery KF8NH)
5. Re: accessor function scope (Brandon S. Allbery KF8NH)
6. Re: CORRECTED: making translation from imperative code]
(Heinrich Apfelmus)
7. Local Haskell meeting, Halle/Saale, Germany, June 12
(Janis Voigtlaender)
----------------------------------------------------------------------
Message: 1
Date: Tue, 07 Apr 2009 02:47:32 -0700
From: Michael Mossey <[email protected]>
Subject: Re: [Haskell-beginners] accessor function scope
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Francesco Bochicchio wrote:
>
>
> me too :-)
>
>
> Again, StaffItem and TextItem resemble derived classes in OO.
>
>
> To me, they are more close to C union : a data type than can
> alternatively have different structures,
> In your example, LayoutItem is a type name, while StaffItem and TextItem
> are constructor, that is functions.
> Saying that a function specializes a type is a bit of a stretch, I think ...
>
> Nevertheless, they can sometime be used to accomplish the same goal :
> where in OO you define an abstact class and then
> specialize with concrete classes to model a classification, in haskell
> you can define a data type with alternate constructors.
>
> I think that data types with alternate constructores are called
> algebraic data types in haskellese, but I'm not sure of that ...
Here's what I've learned from my investigations, but I welcome any
clarifications.
There are a few ways they don't resemble constructors in OO, or unions in C.
They are "constructors", but also "take apart" the item in pattern matching.
myfunc (StaffItem pos dimension) = ...
myfunc (TextItem pos dimension) = ...
You can also hide the constructors when you export a module. I could export
LayoutItem but not StaffItem and TextItem, meaning that other code would see
LayoutItem as a kind of abstract base class.
When you name a field in each constructor (the same name), you can access that
field
on any LayoutItem without knowing its constructor using the accessor function
for
that field. This looks a lot like an abstract base class.
data LayoutItem = TextItem { myField :: Int }
| StaffItem { myField :: Int }
x1 = TextItem { myField = 3 }
x2 = STaffItem { myField = 4 }
y1 = myField x1
y2 = myField x2
When I tried to make TextItem and StaffItem instances of a class, I got an
error.
They aren't really types. Only LayoutItem is the type.
instance Eq TextItem where ...
---> ERROR!
instance Eq StaffItem where ...
---> ERROR!
instance Eq LayoutItem where...
---> ok
Right now I'm just confused by how to translate an exising OO design. I'm
porting a
partially complete Python program to Haskell. There are many options. For
instance I
could set up a class called LayoutClass, make TextItem and StaffItem their own
classes and make them instances of the class.
-- Note: Now I can no longer have any overlapping field names
data TextItem = TextItem { tField1, tField2 :: Int }
data StaffItem = StaffItem { sField1, sField3 :: Int }
class LayoutClass a where
access1 :: a -> Int
instance LayoutClass TextItem where
access1 (TextItem t) = tField1 t
instance LayoutClass StaffItem where
access1 (StaffItem s ) = sField1 s
Or put everything in its own module and use qualified names. Probably the best
choice
for future considerations.
------------------------------
Message: 2
Date: Tue, 7 Apr 2009 09:00:54 -0400
From: John Dorsey <[email protected]>
Subject: Re: [Haskell-beginners] accessor function scope
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
> I've noticed that if I declare two types like this
>
> data Thing1 = Thing1 { itemPos :: Int }
> data Thing2 = Thing2 { itemPos :: Int }
>
> then I get the error "Multiple declarations of Main.itemPos"
Here's something to consider. What's the type of itemPos? In the above
code, it can't be
itemPos :: Thing1 -> Int
because you want to be able to apply it to a Thing2. I suppose the
compiler could, behind the scenes, create a typeclass like this:
class ItemPosAble a where
itemPos :: a -> Int
instance ItemPosAble Thing1 where
itemPos (Thing1 x) = x
instance ItemPosAble Thing2 where
itemPos (Thing2 x) = x
Then itemPos has type
itemPos :: (ItemPosAble t) => t -> Int
Maybe that would work, modulo my typos. But it's messy, and it gets
messier if itemPos doesn't have the same return type in all examples. It
probably makes it harder to produce clear error messages when something
goes wrong. There are probably other issues I haven't seen yet.
At any rate, just disallowing this kind of "overloading" of the accessor
function is simple, and works. As you point out later, you can reuse
the name by separating namespaces using modules.
> data LayoutItem = StaffItem { itemPos :: Pos,
> itemDim :: Dimension }
> | TextItem { itemPos :: Pos,
> itemDim :: Dimension }
Here the type of itemPos is clearly just
itemPos :: LayoutItem -> Pos
No problem. Behind the scenes, the compiler is defining it as something
like
itemPos (StaffItem x _) = x
itemPos (TextItem x _) = x
> This seems to define itemPos in a way that can sense whether it's dealing
> with a StaffItem-type LayoutItem or a TextItem-type LayoutItem. I don't
You're right that there's enough information to figure it out in
this example code, but the type inference in Haskell doesn't do this
kind of ad-hockery.
> know if this would be considered an overloaded operator. However, it does
> resemble derived class in OO.
It's not a bad exercise to compare Haskell to what you already know, but
expect it to break down before long. Clear and idiomatic functional
design will generally look pretty different from clear and idiomatic OO
design. That said, you can do OO stuff in Haskell; it's just not very fun,
and generally not needed.
> For that matter, I don't know what the term is for a "StaffItem-type
> LayoutItem". The type is clearly LayoutItem. "StaffItem" is the
> constructor. How do you refer to the concept of a LayoutItem constructed
> via a StaffItem?
You can just call it "a StaffItem", I guess. I don't know if there's a
common term. But you're right that it's type is LayoutItem.
Regards,
John
------------------------------
Message: 3
Date: Tue, 7 Apr 2009 15:15:00 +0200
From: Daniel Fischer <[email protected]>
Subject: Re: [Haskell-beginners] accessor function scope
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="iso-8859-1"
Am Dienstag 07 April 2009 11:47:32 schrieb Michael Mossey:
> Francesco Bochicchio wrote:
> > me too :-)
> >
> >
> > Again, StaffItem and TextItem resemble derived classes in OO.
> >
> >
> > To me, they are more close to C union : a data type than can
> > alternatively have different structures,
Both analogies capture some aspects of Haskell types. They're useful if you
are aware that they take you only so far.
> > In your example, LayoutItem is a type name, while StaffItem and TextItem
> > are constructor, that is functions.
> > Saying that a function specializes a type is a bit of a stretch, I think
> > ...
> >
> > Nevertheless, they can sometime be used to accomplish the same goal :
> > where in OO you define an abstact class and then
> > specialize with concrete classes to model a classification, in haskell
> > you can define a data type with alternate constructors.
> >
> > I think that data types with alternate constructores are called
> > algebraic data types in haskellese, but I'm not sure of that ...
Yes, they're called algebraic datatypes, but I'm not sure if a type must have
more than one constructor to qualify as such.
>
> Here's what I've learned from my investigations, but I welcome any
> clarifications.
>
> There are a few ways they don't resemble constructors in OO, or unions in
> C.
>
> They are "constructors", but also "take apart" the item in pattern
> matching. myfunc (StaffItem pos dimension) = ...
> myfunc (TextItem pos dimension) = ...
>
> You can also hide the constructors when you export a module. I could export
> LayoutItem but not StaffItem and TextItem, meaning that other code would
> see LayoutItem as a kind of abstract base class.
>
> When you name a field in each constructor (the same name), you can access
> that field on any LayoutItem without knowing its constructor using the
> accessor function for that field. This looks a lot like an abstract base
> class.
>
> data LayoutItem = TextItem { myField :: Int }
>
> | StaffItem { myField :: Int }
>
> x1 = TextItem { myField = 3 }
> x2 = STaffItem { myField = 4 }
>
> y1 = myField x1
> y2 = myField x2
>
> When I tried to make TextItem and StaffItem instances of a class, I got an
> error. They aren't really types. Only LayoutItem is the type.
>
> instance Eq TextItem where ...
> ---> ERROR!
>
> instance Eq StaffItem where ...
>
> ---> ERROR!
>
> instance Eq LayoutItem where...
> ---> ok
>
> Right now I'm just confused by how to translate an exising OO design. I'm
> porting a partially complete Python program to Haskell. There are many
> options. For instance I could set up a class called LayoutClass, make
> TextItem and StaffItem their own classes and make them instances of the
"their own types"
> class.
>
> -- Note: Now I can no longer have any overlapping field names
> data TextItem = TextItem { tField1, tField2 :: Int }
> data StaffItem = StaffItem { sField1, sField3 :: Int }
For fields that are generic enough to be interesting, you can have
class HasPosition a where
pos :: a -> Position
class HasDimension a where
dim :: a -> Dimension
class HasField1 a where
field1 :: a -> Int
instance HasField1 TextItem where
field1 (TextItem f1 _) = f1
>
> class LayoutClass a where
> access1 :: a -> Int
>
> instance LayoutClass TextItem where
> access1 (TextItem t) = tField1 t
>
> instance LayoutClass StaffItem where
> access1 (StaffItem s ) = sField1 s
>
> Or put everything in its own module and use qualified names. Probably the
> best choice for future considerations.
Consider also the "class HasWhatever" approach, sometimes it's better than
qualified names.
------------------------------
Message: 4
Date: Tue, 7 Apr 2009 13:31:40 -0400
From: "Brandon S. Allbery KF8NH" <[email protected]>
Subject: Re: [Haskell-beginners] accessor function scope
To: John Dorsey <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"
On 2009 Apr 7, at 9:00, John Dorsey wrote:
>> I've noticed that if I declare two types like this
>>
>> data Thing1 = Thing1 { itemPos :: Int }
>> data Thing2 = Thing2 { itemPos :: Int }
>>
>> then I get the error "Multiple declarations of Main.itemPos"
>
> Here's something to consider. What's the type of itemPos? In the
> above
> code, it can't be
>
> itemPos :: Thing1 -> Int
>
> because you want to be able to apply it to a Thing2. I suppose the
> compiler could, behind the scenes, create a typeclass like this:
I think it already does this if you ask for the
DisambiguateRecordFields language extension (provided it can tell
which one is needed!).
>> For that matter, I don't know what the term is for a "StaffItem-type
>> LayoutItem". The type is clearly LayoutItem. "StaffItem" is the
>> constructor. How do you refer to the concept of a LayoutItem
>> constructed
>> via a StaffItem?
>
> You can just call it "a StaffItem", I guess. I don't know if
> there's a
> common term. But you're right that it's type is LayoutItem.
Technically LayoutItem is a sum of products and StaffItem is a variant
(see http://en.wikipedia.org/wiki/Sum_type for more information).
--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [email protected]
system administrator [openafs,heimdal,too many hats] [email protected]
electrical and computer engineering, carnegie mellon university KF8NH
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 195 bytes
Desc: This is a digitally signed message part
Url :
http://www.haskell.org/pipermail/beginners/attachments/20090407/163e8167/PGP-0001.bin
------------------------------
Message: 5
Date: Tue, 7 Apr 2009 13:38:16 -0400
From: "Brandon S. Allbery KF8NH" <[email protected]>
Subject: Re: [Haskell-beginners] accessor function scope
To: Daniel Fischer <[email protected]>
Cc: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"
On 2009 Apr 7, at 9:15, Daniel Fischer wrote:
> Yes, they're called algebraic datatypes, but I'm not sure if a type
> must have
> more than one constructor to qualify as such.
An ADT is any type expressible by a combination of sum and product
types, IIRC. Single constructor types are product types, multiple
constructors are sums of product types. (Note that this leaves out
"data Nil"; that's why it's an extension. "data Nil = Nil" is
vacuously an ADT.)
--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] [email protected]
system administrator [openafs,heimdal,too many hats] [email protected]
electrical and computer engineering, carnegie mellon university KF8NH
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 195 bytes
Desc: This is a digitally signed message part
Url :
http://www.haskell.org/pipermail/beginners/attachments/20090407/9275ed20/PGP-0001.bin
------------------------------
Message: 6
Date: Wed, 08 Apr 2009 01:29:22 +0200
From: Heinrich Apfelmus <[email protected]>
Subject: [Haskell-beginners] Re: CORRECTED: making translation from
imperative code]
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1
Michael Mossey wrote:
> Okay, I read all of your email, and there is one problem. My layout
> problem is more complex than I communicated at first. Let me give a more
> detailed example:
>
> staff 1: xxxx|xxxx x|x
> staff 2: x|xx xxxx|xx
> staff 3: x|x
> a b c
>
> There are two additional concerns to what you coded up. Notice that
> parts of events on different staves are allowed to overlap. To determine
> the spacing from a to b, one has to know the widths of items on each
> staff to see that they they can be placed with some overlap but won't
> collide. They can't be treated strictly as a compound item and "going
> blind" to the parts that make them up.
>
> Secondly, look at the item on staff 3 at c. It has no prior item to
> avoid colliding with, and no items on other staves to line up with, but
> there is still a constraint on its position: c > b (by some amount that
> can be experimented with).
No problem. :)
Reading your code, I'd generally recommend a higher-level approach
focusing on *abstraction*. Primitive recursion can do the job, but it's
error-prone and tedious and best avoided.
> -- Item is a pair giving left width and right width.
> type Item = (Int, Int)
> -- Chunk represents items that must align.
> -- There may not be one on every staff,
> -- hence the use of Maybe
> type Chunk = [ Maybe Item ]
Abstraction starts with using type synonyms like
type Pos = Int
type Width = Pos
that indicate what the parameter denotes, not how it's represented by
the computer. [Int] is less descriptive than [Pos] (a list of
absolute coordinates), because it could also mean [Width] (a list of
relative coordinates). For instance, it's possible to add two widths,
but adding two positions should be a type error, you may only advance a
position by a width.
Also, I think that Chunk is too generic a name, but I don't have a
good replacement for now. But see below.
Abstraction is also key to solving the new problem description with the
same algorithm as the old one. In particular, our goal is to implement
the function align just like the old one.
The core abstraction is that of an *extent*. It's simply a list of widths
type Extent = [Width]
representing a vertical group of bars.
xxxx| |xxxx
xx| or |xx = [4,2,3]
xxx| |xxx
We don't specify whether they are ragged to the right or left. The
define the width of an extent to be the maximum width of its bars
width :: Extent -> Width
width = maximum
A Chunk is of course just a pair of extents, one to the left and one
to the right
extents :: Chunk -> (Extent,Extent)
extents = unzip . map (maybe (0,0) id)
Now, align is structured just like before, calculating the gaps
between different items
align :: [(Extent, Extent)] -> [Pos]
align xs = scanl (+) (width l) gaps
where
(l:ls, rs) = unzip xs
gaps = zipWith fit rs ls
However, extents are now fitted together with
fit :: Extent -> Extent -> Width
fit xs ys = (+1) . maximum . zipWith (+) xs ys
The previous code can be interpreted as fitting extents together with
fit xs ys = maximum xs + maximum ys
Different definitions of fit yield different layouts algorithms.
I'm not happy with the definition of align yet, because the specifics
of laying out extents are present in two places, namely width and fit
instead of just one, namely fit . This can be remedied by noting that
the purpose of width is to fit the first extent to the *left
boundary*. In other words,
width = fit (repeat 0)
(assuming that fit is able to crop and infinite list of widths to the
proper size). Thus, we have
align xs = scanl1 (+) gaps
where
(ls,rs) = unzip xs
boundary = repeat 0
gaps = zipWith fit (boundary:rs) ls
In the end, both align and your layout3 functions do exactly the
same calculations, of course, but by virtue of abstraction, the
correctness and structure of the former is self-evident.
> layout3 :: [ Chunk ] -> [ Int ]
> layout3 cs = layout3' cs (replicate (length cs) 0) 0
>
> layout3' :: [ Chunk ] -> [ Int ] -> Int -> [ Int ]
> layout3' [] _ _ = []
> layout3' (c:cs) rs minP = p : layout3' cs rs' (p + 1) where
> p = maximum $ minP : (map place (zip c rs))
> rs' = map (advance p) c
> place (item, r) = case item of
> Just ( left, right ) -> r + left + 1
> _ -> 0
> advance p item = case item of
> Just ( left, right ) -> p + right + 1
> _ -> p
Two remarks on the code for pretty printing:
> drawLayout :: [ Chunk ] -> [ Int ] -> String
> drawLayout cs pos = unlines $ makeLines cs pos where
>
> makeLines :: [ Chunk ] -> [ Int ] -> [ String ]
> makeLines cs@(cs1:_) pos
> | null cs1 = []
> | otherwise = makeLine (map head cs) pos :
> makeLines (map tail cs) pos
This is basically a function known as transpose (from Data.List).
Also, let's reorder the parameters.
makeLines :: [Pos] -> [Chunk] -> [String]
makeLines pos = map (makeLine pos) . transpose
> makeLine :: [ Maybe Item ] -> [ Int ] -> String
> makeLine items pos = foldl addItem [] (zip items pos)
>
> addItem :: String -> ( Maybe Item, Int ) -> String
> addItem s ( item, p ) =
> let le = length s in case item of
> Just ( l, r ) -> s ++ (replicate (p - le - l) ' ') ++
> (replicate l 'x') ++ "|" ++ (replicate r 'x')
> _ -> s
>
> data1 = [ [ Just (2,2), Just(1,1), Just (2,3 ) ],
> [ Just (1,1), Just (3,4), Just(1,1) ],
> [ Just (4,4), Nothing, Just (1,1) ] ]
>
> answer = drawLayout data1 (layout3 data1)
> main = do putStr answer
main = putStr answer -- no do required
> *Main> main
> xx|xx x|x xxxx|xxxx
> x|x xxx|xxxx
> xx|xxx x|x x|x
> *Main>
Regards,
apfelmus
--
http://apfelmus.nfshost.com
------------------------------
Message: 7
Date: Wed, 08 Apr 2009 08:09:11 +0200
From: Janis Voigtlaender <[email protected]>
Subject: [Haskell-beginners] Local Haskell meeting, Halle/Saale,
Germany, June 12
To: [email protected], [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
[Apologies for German announcement text...]
---------------------------------------------
HaL4 : Haskell - Tutorial + Workshop + Party
am Freitag, dem 12. Juni 2009, in Halle/Saale
---------------------------------------------
Das traditionsreiche HaL-Treffen bietet eine gute Mischung
von Haskell-bezogenen Themen aus Forschung, Anwendung und Lehre
mit vielen Möglichkeiten zu Diskussion und Unterhaltung
bei der anschließenden Party. Der Workshop wird in diesem Jahr
ergänzt durch Tutorien für Haskell-Ein- und Umsteiger.
Diesmal findet das Treffen in Halle/Saale im Institut für Informatik
der Martin-Luther-Universität Halle-Wittenberg statt. Wir planen:
10 - 13 Uhr: Tutorien
15 - 19 Uhr: Fachvorträge
19 - 22 Uhr: Grillparty
Wir freuen uns auf rege Teilnahme sowie spannende Vorträge mit heißen
Diskussionen und bitten um Vortragsanmeldungen bis zum 8. Mai.
Gedacht sind 4 mal je 30 min Vortrag + 30 min Diskussion.
Weitere Informationen auf http://www.iba-cg.de/hal4.html
--
Dr. Janis Voigtlaender
http://wwwtcs.inf.tu-dresden.de/~voigt/
mailto:[email protected]
------------------------------
_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners
End of Beginners Digest, Vol 10, Issue 7
****************************************