Tangible Value
From HaskellWiki
m (→Arrow-specific interfaces) |
m (→IO) |
||
| Line 242: | Line 242: | ||
==== IO ==== | ==== IO ==== | ||
| + | |||
| + | We can use <hask>IO</hask> operations in TV interfaces via the <hask>KIO</hask> arrow (defined as <hask>Kleisli IO</hask>). TV provides a few functions in its [http://darcs.haskell.org/packages/TV/doc/html/Graphics-UI-TV-IO.html <hask>IO</hask> module], including a close counterpart to the standard <hask>interact</hask> function. | ||
| + | <haskell> | ||
| + | interactOut :: Output KIO (String -> String) | ||
| + | interactOut = oLambda contentsIn stringOut | ||
| + | </haskell> | ||
| + | |||
| + | Assuming we have a file <tt>"test.txt"</tt> containing some lines of text, we can use it to test string transformations. | ||
| + | <haskell> | ||
| + | testO :: Output KIO (String -> String) | ||
| + | testO = oLambda (fileIn "test.txt") defaultOut | ||
| + | </haskell> | ||
| + | |||
| + | First, here's a handy wrapping pattern (found in TV's [http://darcs.haskell.org/packages/TV/doc/html/Graphics-UI-TV-Misc.html <hask>Misc</hask> module]). For instance, <hask>wrapF show read</hask> turns a string function into value function. | ||
| + | <haskell> | ||
| + | wrapF :: (c->d) -> (a->b) -> ((b->c) -> (a->d)) | ||
| + | wrapF after before f = after . f . before | ||
| + | </haskell> | ||
| + | |||
| + | Using <hask>wrapF</hask> it's easy to define higher-order functions that apply another function to the lines or on the words of a string. | ||
| + | <haskell> | ||
| + | onLines, onWords :: ([String] -> [String]) -> (String -> String) | ||
| + | onLines = wrapF unlines lines | ||
| + | onWords = wrapF unwords words | ||
| + | </haskell> | ||
| + | |||
| + | <haskell> | ||
| + | io3 = tv testO (onLines reverse) | ||
| + | io4 = tv testO (onWords reverse) | ||
| + | </haskell> | ||
[[Category:Interfaces]] | [[Category:Interfaces]] | ||
Revision as of 07:27, 17 January 2007
Contents |
1 Abstract
TV is a library for composing tangible values ("TVs"), i.e., values that carry along external interfaces. In particular, TVs can be composed to create new TVs, and they can be directly executed with a friendly GUI, a process that reads and writes character streams, or many other kinds interfaces. Values and interfaces are combined for direct use, and separable for composition.
TV is for creating software that is ready to use and ready to reuse.
Beside this page, here are some ways to explore TV:
- Read the Haddock docs (with source code, additional examples, and Comment/Talk links)
- Get the code repository: darcs get http://darcs.haskell.org/packages/TV
- Or grab a distribution tarball.
2 Tangible values
As a first example, here is a tangible reverse function:
reverseT :: CTV (String -> String) reverseT = tv (oTitle "reverse" defaultOut) reverse
Running:
runUI reverseT runIO reverseT![]()
*Examples> runIO reverseT reverse: Hello, reversible world. .dlrow elbisrever ,olleH *Examples>
2.1 Outputs
What I've been calling an "interface" is a value of typetotal :: Show a => COutput a total = oTitle "total" showOut
2.2 Inputs and function-valued outputs
Just as an output is a way to deliver a value, an "input" is a way to obtain a value. For example, here are two inputs, each specifying an initial value and a value range, and each given a title.
apples, bananas :: CInput Int apples = iTitle "apples" defaultIn bananas = iTitle "bananas" defaultIn
shoppingO :: COutput (Int -> Int -> Int) shoppingO = oTitle "shopping list" $ oLambda apples (oLambda bananas total)
And a TV:
shopping :: CTV (Int -> Int -> Int) shopping = tv shoppingO (+)
Running:
runUI shopping runIO shopping![]()
shopping list: apples: 8 bananas: 5 total: 13
2.3 A variation
Here is an uncurried variation:
shoppingPr :: CTV ((Int,Int) -> Int) shoppingPr = tv ( oTitle "shopping list -- uncurried" $ oLambda (iPair apples bananas) total ) (uncurry (+))
shoppingPr = uncurryA $$ shopping
Running:
runUI shoppingPr runIO shoppingPr![]()
shopping list: apples: 8 bananas: 5 total: 13
2.4 The general story
TVs, outputs and inputs are not restricted to GUIs and IO. In general, theyre parameterized by an arrow.
data Output (~>) a data Input (~>) a type TV (~>) a
type KIO = Kleisli IO
2.5 Common Ins and Outs
The examplestype Common f a = forall (~>). CommonInsOuts (~>) => f (~>) a
type CInput a = Common Input a type COutput a = Common Output a type CTV a = Common TV a
2.6 Sorting examples
Here's a sorting TV:
sortT :: (Read a, Show a, Ord a) => CTV ([a] -> [a]) sortT = tv (oTitle "sort" $ interactRSOut []) sort
2.7 Composition of TVs
So far, we done a little composition of interfaces and combined them with values to construct TVs. Now let's look at composition of TVs.
First, wrap up thewordsT :: CTV (String -> [String]) wordsT = tv ( oTitle "function: words" $ oLambda (iTitle "sentence in" defaultIn) (oTitle "words out" defaultOut)) words
unwordsT :: CTV ([String] -> String) unwordsT = tv ( oTitle "function: unwords" $ oLambda (iTitle "words in" defaultIn) (oTitle "sentence out" defaultOut)) unwords
sortWordsT :: CTV (String -> String) sortWordsT = wordsT ->| sortT ->| unwordsT
Running:
The operator "<div class="inline-code">
runUI sortWordsT runIO sortWordsT![]()
*Examples> runIO sortWordsT sentence in: The night Max wore his wolf suit sentence out: Max The his night suit wolf wore
2.8 Arrow-specific interfaces
While some interfaces can be implemented for different kinds of interfaces, others are more specialized.
2.8.1 GUIs
Here are inputs for our shopping example above that specifically work with Phooey's UI arrow.
applesU, bananasU :: Input UI Int applesU = iTitle "apples" (islider 3 (0,10)) bananasU = iTitle "bananas" (islider 7 (0,10)) shoppingUO :: Output UI (Int -> Int -> Int) shoppingUO = oTitle "shopping list" $ oLambda applesU (oLambda bananasU total)
We can then make curried and uncurried TVs:
Note: We could define other type classes, besides
code runUI rendering tv shoppingUO (+)![]()
uncurryA $$ tv shoppingUO (+)![]()
2.8.2 IO
We can useinteractOut :: Output KIO (String -> String) interactOut = oLambda contentsIn stringOut
Assuming we have a file "test.txt" containing some lines of text, we can use it to test string transformations.
testO :: Output KIO (String -> String) testO = oLambda (fileIn "test.txt") defaultOut
wrapF :: (c->d) -> (a->b) -> ((b->c) -> (a->d)) wrapF after before f = after . f . before
onLines, onWords :: ([String] -> [String]) -> (String -> String) onLines = wrapF unlines lines onWords = wrapF unwords words
io3 = tv testO (onLines reverse) io4 = tv testO (onWords reverse)
Categories: Interfaces | User Interfaces | IO | Arrow | Libraries | Packages









