WxHaskell Daan Leijen. Ok…. Dat lijkt me een goed plan. Denk je dat je zo iets dinsdag af kunt...
-
Upload
christiana-edwards -
Category
Documents
-
view
213 -
download
0
Transcript of WxHaskell Daan Leijen. Ok…. Dat lijkt me een goed plan. Denk je dat je zo iets dinsdag af kunt...
wxHaskell
Daan Leijen
Ok….
Dat lijkt me een goed plan. Denk je dat je zo iets dinsdag af kunt hebben en presenteren?
Doaitse
On donderdag, september 18, 2003, at 10:43 AM, Daan Leijen wrote:
Nog even over AFP. De turtle-graphics opdracht is volgensmij goed te doen met wxHaskell -- behalve dan dat hetgeinstalleerd dient te worden. Als je wilt kunnen we misschien wat details afspreken endat ik dan wat help om de opdracht vorm te geven met1) een werkend voorbeeld, en 2) concrete vragen.
Overview
wxHaskell as a concrete example of FFI, phantom types, existential types, combinator design, inheritance simulation, and IO as first-class values.
Homework: implement a "turtle" graphics combinator library.
wxHaskell
wxHaskell is a portable GUI library for Haskell build upon the wxWindows (C++) library.
Two layers: a "core" binding (WXCore) and a haskellized layer (WX).
Hello world
hello :: IO ()hello = do f <- frame [text := "Hello!"] quit <- button f [text := "Quit" ,on command := close f] set f [layout := widget quit]
Layout combinators
set f [layout := margin 10 (column 5 [floatCentre (label "Hello") ,floatCentre (widget quit) ] ) ]
Demo
What is needed?
Foreign Function Interface (FFI) Model inheritance Create abstractions:
– Layout combinators– Properties (get/set)
FFI
What are the primitives that you need to interface to the imperative world from Haskell?
4 primitive operations are needed.
1. Call the outside world (foreign import)
2. Be called (foreign export)
3. Use foreign data (CInt, Addr)
4. Export haskell data (StablePtr a)
Examples:
foreign import sin :: Double -> IO Double
foreign import strlen :: Addr -> IO CInt
Phantom types
Make "Addr" typesafe:
type Ptr a = Addr
foreign import strlen :: Ptr Char -> IO Int
Abstraction
foreign import strlen :: Ptr Char -> IO Int
strLen :: String -> IntstrLen s = unsafePerformIO $ withCString s $ \cstr -> strlen cstr
Abstraction
withCString :: String -> (Ptr Char -> IO a) -> IO awithCString s f = do p <- malloc (length s+1) mapM_ (poke p) (zip s [0..]) x <- f p free p return x
wxHaskell
windowSetLabel :: Window a -> String -> IO ()windowSetLabel w txt = withCString txt $ \cstr -> primWindowSetLabel w txt
foreign import "windowSetLabel" primWindowSetLabel :: Window a -> Ptr Char -> IO ()
Inheritance
How to model inheritance?
class Window { void setLabel( const char* txt ); ..};
class Frame : public Window { void maximize( void ); ..};
Simple model.
type Window = Ptr CWindowdata CWindow = CWindow
type Frame = Ptr CFramedata CFrame = CFrame
windowCreate :: IO WindowwindowSetLabel :: Window -> String -> IO ()
frameCreate :: IO FrameframeMaximize :: Frame -> IO ()
Conversions?
windowFromFrame :: Frame -> Window
do f <- frameCreate windowSetLabel (windowFromFrame f)
Encode inheritance in phantom type
type Window a = Ptr (CWindow a)data CWindow a = CWindow
type Frame a = Window (CFrame a)data CFrame a = CFrame
windowCreate :: IO (Window ())windowSetLabel :: Window a -> String -> IO ()
frameCreate :: IO (Frame ())frameMaximize :: Frame a -> IO ()
It works now
do f <- frameCreate windowSetLabel f "Hi"
f :: Frame () == Window (CFrame ()) == Ptr (CWindow (CFrame ()))
windowSetLabel :: Window a -> String -> IO ()
Properties
How can we model the "property" methods?
windowGetLabel :: Window a -> IO StringwindowSetLabel :: Window a -> String -> IO ()
windowGetLayout :: Window a -> IO LayoutwindowSetLayout :: Window a -> Layout -> IO ()
..
Get/Set
We would like to have generic "get" and "set" functions:
get :: w -> Attr -> IO aset :: w -> Attr -> a -> IO ()
Typed get/set
get :: w -> Attr w a -> IO aset :: w -> Attr w a -> a -> IO ()
text :: Attr (Window a) String
Attributes
data Attr w a = Attr (w -> IO a) (w -> a -> IO ())
text :: Attr (Window a) Stringtext = Attr windowGetLabel windowSetLabel
Generic get/set
get :: w -> Attr w a -> IO aget w (Attr getter setter) = getter w
set :: w -> Attr w a -> a -> IO ()set w (Attr getter setter) x = setter w x
Problems
I would like to set many "properties" at once:
set frame text "hi"set frame size (sz 300 300)set frame color blue
== (?)
map (set frame) [text "hi", size (sz 300 300), color blue]
Properties
Properties save a value/attribute pair.
data Prop w = Prop (w -> IO ())
prop :: Attr w a -> a -> Prop wprop (Attr getter setter) x = Prop (\w -> setter w x)
set :: w -> [Prop w] -> IO ()set w props = mapM_ setprop props where setprop (Prop setter) = setter w
Now we can set many properties
set frame [prop text "hi" ,prop color blue ,prop size (sz 300 300) ]
Problem
I want a nicer notation:
prop text "hi" text := "hi"
Existentials
data Prop w = (:=) (Attr w a) a
data Prop w = forall a. (:=) (Attr w a) a
New definition of "set"
set :: w -> [Prop w] -> IO ()set w props = mapM_ setprop props where setprop ((Attr getter setter) := x) = setter w x
Definition of "frame"
frame :: [Prop (Frame ())] -> IO (Frame ())frame props = do f <- frameCreate idAny "" rectNull 0 set f props return f
A combinator language for layout
set f [layout := margin 10 (column 5 [floatCentre (label "Hello") ,floatCentre (widget quit) ] ) ]
Example: C++ vs. Combinators
f <- frame [text "Demo"]
ok <- button f [text "Ok"]can <- button f [text "Cancel"]txt <- textCtrl f AlignLeft [clientSize := sz 100 60]
set f [layout := margin 10 $ column 10 [ fill $ widget txt , hfill $ row 10 [widget ok, widget can] ] ]
Abstract data type
data Layout
windowSetLayout :: Window a -> Layout -> IO ()
do f <- frameCreate idAny "Test" rectNull 0 ok <- buttonCreate f idAny "Bye" rectNull 0 windowSetLayout f (widget ok)
Primitives
widget :: Window a -> Layoutlabel :: String -> Layoutspace :: Size -> Layout
Containers
grid :: Int -> Int -> [[Layout]] -> Layout
grid 5 5 [[label "x", widget xinput] ,[label "y", widget yinput]]
Containers 2
row :: Int -> [Layout] -> Layoutcolumn :: Int -> [Layout] -> Layout
row n xs = grid n 0 [xs]
column n xs = grid 0 n (map (\x -> [x]) xs)
column 5 [grid 5 5 [[label "x", widget xinput] ,[label "y", widget yinput]] row 5 [widget ok, widget cancel]]
Attributes
margin :: Int -> Layout -> Layout
align :: Align -> Layout -> Layoutshaped :: Layout -> Layoutexpand :: Layout -> Layout
Stretch
hstretch, vstretch, stretch :: Layout -> Layout
stretch = hstretch . vstretch
column 5 $[grid 5 5 [[label "x", hstretch $ expand $ widget xinput] ,[label "y", hstretch $ expand $ widget yinput]],stretch $ alignBottomRight $ row 5 [widget ok, widget cancel]]
Many helpers
fill = stretch . expandhfill = hstretch . expand
floatBottomRight = stretch . alignBottomRight
empty = space (sz 0 0)glue = fill emptyhglue = hfill empty
Implementation
data Layout = Widget (Window ()) | Label String | Grid Int Int [[Layout]]
Transformers
data Layout = Widget { options :: Options, ..} | Label { options :: Options, ..} | Grid { options :: Options, ..}
data Options = Options{ stretchH :: Bool , stretchV :: Bool , marginW :: Int , .. }
Generate Layout
widget w = Widget defaultOptions wlabel s = Label defaultOptions s
hstretch layout = updateOptions (\opt -> opt { stretchH = True }) layout
updateOptions f layout = layout{ options = f (options layout) }
Translate Layout
windowSetLayout :: Window a -> Layout -> IO ()windowSetLayout w (Label options s) = do lab <- staticTextCreate s sizer <- windowSizerCreate lab (flags options) windowAddSizer w sizer..
flags options = (if stretchH options then wxHSTRETCH else 0) + (if stretchV options then wxVSTRETCH else 0) + ..
Assignment: Turtle graphics
Design and implement an embedding of the LOGO language in Haskell.
Motivate your design decisions! Deadline: this Sunday.
http://wxhaskell.sourceforge.net/assignment.html [email protected]