[Noted functions, etc. John Goerzen **20070920063201] { hunk ./en/ch13-data.xml 372 - Association Lists + Association Lists and Maps hunk ./en/ch13-data.xml 482 + + + Functions Are Data, Too + + Back in the beginning of the chapter, we reminded you that Haskell isn't + object-oriented. Part of Haskell's power is the ease with which you + can create and manipulate functions with it. Let's take a look at a + record that stores a function as one of its fields: + + &funcrecs.hs:all; + + Notice the type of the colorCalc field: it's a + function. It takes an Int and returns a tuple of + (CuscomColor, Int). We create two + FuncRec records: plus5 and + always0. Notice that the + colorCalc for both of them will always return the + color purple. FuncRec itself has no field to store + the color in, yet that value somehow becomes part of the function + itself. This is called a closure. Let's play + with this a bit: + + &funcrecs.ghci:all; + + That worked well enough, but you might be wondering how to do something + more advanced such as making a piece of data available multiple places. + A type construction function can be helpful. Here's an example: + + &funcrecs2.hs:all; + + Here we have a function called mkFuncRec that + takes a &String; and another function as parameters, and returns + a new FuncRec record. Notice how both parameters to + mkFuncRec are used multiple places. Let's try it + out: + + &funcrecs2.ghci:all; + Notice the creation of plus5a. We changed the + name field, but not the namedCalc + field. That's why name has the new name, but + namedCalc still returns the name that was passed to + mkFuncRec; it doesn't change unless we explicitly + change it. + + addfile ./examples/ch13/funcrecs.ghci hunk ./examples/ch13/funcrecs.ghci 1 +--# all +:l funcrecs.hs +:t plus5 +name plus5 +:t colorCalc plus5 +(colorCalc plus5) 7 +:t colorCalc always0 +(colorCalc always0) 7 + addfile ./examples/ch13/funcrecs.hs hunk ./examples/ch13/funcrecs.hs 1 +{-- snippet all --} +data CustomColor = + CustomColor {red :: Int, + green :: Int, + blue :: Int} + deriving (Eq, Show, Read) + +data FuncRec = + FuncRec {name :: String, + colorCalc :: Int -> (CustomColor, Int)} + +plus5func color x = (color, x + 5) +purple = CustomColor 255 0 255 + +plus5 = FuncRec {name = "plus5", colorCalc = plus5func purple} +always0 = FuncRec {name = "always0", colorCalc = \_ -> (purple, 0)} +{-- /snippet all --} + addfile ./examples/ch13/funcrecs2.ghci hunk ./examples/ch13/funcrecs2.ghci 1 +--# all +:l funcrecs2.hs +:t plus5 +name plus5 +(calc plus5) 5 +(namedCalc plus5) 5 +let plus5a = plus5 {name = "PLUS5A"} +name plus5a +(namedCalc plus5a) 5 addfile ./examples/ch13/funcrecs2.hs hunk ./examples/ch13/funcrecs2.hs 1 +{-- snippet all --} +data FuncRec = + FuncRec {name :: String, + calc :: Int -> Int, + namedCalc :: Int -> (String, Int)} + +mkFuncRec :: String -> (Int -> Int) -> FuncRec +mkFuncRec name calcfunc = + FuncRec {name = name, + calc = calcfunc, + namedCalc = \x -> (name, calcfunc x)} + +plus5 = mkFuncRec "plus5" (+ 5) +always0 = mkFuncRec "always0" (\_ -> 0) +{-- /snippet all --} + }