1 / 24

T ask O riented P rogramming i n using Rinus Plasmeijer – Bas Lijnse - Peter Achten

T ask O riented P rogramming i n using Rinus Plasmeijer – Bas Lijnse - Peter Achten Pieter Koopman - Steffen Michels - Jurriën Stutterheim Jan Martin Jansen (NLDA) - Laszlo Domoszlai (ELTE) ASSIGNMENTS - ANSWERS. 1. Getting started: additional information.

tiger
Download Presentation

T ask O riented P rogramming i n using Rinus Plasmeijer – Bas Lijnse - Peter Achten

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Task Oriented Programming in using Rinus Plasmeijer–Bas Lijnse- Peter Achten Pieter Koopman- Steffen Michels-JurriënStutterheim Jan Martin Jansen (NLDA) - Laszlo Domoszlai (ELTE) ASSIGNMENTS - ANSWERS

  2. 1. Getting started: additional information • Once you have successfully created an iTask application and started it, you and anybody can connect to it via a web browser. • If you only want to test the application for yourself, it is sufficient to navigate to http://localhost/. • If you want other people to use your application as well (as with the Ligretto case study), then these persons need to navigate to the IP-address of your computer. • In both cases, the application uses the web browser for the interaction with your program(s).

  3. 2. Tasks panel • The function basicAPIExamplesin the main module BasicAPIExamples.iclenumerates all tasks that can be explored by the user(s). • An element in this list is specified with: • workflow task_tree_specbrief_explanation task • in which: • task_tree_spec: • is a string of shape g1/g2/…/gn/task_name such that the names gi are used to group similar tasks, and task_nameis the name of the task • brief_explanation: • is a short string that explains the purpose of executing this task • task: • a task of any arbitrary result value

  4. 3. Persistent tasks • In the iTask system all tasks are persistent, i.e.: their state is stored in background storage at all times. • Consequently, it does not matter if you stop working on that task for a period of time, or simply close your browser and reconnect later. • It is possible to completely erase all background storage. On your computer, navigate to the folder in which your main module is located. Suppose your main module is called 'main.icl'. You should find a folder called 'main.exe-data'. Simply remove this folder. • For instance, in the case of BasicAPIExamples, navigate to '\iTasks-SDK\Examples\' and remove the folder 'BasicAPIExamples.exe-data'

  5. 4. Custom types • The iTask system is a domain specific language for defining dynamic workflow style application. It is embedded in the host language Clean. • The implementation of the iTask system uses the generic programming facilities of Clean to automatically create web pages for any custom data type that you can think of. • If you create a new type and want the iTask system to be able to use it, then you need to invoke the generic programming mechanism for that type. • In the case of the MyPerson type, this looks as follows:derive class iTask MyPerson • If you forget to include this derive class declaration in your code you will get swamped with lots of compiler error messages, e.g.:Overloading error [BasicAPIExamples.icl,66,Start]: "JSONEncode_s" no instance available of type MyPersonOverloading error [BasicAPIExamples.icl,66,Start]: "gVisualizeText_s" no instance available of type MyPersonOverloading error [BasicAPIExamples.icl,66,Start]: "gHeaders_s" no instance available of type MyPersonOverloading error [BasicAPIExamples.icl,66,Start]: "gGridRows_s" no instance available of type MyPersonOverloading error [BasicAPIExamples.icl,66,Start]: "gDefault_s" no instance available of type MyPerson…

  6. 5. Customized view • The basic interactive tasks enterInformation, update(Shared)Information, view(Shared)Information, and so on can be fine-tuned by means of a list of options. • Currently, these options concern only the way the task value is rendered. • In a future version, more option-types will be added to these lists.

  7. Intermezzo • During the lab sessions we suggested to put new Clean implementation and definition modules in the same folder as the BasicAPIExamples.icl module. • It is better practice to store modules that belong to each other in a separate module. • In that case you need to add the directory-path to these modules in your project file. In the CleanIDEthis can be done as follows: • choose 'Project:Project Options…' • this opens the project window (right) • choose 'Project Paths' • this opens the project paths window • choose the 'Append…' button • navigate to the folder(s) that you wish toadd • choose the 'OK' button to confirm

  8. 6. Play with HTML • The Html type is quite a large algebraic data type. You can find its definition in module HTML.dcl. If you are already familiar with html, then you probably recognize most of the tags being coded as data constructors of this type. • The Html and HtmlAtts types are examples of deeply embedded domain specific languages, in this case for representing html.

  9. 7. Viewing a Player • A possible solution to view_player is the following: • view_player :: Player -> Task Playerview_playerplayer • = viewInformation("Player " <+++ player.color) [ViewWithplayer_view] player • player_view :: !Player -> HtmlTag • player_view player • = TableTag[BorderAttr"2"] [view_rowplayer.row • ,view_ligrettoplayer.ligretto • ,view_handplayer.hand • ] • This definition shows, in left-to-right order, the row, ligretto pile, and the two hand piles (concealed and discarded cards) of the player.

  10. 8. Viewing the middle piles • A possible solution to view_piles is: • view_piles:: [Pile] -> Task [Pile]view_piles piles • = viewInformation"Piles" [ViewWithpiles_view] piles • piles_view :: ![Pile] -> HtmlTag • piles_view piles • = TableTag[BorderAttr"2"] • [ TrTag[] [ if (isEmpty pile) (TdTag[] [Text "empty!"]) • (view_cardFront (hd pile)) • \\ pile <- piles • ] • , TrTag[] [ TdTag[] [Text (toStringi)] \\ i <- [1..length piles] ] • ] • this definition shows all piles of cards in a single row; underneath each (empty) pile a number is shown as well (1 upto maximum number of piles)

  11. 9. Add people • The iTask system is a distributed, multi-user system. The currently registered users are stored in a shared data source, called userAccounts (module UserAdmin.dcl). • This module contains a number of useful functions to get access to the current users (shared data source users), find users with a certain role (usersWithRole), authentication (authenticateUser), and more…

  12. 10. Invite friends • A solution to invite_friends is: • invite_friends:: Task [User] • invite_friends • = enterSharedMultipleChoice"Select friends to play with" [] users • >>= \friends -> if (not (isMember (length friends) [1..3])) • ( viewInformation"Oops" [] • "number of friends must be 1, 2, or 3" • >>|invite_friends • ) • ( return friends ) • This defines a recursive task that keeps asking the current user to enter 1 upto 3 persons from the users shared data source

  13. 11. Shared data source • Solutions to middle_state and player_state shared data sources are: • middle_state :: Shared Middle • middle_state • = sharedStore "middle" (repeat 16 []) • player_state :: Color -> Shared Player • player_state color • = sharedStore ("player " <+++ color) • {color = color, row = [], ligretto = [], hand = {conceal = [], discard = []}} • The first argument of the sharedStore function is used as unique identifier of the shared data store that is to be created. Therefor, the players are identified using their color. • The second argument of the sharedStore function is the initial value of the shared data store. • In case of the Ligretto case, the initial player value is overwritten once a game starts, providing the player with cards.

  14. 12. Viewing the middle piles, now as shared view • Solutions to viewing the piles and players are (changes are underlined): • view_player:: Player -> Task Player • view_playerplayer • = viewSharedInformation("Player " <+++ player.color) • [ViewWithplayer_view] • (player_stateplayer.color) • view_piles:: Task [Pile] • view_piles • = viewSharedInformation"Middle" [ViewWithpiles_view] middle_state • Instead of looking at a particular value (with viewInformation) your application now looks at a shared data source (with viewSharedInformation). As an effect, whenever the shared data source is altered the view is updated is well. • Note that the altered view_pilestask no longer requires a [Pile] argument, as it gets its information from the middle_state shared data source.

  15. 13. One player plays a game of Ligretto • A possible solution to the game function is: • game :: NrOfPlayersColor-> Task Color • game nr_of_playerscolor • = get randomInt • >>= \r -> let player = initial_playernr_of_playerscolor (abs r) in  • setplayer (player_statecolor)  • >>| view_piles • ||- view_playerplayer  • ||- play_cardsnr_of_playersplayer  •  obtain a random number from the randomIntshared data source •  create a new player with shuffled cards and proper row, ligretto, and hand •  set this new player value in the corresponding shared data source •  look at the middle piles •  look at yourself •  start to play cards according to the rules yet to be defined in play_cards

  16. 14. Playing the cards • The suggested structure for the play_cards task is: • play_cards :: NrOfPlayers Player -> Task Color • play_cardsnr_of_players player • = watch (player_statecolor>+<middle_state) • >>* • (watch sds)is a task that continuously keeps an eye on the read value of sds. The task value of (watch sds) is always that of the read value of sds. • (sds1 >+< sds2) turns two separate shared data sources, sds1 and sds2, into one shared data source. The read value of the new shared data source is (r1, r2), with ri the read value of sdsi. The write value of the new shared data source is (w1, w2), with wi the write value of sdsi. • (t >>* steps) is a new task that performs task t while keeping an eye on the task value tvof t. The list steps enumerate all possible ways to continue from here, based on tv. There are four kinds of steps: • (OnValuetf): perform a task depending on (tftv) • (OnActionaction tf): provide user with action to do a task depending on (tftv) • (OnExceptiontf): catch specific exception e and do task depending on (tf e) • (OnAllExceptionstf): catch any exception as str and do task depending on (tfstr)

  17. 14. Playing the cards • The suggested structure for the play_cards task is: • play_cards :: NrOfPlayers Player -> Task Color • play_cardsnr_of_players player • = watch (player_statecolor>+<middle_state) • >>* • Finish  with appropriate actions (OnAction): • the player can put a row card on a (new) pile in the middle • the player can put the top discard hand card on a (new) pile in the middle • the player can move the top three cards from conceal to discard pile • the player can shuffle all discard cards to restart with the conceal pile • Finish  with an appropriate predicate (OnValue): • immediately when the ligretto pile is empty, return the color of the player

  18. 14. Playing the cards:1. put a row card on a (new) pile in the middle • Offer the actions to the user (summarize with a list comprehension): • [ OnAction(Action ("Play card " <+++ cardnr) []) • (play_cardnr_of_players player cardnr) • \\ cardnr <- [1 .. nr_of_cards_in_rownr_of_players] • ] • The action can only be performed if a middle pile matches: • play_card :: NrOfPlayers Player Int (TaskValue (Player,Middle)) -> Maybe (Task Color) • play_cardnr_of_players player cardnr (Value (me, middle) _) • | not (isEmptymatching_piles) • = let (index,pile) = hdmatching_piles in • Just( update(updateAt index [card : pile]) middle_state • >>| set(move_ligretto_card_to_rowcardnr me) (player_stateplayer.color) • >>| play_cardsnr_of_players player • ) • where card= row_cardcardnr me • matching_piles = [ (index,pile) \\ pile <- middle & index <- [0 ..] • | card_matches_top_of_pile card pile ] • play_card _ _ _ _ = Nothing

  19. 14. Playing the cards:2. put top discard card on a (new) pile in the middle • Offer the action to the user: • OnAction(Action "Play hand" []) (play_handnr_of_players player) • The action can only be performed if the discard pile has a card and a middle pile matches: • play_hand :: NrOfPlayers Player (TaskValue (Player,Middle)) -> Maybe (Task Color) • play_handnr_of_players player (Value (me, middle) _) • | isJustmaybe_card && not (isEmptymatching_piles) • = let (index,pile) = hdmatching_piles in • Just( update(updateAt index [card : pile]) middle_state • >>| set (remove_top_of_discard me) (player_stateplayer.color) • >>| play_cardsnr_of_players player • ) • where maybe_card = top_discard me • card= fromJustmaybe_card • matching_piles= [ (index,pile) \\ pile <- middle & index <- [0..] • | card_matches_top_of_pile card pile] • play_hand _ _ _ = Nothing

  20. 14. Playing the cards:3. move top 3 concealed cards to discard pile • Offer the action to the user: • OnAction(Action "Next hand" []) (next_handnr_of_playersplayer) • The action can only be performed if the concealed pile is not empty: • next_hand:: NrOfPlayers Player (TaskValue (Player,Middle)) -> Maybe (Task Color) • next_handnr_of_players player (Value (me, middle) _) • | not (isEmpty conceal) • = Just( set(swap_discards me) (player_stateplayer.color) • >>| play_cardsnr_of_players player • ) • where conceal = me.hand.conceal • next_hand_ _ _ = Nothing

  21. 14. Playing the cards:4. shuffle all discard cards and make them concealed • Offer the action to the user: • OnAction(Action "Shuffle hand" []) (shufflenr_of_playersplayer) • The action can only be performed if the concealed pile is empty: • shuffle :: NrOfPlayers Player (TaskValue (Player,Middle)) -> Maybe (Task Color) • shuffle nr_of_players player (Value (me, middle) _) • | isEmptyconceal • = Just( get randomInt • >>= \r -> set (shuffle_hand (abs r) me) (player_stateplayer.color) • >>| play_cardsnr_of_players player • ) • where conceal= me.hand.conceal • shuffle _ _ _ = Nothing

  22. 14. Playing the cards:5. return when ligretto pile is empty • Offer the predicate to the step combinator: • OnValueplayer_wins • Return color of player only if the ligretto pile is empty: • player_wins :: (TaskValue (Player,Middle)) -> Maybe (Task Color) • player_wins (Value (me, middle) _) • | isEmptyme.ligretto = Just (returnme.color) • player_wins _ = Nothing

  23. 14. Playing the cards: include 1. upto 5. • Thus, the complete solution for the play_cards task is: • play_cards :: NrOfPlayers Player -> Task Color • play_cardsnr_of_players player • = watch (player_statecolor>+<middle_state) • >>*( [ OnAction(Action ("Play card "<+++cardnr) []) • (play_cardnr_of_players player cardnr) • \\ cardnr <- [1 .. nr_of_cards_in_rownr_of_players] • ] • ++ [ OnAction(Action "Play hand" []) (play_handnr_of_playersplayer) • , OnAction(Action "Next hand" []) (next_handnr_of_players player) • , OnAction(Action "Shuffle hand" []) (shuffle nr_of_players player) • , OnValueplayer_wins • ] • )

  24. 15. All players play a game of Ligretto • A possible solution to the main task play_ligretto is: • play_ligretto :: Task Color • play_ligretto • = get currentUser • >>= \me -> invite_friends • >>= \friends -> set (repeatn 16 []) middle_state • >>| let nr_of_players = length friends + 1 in • anyTask • [ player @: game nr_of_playerscolor • \\ player <- [me : friends] & color <- colorsnr_of_players • ] • >>= \winner -> allTasks • [ player @: (viewInformation"The winner is:" [] winner >>= return) • \\ player <- [me : friends] • ] • >>| return winner

More Related