Permalink
Browse files

integrated conal's darcs repo

  • Loading branch information...
0 parents commit af02f71e39a27a937292a7525c13871802711d50 @ekmett committed Feb 20, 2011
Showing with 5,757 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +661 −0 COPYING
  3. +1 −0 Makefile
  4. +32 −0 README
  5. +3 −0 Setup.lhs
  6. +9 −0 announce
  7. +29 −0 changes.tw
  8. +88 −0 reactive.cabal
  9. +159 −0 src/Data/AddBounds.hs
  10. +30 −0 src/Data/Max.hs
  11. +28 −0 src/Data/Min.hs
  12. +40 −0 src/Data/PairMonad.hs
  13. +311 −0 src/Examples.hs
  14. +49 −0 src/FRP/Reactive.hs
  15. +342 −0 src/FRP/Reactive/Behavior.hs
  16. +151 −0 src/FRP/Reactive/Fun.hs
  17. +224 −0 src/FRP/Reactive/Future.hs
  18. +215 −0 src/FRP/Reactive/Improving.hs
  19. +80 −0 src/FRP/Reactive/Internal/Behavior.hs
  20. +149 −0 src/FRP/Reactive/Internal/Chan.hs
  21. +57 −0 src/FRP/Reactive/Internal/Clock.hs
  22. +18 −0 src/FRP/Reactive/Internal/Fun.hs
  23. +86 −0 src/FRP/Reactive/Internal/Future.hs
  24. +122 −0 src/FRP/Reactive/Internal/IVar.hs
  25. +20 −0 src/FRP/Reactive/Internal/Misc.hs
  26. +258 −0 src/FRP/Reactive/Internal/Reactive.hs
  27. +35 −0 src/FRP/Reactive/Internal/Serial.hs
  28. +276 −0 src/FRP/Reactive/Internal/TVal.hs
  29. +112 −0 src/FRP/Reactive/Internal/Timing.hs
  30. +26 −0 src/FRP/Reactive/LegacyAdapters.hs
  31. +112 −0 src/FRP/Reactive/Num-inc.hs
  32. +115 −0 src/FRP/Reactive/Num.hs
  33. +957 −0 src/FRP/Reactive/PrimReactive.hs
  34. +390 −0 src/FRP/Reactive/Reactive.hs
  35. +173 −0 src/FRP/Reactive/SImproving.hs
  36. +77 −0 src/FRP/Reactive/Sorted.hs
  37. +21 −0 src/FRP/Reactive/VectorSpace.hs
  38. +3 −0 src/Test.hs
  39. +52 −0 src/Test/Integ.hs
  40. +89 −0 src/Test/Merge.hs
  41. +35 −0 src/Test/Reactive.hs
  42. +92 −0 src/Test/SimpleFilter.hs
  43. +28 −0 src/Test/Snap.hs
2 .gitignore
@@ -0,0 +1,2 @@
+_darcs
+dist
661 COPYING
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
1 Makefile
@@ -0,0 +1 @@
+include ../cho-cabal-make.inc
32 README
@@ -0,0 +1,32 @@
+_Reactive_ [1] is a simple foundation for programming reactive systems
+functionally. Like Fran/FRP, it has a notions of (reactive) behaviors and
+events. Like DataDriven [2], Reactive has a data-driven implementation.
+
+The inspiration for Reactive was Mike Sperber's Lula [3] implementation of
+FRP. Mike used blocking threads, which I had never considered for FRP.
+While playing with the idea, I realized that I could give a very elegant
+and efficient solution to caching, which DataDriven doesn't do. (For an
+application "f <*> a" of a varying function to a varying argument, caching
+remembers the latest function to apply to a new argument and the last
+argument to which to apply a new function.)
+
+The theory and implementation of Reactive are described in the paper
+"Push-pull functional reactive programming" [4].
+
+Note that cabal[5], version 1.4.0.1 or greater is required for installation.
+
+You can configure, build, and install all in the usual way with Cabal
+commands.
+
+ runhaskell Setup.lhs configure
+ runhaskell Setup.lhs build
+ runhaskell Setup.lhs install
+
+
+References:
+
+[1] http://haskell.org/haskellwiki/Reactive
+[2] http://haskell.org/haskellwiki/DataDriven
+[3] http://www-pu.informatik.uni-tuebingen.de/lula/deutsch/publications.html
+[4] http://conal.net/papers/push-pull-frp/
+[5] http://www.haskell.org/cabal/download.html
3 Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
9 announce
@@ -0,0 +1,9 @@
+Reactive [1] is a library for functional reactive programming (FRP), similar to the original Fran [2] but with a more modern interface (using standard type classes) and a hybrid push/pull implementation. It is designed to be used in a variety of contexts, such as interactive 2D and 3D graphics, graphical user interfaces, web services, and automatic recompilation/re-execution. It has a simple and precise semantics based on continuous time and is built on a notion of functional future values. The semantics and implementation are described in the paper "Simply efficient functional reactivity" [3].
+
+Reactive now has a mailing list [4] and a feature/bug tracker [5].
+
+[1] http://haskell.org/haskellwiki/Reactive
+[2] http://conal.net/Fran
+[3] http://conal.net/papers/simply-reactive
+[4] http://www.haskell.org/mailman/listinfo/reactive
+[5] http://trac.haskell.org/reactive
29 changes.tw
@@ -0,0 +1,29 @@
+== Version 0 ==
+
+=== Version 0.8 ===
+
+=== Version 0.8.1 ===
+
+* Adding QuickCheck tests.
+
+''Fill in missing versions''
+
+
+=== Version 0.3 ===
+
+* Commented out LANGUAGE pragmas and added OPTIONS_GHC -fglasgow-exts for ghc-6.6 compatibility.
+
+=== Version 0.2 ===
+
+* Fixed <hask>switcher</hask>. Didn't terminate. Thanks to Ivan Tomac for the bug report.
+
+=== Version 0.1 ===
+
+* Added <hask>Never</hask> constructor for Future. Allows optimizations, including a huge improvement for <hask>(>>=)</hask> on <hask>Event</hask> (which had been piling up <hask>never</hask>s).
+* removed <code>-threaded</code> comment
+* added <hask>traceR</hask> (reactive value tracing)
+* use idler in <code>src/Examples.hs</code> (for single-threaded use of wxHaskell)
+
+=== Version 0.0 ===
+
+* New project.
88 reactive.cabal
@@ -0,0 +1,88 @@
+Name: reactive
+Version: 0.11.5
+Synopsis: Push-pull functional reactive programming
+Category: reactivity, FRP
+Description:
+ /Reactive/ is a simple foundation for programming reactive systems
+ functionally. Like Fran\/FRP, it has a notions of (reactive) behaviors and
+ events. Unlike most previous FRP implementations, Reactive has a hybrid
+ demand/data-driven implementation, as described in the paper \"Push-pull
+ functional reactive programming\", <http://conal.net/papers/push-pull-frp/>.
+ .
+ This version of Reactive has some serious bugs that show up particularly
+ with some uses of the Event monad. Some problems have been due to bugs
+ in the GHC run-time support for concurrency. I do not know whether the
+ remaining problems in Reactive are still more subtle RTS issues, or
+ some subtle laziness bugs in Reactive. Help probing the remaining
+ difficulties is most welcome.
+ .
+ Import "FRP.Reactive" for FRP client apps. To make a Reactive adapter for an
+ imperative library, import "FRP.Reactive.LegacyAdapters".
+ .
+ Please see the project wiki page: <http://haskell.org/haskellwiki/reactive>
+ .
+ &#169; 2007-2009 by Conal Elliott; GNU AGPLv3 license (see COPYING).
+ I am not thrilled with GPL, and I doubt I'll stay with it for long.
+ If you would like different terms, please talk to me.
+ .
+ With contributions from: Robin Green, Thomas Davie, Luke Palmer,
+ David Sankel, Jules Bean, Creighton Hogg, Chuan-kai Lin, and Richard
+ Smith. Please let me know if I've forgotten to list you.
+
+Author: Conal Elliott
+Maintainer: conal@conal.net
+Homepage: http://haskell.org/haskellwiki/reactive
+Package-Url: http://code.haskell.org/reactive
+Bug-Reports: http://trac.haskell.org/reactive
+
+Copyright: (c) 2007-2009 by Conal Elliott
+Cabal-Version: >= 1.2
+License: OtherLicense
+License-File: COPYING
+Stability: provisional
+Build-Type: Simple
+Extra-Source-Files:
+Library
+ Build-Depends: base >=4 && <5, old-time, random, QuickCheck >= 2.1.0.2,
+ TypeCompose>=0.8.0, vector-space>=0.5,
+ unamb>=0.1.5, checkers >= 0.2.3,
+ category-extras >= 0.53.5, Stream >= 0.3.1
+ -- This library uses the ImpredicativeTypes flag, and it depends
+ -- on vector-space, which needs ghc >= 6.9
+ if impl(ghc < 6.9) {
+ buildable: False
+ }
+ Hs-Source-Dirs: src
+ Exposed-Modules:
+ FRP.Reactive
+
+ FRP.Reactive.Future
+ FRP.Reactive.PrimReactive
+ FRP.Reactive.Reactive
+ FRP.Reactive.Behavior
+ FRP.Reactive.Fun
+ FRP.Reactive.Improving
+ FRP.Reactive.Num
+ FRP.Reactive.VectorSpace
+
+ FRP.Reactive.Internal.Misc
+ FRP.Reactive.Internal.Fun
+ FRP.Reactive.Internal.Future
+ FRP.Reactive.Internal.Reactive
+ FRP.Reactive.Internal.Behavior
+ FRP.Reactive.Internal.Clock
+ FRP.Reactive.Internal.Timing
+ FRP.Reactive.Internal.Chan
+
+ FRP.Reactive.LegacyAdapters
+
+ Data.AddBounds
+ Data.Min
+ Data.Max
+ Data.PairMonad
+ -- Probably eliminate the next few
+ FRP.Reactive.Internal.IVar
+ FRP.Reactive.Internal.Serial
+ FRP.Reactive.Internal.TVal
+
+ ghc-options: -Wall
159 src/Data/AddBounds.hs
@@ -0,0 +1,159 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module : Data.AddBounds
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Add bounds to an ordered type
+----------------------------------------------------------------------
+
+module Data.AddBounds (AddBounds(..)) where
+
+import Control.Applicative (pure,(<$>))
+
+import Data.Unamb (unamb)
+
+import Data.AffineSpace
+
+-- Testing
+import Test.QuickCheck
+import Test.QuickCheck.Checkers
+
+
+-- | Wrap a type into one having new least and greatest elements,
+-- preserving the existing ordering.
+data AddBounds a = MinBound | NoBound a | MaxBound
+ deriving (Eq {-, Ord-}, Read, Show)
+
+instance Bounded (AddBounds a) where
+ minBound = MinBound
+ maxBound = MaxBound
+
+
+-- Normally, I'd derive 'Ord' as well, but there's a sticky point. The
+-- derived instance uses the default definition of 'min', which is uses
+-- '(<=)' and thus cannot exploit any partial information. So, define our
+-- own 'min' in terms of 'min' on @a@.
+-- Examples:
+-- (NoBound undefined) `min` (NoBound undefined) can return (NoBound _|_)
+-- using this definition, but will not produce any output using the
+-- default min.
+--
+-- (NoBound a) `min` (NoBound b) can return partial information from
+-- a `min` b while the default implementation cannot.
+
+-- instance Ord a => Ord (AddBounds a) where
+-- MinBound <= _ = True
+-- NoBound _ <= MinBound = False
+-- NoBound a <= NoBound b = a <= b
+-- NoBound _ <= MaxBound = True
+-- MaxBound <= MaxBound = True
+-- MaxBound <= _ = False -- given previous
+
+-- MinBound `min` _ = MinBound
+-- _ `min` MinBound = MinBound
+-- NoBound a `min` NoBound b = NoBound (a `min` b)
+-- u `min` MaxBound = u
+-- MaxBound `min` v = v
+
+-- MinBound `max` v = v
+-- u `max` MinBound = u
+-- NoBound a `max` NoBound b = NoBound (a `max` b)
+-- _ `max` MaxBound = MaxBound
+-- MaxBound `max` _ = MaxBound
+
+
+-- The definition above is too strict for some uses. Here's a parallel
+-- version.
+
+
+-- Alternatively, make a non-parallel definition here and use 'pmin'
+-- instead of 'min' where I want.
+
+
+-- General recipe for Ord methods: use unamb to try two strategies. The
+-- first one, "justB", only examines b. The second one first examines
+-- only examines a and then examines both. I take care that the two
+-- strategies handle disjoint inputs. I could instead let the second
+-- strategy handle the first one redundantly, being careful that they
+-- agree.
+
+-- This instance is very like the one Richard Smith (lilac) constructed.
+-- It fixes a couple of small bugs and follows a style that helps me see
+-- that I'm covering all of the cases with the evaluation order I want.
+
+instance Ord a => Ord (AddBounds a) where
+ a <= b = justB b `unamb` (a <=* b)
+ where
+ justB MaxBound = True
+ justB _ = undefined
+
+ MinBound <=* _ = True
+ _ <=* MinBound = False
+ NoBound u <=* NoBound v = u <= v
+ MaxBound <=* NoBound _ = False
+ _ <=* MaxBound = undefined
+
+ a `min` b = justB b `unamb` (a `min'` b)
+ where
+ justB MinBound = MinBound
+ justB MaxBound = a
+ justB (NoBound _) = undefined
+
+ MinBound `min'` _ = MinBound
+ MaxBound `min'` v = v
+ NoBound u `min'` NoBound v = NoBound (u `min` v)
+ _ `min'` MinBound = undefined
+ _ `min'` MaxBound = undefined
+
+ a `max` b = justB b `unamb` (a `max'` b)
+ where
+ justB MaxBound = MaxBound
+ justB MinBound = a
+ justB (NoBound _) = undefined
+
+ MaxBound `max'` _ = MaxBound
+ MinBound `max'` v = v
+ NoBound u `max'` NoBound v = NoBound (u `max` v)
+ _ `max'` MaxBound = undefined
+ _ `max'` MinBound = undefined
+
+
+-- instance Arbitrary a => Arbitrary (AddBounds a) where
+-- arbitrary = frequency [ (1 ,pure MinBound)
+-- , (10, NoBound <$> arbitrary)
+-- , (1 ,pure MaxBound) ]
+-- coarbitrary MinBound = variant 0
+-- coarbitrary (NoBound a) = variant 1 . coarbitrary a
+-- coarbitrary MaxBound = variant 2
+
+instance Arbitrary a => Arbitrary (AddBounds a) where
+ arbitrary = frequency [ (1 ,pure MinBound)
+ , (10, NoBound <$> arbitrary)
+ , (1 ,pure MaxBound) ]
+
+instance CoArbitrary a => CoArbitrary (AddBounds a) where
+ coarbitrary MinBound = variant (0::Int)
+ coarbitrary (NoBound a) = variant (1::Int) . coarbitrary a
+ coarbitrary MaxBound = variant (2::Int)
+
+instance (EqProp a, Eq a) => EqProp (AddBounds a) where
+ NoBound a =-= NoBound b = a =-= b
+ u =-= v = u `eq` v
+
+
+-- Hm. I'm dissatisfied with this next instance. I'd like to tweak my
+-- type definitions to eliminate these partial definitions.
+
+instance AffineSpace t => AffineSpace (AddBounds t) where
+ type Diff (AddBounds t) = Diff t
+ NoBound u .-. NoBound v = u .-. v
+ -- I don't know what to do here
+ _ .-. _ = error "(.-.) on AddBounds: only defined on NoBound args"
+ NoBound u .+^ v = NoBound (u .+^ v)
+ _ .+^ _ = error "(.+^) on AddBounds: only defined on NoBound args"
30 src/Data/Max.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# OPTIONS -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module : Data.Max
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Max monoid
+----------------------------------------------------------------------
+
+module Data.Max (Max(..)) where
+
+
+import Data.Monoid (Monoid(..))
+
+import Test.QuickCheck (Arbitrary, CoArbitrary)
+import Test.QuickCheck.Checkers (EqProp)
+
+
+-- | Ordered monoid under 'max'.
+newtype Max a = Max { getMax :: a }
+ deriving (Eq, Ord, Bounded, Read, Show, EqProp, Arbitrary, CoArbitrary)
+
+instance (Ord a, Bounded a) => Monoid (Max a) where
+ mempty = Max minBound
+ Max a `mappend` Max b = Max (a `max` b)
28 src/Data/Min.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# OPTIONS -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module : Data.Min
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Min monoid
+----------------------------------------------------------------------
+
+module Data.Min (Min(..)) where
+
+import Data.Monoid (Monoid(..))
+
+import Test.QuickCheck (Arbitrary)
+import Test.QuickCheck.Checkers (EqProp)
+
+-- | Ordered monoid under 'min'.
+newtype Min a = Min { getMin :: a }
+ deriving (Eq, Ord, Read, Show, Bounded, EqProp, Arbitrary)
+
+instance (Ord a, Bounded a) => Monoid (Min a) where
+ mempty = Min maxBound
+ Min a `mappend` Min b = Min (a `min` b)
40 src/Data/PairMonad.hs
@@ -0,0 +1,40 @@
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+----------------------------------------------------------------------
+-- |
+-- Module : Data.PairMonad
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Writer monad as a pair. Until it's in Control.Monad.Instances.
+--
+-- Use @import Data.PairMonad ()@
+----------------------------------------------------------------------
+
+module Data.PairMonad () where
+
+import Data.Monoid
+import Control.Applicative
+
+
+-- Orphan instance:
+
+-- Equivalent to the Monad Writer instance.
+instance Monoid o => Monad ((,) o) where
+ return = pure
+ (o,a) >>= f = (o `mappend` o', a') where (o',a') = f a
+
+-- Alternatively,
+-- m >>= f = join (fmap f m)
+-- where
+-- join ((o, (o',a))) = (o `mappend` o', a)
+-- Or even,
+-- (o,a) >>= f = (o,id) <*> f a
+--
+-- I prefer the join version, because it's the standard (>>=)-via-join,
+-- plus a very simple definition for join. Too bad join isn't a method of
+-- Monad, with (>>=) and join defined in terms of each other. Why isn't
+-- it? Probably because Monad isn't derived from Functor. Was that an
+-- oversight?
311 src/Examples.hs
@@ -0,0 +1,311 @@
+{-# LANGUAGE TypeOperators, FlexibleContexts, TypeSynonymInstances, FlexibleInstances #-}
+
+----------------------------------------------------------------------
+-- |
+-- Module : Examples
+-- Copyright : (c) Conal Elliott 2007
+-- License : BSD3
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Simple test for Reactive
+----------------------------------------------------------------------
+
+-- module Main where
+
+-- base
+import Data.Monoid
+import Data.IORef
+import Control.Monad
+import Control.Applicative
+import Control.Arrow (first,second)
+import Control.Concurrent (yield, forkIO, killThread, threadDelay, ThreadId)
+
+-- wxHaskell
+import Graphics.UI.WX hiding (Event,Reactive)
+import qualified Graphics.UI.WX as WX
+-- TypeCompose
+import Control.Compose ((:.)(..), inO,inO2)
+import Data.Title
+
+-- Reactive
+import Reactive.Reactive
+
+
+{--------------------------------------------------------------------
+ Mini-Phooey
+--------------------------------------------------------------------}
+
+type Win = Panel ()
+
+type Wio = ((->) Win) :. IO :. (,) Layout
+
+type Wio' a = Win -> IO (Layout,a)
+
+
+wio :: Wio' a -> Wio a
+wio = O . O
+
+unWio :: Wio a -> Wio' a
+unWio = unO . unO
+
+inWio :: (Wio' a -> Wio' b) -> (Wio a -> Wio b)
+inWio f = wio . f . unWio
+
+inWio2 :: (Wio' a -> Wio' b -> Wio' c) -> (Wio a -> Wio b -> Wio c)
+inWio2 f = inWio . f . unWio
+
+instance Title_f Wio where
+ title_f str = inWio ((fmap.fmap.first) (boxed str))
+
+-- Bake in vertical layout. See phooey for flexible layout.
+instance Monoid Layout where
+ mempty = WX.empty
+ mappend = above
+
+instance Monoid a => Monoid (Wio a) where
+ mempty = wio mempty
+ mappend = inWio2 mappend
+
+type WioE a = Wio (Event a)
+type WioR a = Wio (Reactive a)
+
+buttonE :: String -> WioE ()
+buttonE str = wio $ \ win ->
+ do (e, snk) <- mkEvent
+ b <- button win [ text := str, on command := snk () ]
+ return (hwidget b, e)
+
+buttonE' :: String -> a -> WioE a
+buttonE' str a = (a `replace`) <$> buttonE str
+
+sliderE :: (Int,Int) -> Int -> WioE Int
+sliderE (lo,hi) initial = wio $ \ win ->
+ do (e, snk) <- mkEvent
+ s <- hslider win True lo hi
+ [ selection := initial ]
+ set s [ on command := getAttr selection s >>= snk ]
+ return (hwidget s, e)
+
+sliderR :: (Int,Int) -> Int -> WioR Int
+sliderR lh initial = stepper initial <$> sliderE lh initial
+
+stringO :: Wio (Sink String)
+stringO = attrO (flip textEntry []) text
+
+-- Make an output. The returned sink collects updates. On idle, the
+-- latest update gets stored in the given attribute.
+attrO :: Widget w => (Win -> IO w) -> Attr w a -> Wio (Sink a)
+attrO mk attr = wio $ \ win ->
+ do ctl <- mk win
+ ref <- newIORef Nothing
+ setAttr (on idle) win $
+ do readIORef ref >>= maybe mempty (setAttr attr ctl)
+ writeIORef ref Nothing
+ return True
+ return (hwidget ctl , writeIORef ref . Just)
+
+-- -- The following alternative ought to be more efficient. Oddly, the timer
+-- -- doesn't get restarted, although enabled gets set to True.
+
+-- stringO = wio $ \ win ->
+-- do ctl <- textEntry win []
+-- ref <- newIORef (error "stringO: no initial value")
+-- tim <- timer win [ interval := 10, enabled := False ]
+-- let enable b = do putStrLn $ "enable: " ++ show b
+-- setAttr enabled tim b
+-- set tim [ on command := do putStrLn "timer"
+-- readIORef ref >>= setAttr text ctl
+-- enable False
+-- ]
+-- return ( hwidget ctl
+-- , \ str -> writeIORef ref str >> enable True )
+
+showO :: Show a => Wio (Sink a)
+showO = (. show) <$> stringO
+
+showR :: Show a => WioR (Sink a)
+showR = pure <$> showO
+
+
+-- | Horizontally-filled widget layout
+hwidget :: Widget w => w -> Layout
+hwidget = hfill . widget
+
+-- | Binary layout combinator
+above, leftOf :: Layout -> Layout -> Layout
+la `above` lb = fill (column 0 [la,lb])
+la `leftOf` lb = fill (row 0 [la,lb])
+
+-- | Get attribute. Just a flipped 'get'. Handy for partial application.
+getAttr :: Attr w a -> w -> IO a
+getAttr = flip get
+
+-- | Set a single attribute. Handy for partial application.
+setAttr :: Attr w a -> w -> Sink a
+setAttr attr ctl x = set ctl [ attr := x ]
+
+
+{--------------------------------------------------------------------
+ Running
+--------------------------------------------------------------------}
+
+-- | Fork a 'Wio': handle frame & widget creation, and apply layout.
+forkWio :: (o -> IO ThreadId) -> String -> Wio o -> IO ()
+forkWio forker name w = start $
+ do f <- frame [ visible := False, text := name ]
+ pan <- panel f []
+ (l,o) <- unWio w pan
+ set pan [ layout := l ]
+ forker o
+ -- Yield regularly, to allow other threads to continue. Unnecessary
+ -- when apps are compiled with -threaded.
+ -- timer pan [interval := 10, on command := yield]
+ set f [ layout := fill (widget pan)
+ , visible := True
+ ]
+
+-- | Fork a 'WioE'
+forkWioE :: String -> WioE Action -> IO ()
+forkWioE = forkWio forkE
+
+-- | Fork a 'WioR'
+forkWioR :: String -> WioR Action -> IO ()
+forkWioR = forkWio forkR
+
+
+{--------------------------------------------------------------------
+ Examples
+--------------------------------------------------------------------}
+
+alarm :: Double -> Int -> IO (Event Int)
+alarm secs reps =
+ do (e,snk) <- mkEvent
+ forkIO $ forM_ [1 .. reps] $ \ i ->
+ do threadDelay micros
+ snk i
+ return e
+ where
+ micros = round (1.0e6 * secs)
+
+
+t0 = alarm 0.5 10 >>= \ e -> runE $ print <$> {-traceE (const "boo!")-} e
+
+mkAB :: WioE String
+mkAB = buttonE' "a" "a" `mappend` buttonE' "b" "b"
+
+
+t1 = forkWioE "t1" $ liftA2 (<$>) stringO mkAB
+
+acc :: WioE String
+acc = g <$> mkAB
+ where
+ g :: Event String -> Event String
+ g e = "" `accumE` (flip (++) <$> e)
+
+t2 = forkWioE "t2" $ liftA2 (<$>) stringO acc
+
+total :: Show a => WioR (Sink a)
+total = title "total" showR
+
+sl :: Int -> WioR Int
+sl = sliderR (0,100)
+
+apples, bananas, fruit :: WioR Int
+apples = title "apples" $ sl 3
+bananas = title "bananas" $ sl 7
+fruit = title "fruit" $ (liftA2.liftA2) (+) apples bananas
+
+t3 = forkWioR "t3" $ liftA2 (<**>) fruit total
+
+t4 = forkWioR "t4" $ liftA2 (<*>) showR (sl 0)
+
+t5 = forkWioR "t5" $ liftA2 (<$>) showO (sl 0)
+
+-- This example shows what happens with expensive computations. There's a
+-- lag between slider movement and shown result. Can even get more than
+-- one computation behind.
+t6 = forkWioR "t6" $ liftA2 (<$>) showO (fmap (ack 2) <$> sliderR (0,1000) 0)
+
+ack 0 n = n+1
+ack m 0 = ack (m-1) 1
+ack m n = ack (m-1) (ack m (n-1))
+
+-- Test switchers. Ivan Tomac's example.
+sw1 = do (e, snk) <- mkEvent
+ forkR $ print <$> pure "init" `switcher` ((\_ -> pure "next") <$> e)
+ snk ()
+ snk ()
+
+-- TODO: replace sw1 with a declarative GUI example, say switching between
+-- two different previous GUI examples.
+
+main = t6
+
+
+updPair :: Either c d -> (c,d) -> (c,d)
+updPair = (first.const) `either` (second.const)
+
+-- updPair (Left c') (_,d) = (c',d)
+-- updPair (Right d') (c,_) = (c,d')
+
+-- mixEither :: (Event c, Event d) -> Event (Either c d)
+-- mixEither :: (Functor f, Monoid (f (Either a b))) =>
+-- (f a, f b) -> f (Either a b)
+mixEither :: MonadPlus m => (m a, m b) -> m (Either a b)
+mixEither (ec,ed) = liftM Left ec `mplus` liftM Right ed
+
+-- unmixEither :: Event (Either c d) -> (Event c, Event d)
+unmixEither :: MonadPlus m => m (Either c d) -> (m c, m d)
+unmixEither ecd = (filt left, filt right)
+ where
+ filt f = joinMaybes (liftM f ecd)
+
+left :: Either c d -> Maybe c
+left (Left c) = Just c
+left _ = Nothing
+
+right :: Either c d -> Maybe d
+right (Right d) = Just d
+right _ = Nothing
+
+
+-- pairEditE :: (Event c, Event d) -> Event ((c,d) -> (c,d))
+
+-- pairEditE :: (Functor f, Monoid (f ((d, a) -> (d, a)))) =>
+-- (f d, f a) -> f ((d, a) -> (d, a))
+-- pairEditE (ce,de) =
+-- ((first.const) <$> ce) `mappend` ((second.const) <$> de)
+
+-- pairEditE :: (Functor m, MonadPlus m) => (m d, m a) -> m ((d, a) -> (d, a))
+-- pairEditE (ce,de) =
+-- ((first.const) <$> ce) `mplus` ((second.const) <$> de)
+
+pairEditE :: MonadPlus m => (m c,m d) -> m ((c,d) -> (c,d))
+pairEditE = liftM updPair . mixEither
+
+-- pairEditE cde = liftM updPair (mixEither cde)
+
+-- or, skipping sums
+
+-- pairEditE (ce,de) =
+-- liftM (first.const) ce `mplus` liftM (second.const) de
+
+pairE :: (c,d) -> (Event c, Event d) -> Event (c,d)
+pairE cd cde = cd `accumE` pairEditE cde
+
+pairR :: Reactive c -> Reactive d -> Reactive (c,d)
+
+-- (c `Stepper` ce) `pairR` (d `Stepper` de) =
+-- (c,d) `stepper` pairE (c,d) (ce,de)
+
+-- More directly:
+
+(c `Stepper` ce) `pairR` (d `Stepper` de) =
+ (c,d) `accumR` pairEditE (ce,de)
+
+-- pairR' :: Reactive c -> Reactive d -> Reactive (c,d)
+-- (c `Stepper` ce) `pairR'` (d `Stepper` de) =
+-- (c,d) `accumR` pairEditE (ce,de)
+
49 src/FRP/Reactive.hs
@@ -0,0 +1,49 @@
+{-# OPTIONS -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module : FRP.Reactive
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- A library for programming with functional reactive behaviors.
+----------------------------------------------------------------------
+
+module FRP.Reactive
+ (
+ -- * Events
+ TimeT, ITime
+ , EventG, Event
+ , accumE
+ , withTimeE, withTimeE_
+ , zipE, scanlE, monoidE
+ , mealy, mealy_, countE, countE_, diffE
+ , withPrevE, withPrevEWith
+ , eitherE
+ , justE, filterE
+ -- ** More esoteric
+ , listE, atTimes, atTime, once
+ , firstRestE, firstE, restE, snapRemainderE
+ , withRestE, untilE
+ , splitE, switchE
+ -- ** Useful with events.
+ , joinMaybes, filterMP
+ -- * Behaviors
+ , BehaviorG, Behavior, Behaviour
+ , time
+ , stepper, switcher --, select
+ , snapshotWith, snapshot, snapshot_, whenE
+ , accumB
+ , scanlB, monoidB, maybeB, flipFlop, countB
+ , sumB, integral
+ ) where
+
+-- Reactive.Reactive exports reactive values as well. Filter them out.
+
+import FRP.Reactive.Reactive hiding
+ (stepper,switcher,snapshotWith,snapshot,snapshot_,whenE,flipFlop,integral)
+import FRP.Reactive.Behavior
+import FRP.Reactive.VectorSpace ()
+import FRP.Reactive.Num ()
342 src/FRP/Reactive/Behavior.hs
@@ -0,0 +1,342 @@
+{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies, TypeOperators
+ , StandaloneDeriving, GeneralizedNewtypeDeriving
+ , TypeSynonymInstances, UndecidableInstances
+ #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+----------------------------------------------------------------------
+-- |
+-- Module : FRP.Reactive.Behavior
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Reactive behaviors (continuous time)
+----------------------------------------------------------------------
+
+module FRP.Reactive.Behavior
+ (
+ BehaviorG, Behavior, Behaviour
+ , time
+ , stepper, switcher --, select
+ , snapshotWith, snapshot, snapshot_, whenE
+ , accumB, scanlB, monoidB, maybeB, flipFlop, countB
+ , sumB, integral
+ ) where
+
+import Data.Monoid (Monoid(..))
+import Control.Applicative (Applicative,(<$>),pure)
+-- import Control.Monad (join)
+
+import Control.Comonad
+
+import Control.Compose ((:.)(..),unO)
+
+import Data.VectorSpace
+import Data.AffineSpace
+
+import qualified FRP.Reactive.Reactive as R
+import FRP.Reactive.Reactive
+ ( ImpBounds, TimeT, EventG, ReactiveG
+ , withTimeE,onceRestE,diffE,joinMaybes,result)
+import FRP.Reactive.Fun
+-- import FRP.Reactive.Improving
+import FRP.Reactive.Internal.Behavior
+
+-- type EventI t = EventG (Improving t)
+-- type ReactiveI t = ReactiveG (Improving t)
+-- type BehaviorI t = BehaviorG (Improving t) t
+
+type EventI t = EventG (ImpBounds t)
+type ReactiveI t = ReactiveG (ImpBounds t)
+type BehaviorI t = BehaviorG (ImpBounds t) t
+
+-- | Time-specialized behaviors.
+-- Note: The signatures of all of the behavior functions can be generalized. Is
+-- the interface generality worth the complexity?
+type Behavior = BehaviorI TimeT
+
+-- Synonym for 'Behavior'
+type Behaviour = Behavior
+
+
+-- | The identity generalized behavior. Has value @t@ at time @t@.
+--
+-- > time :: Behavior TimeT
+time :: (Ord t) => BehaviorI t t
+time = beh (pure (fun id))
+
+-- Turn a reactive value into a discretly changing behavior.
+rToB :: ReactiveI t a -> BehaviorI t a
+rToB = beh . fmap pure
+
+-- Then use 'rToB' to promote reactive value functions to behavior
+-- functions.
+
+-- | Discretely changing behavior, based on an initial value and a
+-- new-value event.
+--
+-- >stepper :: a -> Event a -> Behavior a
+stepper :: a -> EventI t a -> BehaviorI t a
+stepper = (result.result) rToB R.stepper
+
+-- Suggested by Robin Green:
+
+-- stepper = select pure
+
+-- -- | Use a key event to key into a behaviour-valued function
+-- select :: (a -> Behavior b) -> a -> Event a -> Behavior b
+-- select f a e = f a `switcher` (f <$> e)
+
+-- Looking for a more descriptive name.
+
+-- | Switch between behaviors.
+--
+-- > switcher :: Behavior a -> Event (Behavior a) -> Behavior a
+switcher :: (Ord tr, Bounded tr) =>
+ BehaviorG tr tf a
+ -> EventG tr (BehaviorG tr tf a)
+ -> BehaviorG tr tf a
+b `switcher` eb = beh (unb b `R.switcher` (unb <$> eb))
+
+-- | Snapshots a behavior whenever an event occurs and combines the values
+-- using the combining function passed. Take careful note of the order of
+-- arguments and results.
+--
+-- > snapshotWith :: (a -> b -> c) -> Behavior b -> Event a -> Event c
+snapshotWith :: (Ord t) =>
+ (a -> b -> c)
+ -> BehaviorI t b -> EventI t a -> EventI t c
+snapshotWith h b e = f <$> (unb b `R.snapshot` withTimeE e)
+ where
+ f ((a,t),tfun) = h a (tfun `apply` t)
+
+
+-- 'snapshotWith' is where tr meets tf. withTimeE is specialized from
+-- withTimeGE, converting the ITime into a TimeT. This specialization
+-- interferes with the generality of several functions in this module,
+-- which are therefore now still using 'Behavior' instead of 'BehaviorG'.
+-- Figure out how to get generality.
+
+
+-- | Snapshot a behavior whenever an event occurs. See also
+-- 'snapshotWith'. Take careful note of the order of arguments and
+-- results.
+--
+-- > snapshot :: Behavior b -> Event a -> Event (a,b)
+snapshot :: (Ord t) => BehaviorI t b -> EventI t a -> EventI t (a,b)
+snapshot = snapshotWith (,)
+
+-- TODO: tweak withTimeE so that 'snapshotWith' and 'snapshot' can have
+-- more general types. The problem is that withTimeE gives a friendlier
+-- kind of time, namely known and finite. Necessary?
+
+-- Alternative implementations:
+-- snapshotWith c e b = uncurry c <$> snapshot e b
+-- snapshotWith c = (result.result.fmap) (uncurry c) snapshot
+
+-- | Like 'snapshot' but discarding event data (often @a@ is '()').
+--
+-- > snapshot_ :: Behavior b -> Event a -> Event b
+snapshot_ :: (Ord t) => BehaviorI t b -> EventI t a -> EventI t b
+snapshot_ = snapshotWith (flip const)
+
+-- Alternative implementations
+-- e `snapshot_` src = snd <$> (e `snapshot` src)
+-- snapshot_ = (result.result.fmap) snd snapshot
+
+-- | Filter an event according to whether a reactive boolean is true.
+--
+-- > whenE :: Behavior Bool -> Event a -> Event a
+whenE :: (Ord t) => BehaviorI t Bool -> EventI t a -> EventI t a
+b `whenE` e = joinMaybes (h <$> (b `snapshot` e))
+ where
+ h (a,True) = Just a
+ h (_,False) = Nothing
+
+-- TODO: Same comment about generality as with snapshot
+
+-- | Behavior from an initial value and an updater event. See also
+-- 'accumE'.
+--
+-- > accumB :: a -> Event (a -> a) -> Behavior a
+accumB :: a -> EventI t (a -> a) -> BehaviorI t a
+accumB = (result.result) rToB R.accumR
+
+-- -- | Like 'scanl' for behaviors. See also 'scanlE'.
+-- scanlB :: (a -> b -> a) -> a -> Event b -> Behavior a
+-- scanlB = (result.result.result) rToB R.scanlR
+
+-- -- | Accumulate values from a monoid-valued event. Specialization of
+-- -- 'scanlB', using 'mappend' and 'mempty'. See also 'monoidE'.
+-- monoidB :: Monoid a => Event a -> Behavior a
+-- monoidB = result rToB R.monoidR
+
+
+---- The next versions are more continuous:
+
+-- type RF a = Reactive (Fun TimeT a)
+
+-- scanlB :: forall a c. (Behavior a -> c -> Behavior a) -> Behavior a
+-- -> Event c -> Behavior a
+-- scanlB f b0 e = beh (scanlRF f' (unb b0) e)
+-- where
+-- f' :: RF a -> c -> RF a
+-- f' r c = unb (f (beh r) c)
+
+-- scanlRF :: (RF a -> c -> RF a) -> RF a -> Event c -> RF a
+-- scanlRF h rf0 e = join (R.scanlR h rf0 e)
+
+-- monoidB :: Monoid a => Event (Behavior a) -> Behavior a
+-- monoidB = scanlB mappend mempty
+
+-- -- I doubt the above definitions work well. They accumulate reactives without
+-- -- aging them. See 'accumE'.
+
+
+-- | Like 'scanl' for behaviors. See also 'scanlE'.
+--
+-- > scanlB :: forall a. (Behavior a -> Behavior a -> Behavior a) -> Behavior a
+-- > -> Event (Behavior a) -> Behavior a
+
+-- TODO: generalize scanlB's type
+
+scanlB :: forall a b tr tf. (Ord tr, Bounded tr) =>
+ (b -> BehaviorG tr tf a -> BehaviorG tr tf a)
+ -> BehaviorG tr tf a
+ -> EventG tr b -> BehaviorG tr tf a
+scanlB plus zero = h
+ where
+ h :: EventG tr b -> BehaviorG tr tf a
+ h e = zero `switcher` (g <$> onceRestE e)
+ g :: (b, EventG tr b) -> BehaviorG tr tf a
+ g (b, e') = b `plus` h e'
+
+
+-- | Accumulate values from a monoid-valued event. Specialization of
+-- 'scanlB', using 'mappend' and 'mempty'. See also 'monoidE'.
+--
+-- > monoidB :: Monoid a => Event (Behavior a) -> Behavior a
+monoidB :: (Ord tr, Bounded tr, Monoid a) => EventG tr (BehaviorG tr tf a)
+ -> BehaviorG tr tf a
+monoidB = scanlB mappend mempty
+
+-- | Like 'sum' for behaviors.
+--
+-- > sumB :: AdditiveGroup a => Event a -> Behavior a
+sumB :: (Ord t, AdditiveGroup a) => EventI t a -> BehaviorI t a
+sumB = result rToB R.sumR
+
+-- | Start out blank ('Nothing'), latching onto each new @a@, and blanking
+-- on each @b@. If you just want to latch and not blank, then use
+-- 'mempty' for the second event.
+--
+-- > maybeB :: Event a -> Event b -> Behavior (Maybe a)
+maybeB :: (Ord t) =>
+ EventI t a -> EventI t b -> BehaviorI t (Maybe a)
+maybeB = (result.result) rToB R.maybeR
+
+-- | Flip-flopping behavior. Turns true whenever first event occurs and
+-- false whenever the second event occurs.
+--
+-- > flipFlop :: Event a -> Event b -> Behavior Bool
+flipFlop :: (Ord t) => EventI t a -> EventI t b -> BehaviorI t Bool
+flipFlop = (result.result) rToB R.flipFlop
+
+-- | Count occurrences of an event. See also 'countE'.
+--
+-- > countB :: Num n => Event a -> Behavior n
+countB :: (Ord t, Num n) => EventI t a -> BehaviorI t n
+countB = result rToB R.countR
+
+-- | Euler integral.
+--
+-- > integral :: (VectorSpace v, Scalar v ~ TimeT) =>
+-- > Event () -> Behavior v -> Behavior v
+integral :: (VectorSpace v, AffineSpace t, Scalar v ~ Diff t, Ord t) =>
+ EventI t a -> BehaviorI t v -> BehaviorI t v
+integral t b = sumB (snapshotWith (*^) b (diffE (time `snapshot_` t)))
+
+-- TODO: This integral definition is piecewise-constant. Change to piecewise-linear.
+
+
+-- TODO: find out whether this integral works recursively. If not, then
+-- fix the implementation, rather than changing the semantics. (No
+-- "delayed integral".)
+--
+-- Early experiments suggest that recursive integration gets stuck.
+-- Chuan-kai Lin has come up with a new lazier R.snapshotWith, but it
+-- leaks when the reactive value changes in between event occurrences.
+
+
+---- Comonadic stuff
+
+-- Orphan. Move elsewhere
+
+instance (Functor g, Functor f, Copointed g, Copointed f)
+ => Copointed (g :. f) where
+ extract = extract . extract . unO
+
+-- instance (Comonad g, Comonad f) => Comonad (g :. f) where
+-- duplicate = inO (fmap duplicate . duplicate)
+
+
+-- WORKING HERE
+
+-- The plan for duplicate:
+--
+-- (g :. f) a -> g (f a) -> g (f (f a)) -> g (g (f (f a)))
+-- -> g (f (g (f a))) -> (g :. f) (g (f a))
+-- -> (g :. f) ((g :. f) a) ->
+
+-- But we'll have to do that middle twiddle, which I couldn't do for
+-- behaviors to get a Monad either. Is there another way?
+
+
+-- instance Comonad (g :. f) where
+-- duplicate
+
+deriving instance (Monoid tr, Monoid tf) => Copointed (BehaviorG tr tf)
+
+-- ITime and TimeT are not currently monoids. They can be when I wrap
+-- them in the Sum monoid constructor, in which mempty = 0 and mappend =
+-- (+). This monoid change moves us from absolute to relative time. What
+-- do I do for never-occuring futures and terminating events?
+
+--
+
+-- instance (Ord t, Monoid t, Monoid (Improving t)) => Comonad (BehaviorI t) where
+-- duplicate = duplicateB
+
+-- duplicateB :: forall t a.
+-- (Ord t, Monoid t, Monoid (Improving t)) =>
+-- BehaviorI t -> BehaviorI t (BehaviorI t a) where
+-- duplicate b@(_ `Stepper`) = bb0 `switcher`
+-- where
+-- f0 `R.Stepper` e = unb b
+-- bb0 = beh (pure (fun (\ t -> undefined)))
+
+-- f0 :: T a
+
+-- e :: E (T a)
+
+-- duplicate f0 :: T (T a)
+
+
+-- b :: B a
+
+-- unb b :: R (T a)
+
+
+
+-- dup b :: B (B a)
+
+
+-- TODO: generalize to BehaviorG
+-- TODO: something about Monoid (Improving t)
+
+-- Standard instances for applicative functors
+
+-- #define APPLICATIVE Behavior
+-- #include "Num-inc.hs"
151 src/FRP/Reactive/Fun.hs
@@ -0,0 +1,151 @@
+{-# LANGUAGE CPP, MultiParamTypeClasses, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+----------------------------------------------------------------------
+-- |
+-- Module : FRP.Reactive.Fun
+-- Copyright : (c) Conal Elliott 2007
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Functions, with constant functions optimized, with instances for many
+-- standard classes.
+----------------------------------------------------------------------
+
+module FRP.Reactive.Fun (Fun, fun, apply, batch) where
+
+import Prelude hiding
+ ( zip, zipWith
+#if __GLASGOW_HASKELL__ >= 609
+ , (.), id
+#endif
+ )
+#if __GLASGOW_HASKELL__ >= 609
+import Control.Category
+#endif
+
+
+import Data.Monoid (Monoid(..))
+import Control.Applicative (Applicative(..),liftA)
+import Control.Arrow
+#if __GLASGOW_HASKELL__ < 610
+ hiding (pure)
+#endif
+import Text.Show.Functions ()
+
+import Control.Comonad
+
+import Data.Zip (Zip(..))
+
+import Test.QuickCheck
+import Test.QuickCheck.Checkers
+import Test.QuickCheck.Classes
+
+import FRP.Reactive.Internal.Fun
+
+
+-- TODO: write RULE for fun . const = K
+fun :: (t -> a) -> Fun t a
+fun = Fun
+
+instance (CoArbitrary a,Arbitrary b) => Arbitrary (Fun a b) where
+ arbitrary = oneof [liftA K arbitrary, liftA Fun arbitrary]
+
+instance (Arbitrary a, CoArbitrary b) => CoArbitrary (Fun a b) where
+ coarbitrary (K a) = variant (0 :: Int) . coarbitrary a
+ coarbitrary (Fun x) = variant (1 :: Int) . coarbitrary x
+
+instance Show b => Show (Fun a b) where
+ show (K x) = "K " ++ show x
+ show (Fun f) = "Fun " ++ show f
+
+instance (Show a, Arbitrary a, EqProp a, EqProp b) => EqProp (Fun a b) where
+ (=-=) = eqModels
+
+instance Model (Fun a b) (a -> b) where
+ model = apply
+
+instance Model1 (Fun a) ((->) a) where
+ model1 = apply
+
+-- | 'Fun' as a function
+apply :: Fun t a -> (t -> a)
+apply (K a) = const a
+apply (Fun f) = f
+
+instance Monoid a => Monoid (Fun t a) where
+ mempty = K mempty
+ K a `mappend` K a' = K (a `mappend` a')
+ funa `mappend` funb = Fun (apply funa `mappend` apply funb)
+
+instance Functor (Fun t) where
+ fmap f (K a) = K (f a)
+ fmap f (Fun g) = Fun (f.g) -- == Fun (fmap f g)
+
+instance Zip (Fun t) where
+ K x `zip` K y = K (x,y)
+ cf `zip` cx = Fun (apply cf `zip` apply cx)
+
+instance Applicative (Fun t) where
+ pure = K
+ K f <*> K x = K (f x)
+ cf <*> cx = Fun (apply cf <*> apply cx)
+
+instance Monad (Fun t) where
+ return = pure
+ K a >>= h = h a
+ Fun f >>= h = Fun (f >>= apply . h)
+
+#if __GLASGOW_HASKELL__ >= 609
+instance Category Fun where
+ id = Fun id
+ K b . _ = K b
+ Fun g . K a = K (g a)
+ Fun f . Fun g = Fun (f . g)
+#endif
+
+instance Arrow Fun where
+ arr = Fun
+#if __GLASGOW_HASKELL__ < 609
+ _ >>> K b = K b
+ K a >>> Fun g = K (g a)
+ Fun g >>> Fun f = Fun (g >>> f)
+#endif
+ first = Fun . first . apply
+ second = Fun . second . apply
+ K a' *** K b' = K (a',b')
+ f *** g = first f >>> second g
+
+instance Pointed (Fun t) where
+ point = K
+
+instance Monoid t => Copointed (Fun t) where
+ extract = extract . apply
+
+instance Monoid t => Comonad (Fun t) where
+ duplicate (K a) = K (K a)
+ duplicate (Fun f) = Fun (Fun . duplicate f)
+
+
+
+----------------------------------
+
+batch :: TestBatch
+batch = ( "FRP.Reactive.Fun"
+ , concatMap unbatch
+ [ monoid (undefined :: Fun NumT [T])
+ , semanticMonoid (undefined :: Fun NumT [T])
+ , functor (undefined :: Fun NumT (NumT,T,NumT))
+ , semanticFunctor (undefined :: Fun NumT ())
+ , applicative (undefined :: Fun NumT (NumT,T,NumT))
+ , semanticApplicative (undefined :: Fun NumT ())
+ , monad (undefined :: Fun NumT (NumT,T,NumT))
+ , semanticMonad (undefined :: Fun NumT ())
+ , arrow (undefined :: Fun NumT (NumT,T,NumT))
+ , ("specifics",
+ [("Constants are"
+ ,property (\x -> (K (x :: NumT)) =-=
+ ((fun . const $ x) :: Fun T NumT)))])
+ ]
+ )
224 src/FRP/Reactive/Future.hs
@@ -0,0 +1,224 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+
+----------------------------------------------------------------------
+-- |
+-- Module : FRP.Reactive.Future
+-- Copyright : (c) Conal Elliott 2007-2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- A simple formulation of functional /futures/, roughly as
+-- described at <http://en.wikipedia.org/wiki/Futures_and_promises>.
+--
+-- A /future/ is a value with an associated time of /arrival/. Typically,
+-- neither the time nor the value can be known until the arrival time.
+--
+-- Primitive futures can be things like /the value of the next key you
+-- press/, or /the value of LambdaPix stock at noon next Monday/.
+--
+-- Composition is via standard type classes: 'Functor', 'Applicative',
+-- 'Monad', and 'Monoid'. Some comments on the 'Future' instances of
+-- these classes:
+--
+-- * Monoid: 'mempty' is a future that never arrives (infinite time and
+-- undefined value), and @a `mappend` b@ is the earlier of @a@ and @b@,
+-- preferring @a@ when simultaneous.
+--
+-- * 'Functor': apply a function to a future argument. The (future)
+-- result arrives simultaneously with the argument.
+--
+-- * 'Applicative': 'pure' gives value arriving negative infinity.
+-- '(\<*\>)' applies a future function to a future argument, yielding a
+-- future result that arrives once /both/ function and argument have
+-- arrived (coinciding with the later of the two times).
+--
+-- * 'Monad': 'return' is the same as 'pure' (as usual). @(>>=)@ cascades
+-- futures. 'join' resolves a future future value into a future value.
+--
+-- Futures are parametric over /time/ as well as /value/ types. The time
+-- parameter can be any ordered type and is particularly useful with time
+-- types that have rich partial information structure, such as /improving
+-- values/.
+----------------------------------------------------------------------
+
+module FRP.Reactive.Future
+ (
+ -- * Time & futures
+ Time, ftime
+ , FutureG(..), isNeverF, inFuture, inFuture2, futTime, futVal, future
+ , withTimeF
+ -- * Tests
+ , batch
+ ) where
+
+import Data.Monoid (Monoid(..))
+
+import Data.Max
+-- import Data.AddBounds
+import FRP.Reactive.Internal.Future
+
+-- Testing
+import Test.QuickCheck
+import Test.QuickCheck.Checkers
+import Test.QuickCheck.Classes
+
+{----------------------------------------------------------
+ Time and futures
+----------------------------------------------------------}
+
+-- | Make a finite time
+ftime :: t -> Time t
+ftime = Max
+
+-- FutureG representation in Internal.Future
+
+instance (Bounded t, Eq t, EqProp t, EqProp a) => EqProp (FutureG t a) where
+ u =-= v | isNeverF u && isNeverF v = property True
+ Future a =-= Future b = a =-= b
+
+-- I'd rather say:
+--
+-- instance (Bounded t, EqProp t, EqProp a) => EqProp (FutureG t a) where
+-- Future a =-= Future b =
+-- (fst a =-= maxBound && fst b =-= maxBound) .|. a =-= b
+--
+-- However, I don't know how to define disjunction on QuickCheck properties.
+
+-- | A future's time
+futTime :: FutureG t a -> Time t
+futTime = fst . unFuture
+
+-- | A future's value
+futVal :: FutureG t a -> a
+futVal = snd . unFuture
+
+-- | A future value with given time & value
+future :: t -> a -> FutureG t a
+future t a = Future (ftime t, a)
+
+-- | Access time of future
+withTimeF :: FutureG t a -> FutureG t (Time t, a)
+withTimeF = inFuture $ \ (t,a) -> (t,(t,a))
+
+-- withTimeF = inFuture duplicate (with Comonad)
+
+-- TODO: Eliminate this Monoid instance. Derive Monoid along with all the
+-- other classes. And don't use mempty and mappend for the operations
+-- below. For one thing, the current instance makes Future a monoid but
+-- unFuture not be a monoid morphism.
+
+instance (Ord t, Bounded t) => Monoid (FutureG t a) where
+ mempty = Future (maxBound, error "Future mempty: it'll never happen, buddy")
+ -- Pick the earlier future.
+ Future (s,a) `mappend` Future (t,b) =
+ Future (s `min` t, if s <= t then a else b)
+
+-- Consider the following simpler definition:
+--
+-- fa@(Future (s,_)) `mappend` fb@(Future (t,_)) =
+-- if s <= t then fa else fb
+--
+-- Nothing can be known about the resulting future until @s <= t@ is
+-- determined. In particular, we cannot know lower bounds for the time.
+-- In contrast, the actual 'mappend' definition can potentially yield
+-- useful partial information, such as lower bounds, about the future
+-- time, if the type parameter @t@ has rich partial information structure
+-- (non-flat).
+
+-- For some choices of @t@, there may be an efficient combination of 'min'
+-- and '(<=)', so the 'mappend' definition is sub-optimal. In particular,
+-- 'Improving' has 'minI'.
+
+
+-- -- A future known never to happen (by construction), i.e., infinite time.
+-- isNever :: FutureG t a -> Bool
+-- isNever = isMaxBound . futTime
+-- where
+-- isMaxBound (Max MaxBound) = True
+-- isMaxBound _ = False
+--
+-- This function is an abstraction leak. Don't export it to library
+-- users.
+
+
+
+{----------------------------------------------------------
+ Tests
+----------------------------------------------------------}
+
+-- Represents times at a given instant.
+newtype TimeInfo t = TimeInfo (Maybe t)
+ deriving EqProp
+
+instance Bounded t => Bounded (TimeInfo t) where
+ minBound = TimeInfo (Just minBound)
+ maxBound = TimeInfo Nothing
+
+
+-- A time at a given instant can be some unknown time in the future
+unknownTimeInFuture :: TimeInfo a
+unknownTimeInFuture = TimeInfo Nothing
+
+-- or, a known time in the past. We're ignoring known future times for now.
+knownTimeInPast :: a -> TimeInfo a
+knownTimeInPast = TimeInfo . Just
+
+instance Eq a => Eq (TimeInfo a) where
+ TimeInfo Nothing == TimeInfo Nothing = error "Cannot tell if two unknown times in the future are equal"
+ TimeInfo (Just _) == TimeInfo Nothing = False
+ TimeInfo Nothing == TimeInfo (Just _) = False
+ TimeInfo (Just a) == TimeInfo (Just b) = a == b
+
+instance Ord a => Ord (TimeInfo a) where
+ -- The minimum of two unknown times in the future is an unkown time in the
+ -- future.
+ TimeInfo Nothing `min` TimeInfo Nothing = unknownTimeInFuture
+ TimeInfo Nothing `min` b = b
+ a `min` TimeInfo Nothing = a
+ TimeInfo (Just a) `min` TimeInfo (Just b) = (TimeInfo . Just) (a `min` b)
+
+ TimeInfo Nothing <= TimeInfo Nothing = error "Cannot tell if one unknown time in the future is less than another."
+ TimeInfo Nothing <= TimeInfo (Just _) = False
+ TimeInfo (Just _) <= TimeInfo Nothing = True
+ TimeInfo (Just a) <= TimeInfo (Just b) = a <= b
+
+batch :: TestBatch
+batch = ( "FRP.Reactive.Future"
+ , concatMap unbatch
+ [ monoid (undefined :: FutureG NumT T)
+ , functorMonoid (undefined :: FutureG NumT
+ (T,NumT))
+ -- Checking the semantics here isn't necessary because
+ -- the implementation is identical to them.
+ --
+ -- Also, Functor, Applicative, and Monad don't require checking
+ -- since they are automatically derived.
+ --
+ -- , semanticMonoid' (undefined :: FutureG NumT T)
+ -- , functor (undefined :: FutureG NumT (T,NumT,T))
+ -- , semanticFunctor (undefined :: FutureG NumT ())
+ -- , applicative (undefined :: FutureG NumT (NumT,T,NumT))
+ -- , semanticApplicative (undefined :: FutureG NumT ())
+ -- , monad (undefined :: FutureG NumT (NumT,T,NumT))
+ -- , semanticMonad (undefined :: FutureG NumT ())
+
+ , ("specifics",
+ [ ("laziness", property laziness )
+ ])
+ ]
+ )
+ where
+ laziness :: BoundedT -> T -> Property
+ laziness t a = (uf `mappend` uf) `mappend` kf =-= kf
+ where
+ uf = unknownFuture
+ kf = knownFuture
+ knownFuture = future (knownTimeInPast t) a
+ unknownFuture = future unknownTimeInFuture (error "cannot retrieve value at unknown time at the future")
+
+
+-- Move to checkers
+type BoundedT = Int
215 src/FRP/Reactive/Improving.hs
@@ -0,0 +1,215 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module : FRP.Reactive.Improving
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Improving values -- efficient version
+----------------------------------------------------------------------
+
+module FRP.Reactive.Improving
+ (
+ Improving(..), exactly, before, after, minI, maxI
+ , batch
+ ) where
+
+
+import Data.Function (on)
+import Text.Show.Functions ()
+import Control.Applicative (pure,(<$>),liftA2)
+
+import Data.Unamb (unamb,parCommute,pmin,pmax)
+
+import Test.QuickCheck
+-- import Test.QuickCheck.Instances
+import Test.QuickCheck.Checkers
+import Test.QuickCheck.Classes
+import Test.QuickCheck.Instances.Num
+
+
+{----------------------------------------------------------
+ Improving values
+----------------------------------------------------------}
+
+-- | An improving value.
+data Improving a = Imp { exact :: a, compareI :: a -> Ordering }
+ -- deriving Show
+
+instance Show a => Show (Improving a) where
+ show = ("Imp "++) . show . exact
+
+-- | A known improving value (which doesn't really improve)
+exactly :: Ord a => a -> Improving a
+exactly a = Imp a (compare a)
+
+-- | A value known to be @< x@.
+before :: Ord a => a -> Improving a
+before x = Imp undefined comp
+ where
+ comp y | x <= y = LT
+ | otherwise = error "before: comparing before"
+
+-- | A value known to be @> x@.
+after :: Ord a => a -> Improving a
+after x = Imp undefined comp
+ where
+ comp y | x >= y = GT
+ | otherwise = error "after: comparing after"
+
+
+instance Eq a => Eq (Improving a) where
+ -- (==) = (==) `on` exact
+ -- This version can prove inequality without having to know both values
+ -- exactly.
+ (==) = parCommute (\ u v -> u `compareI` exact v == EQ)
+
+-- TODO: experiment with these two versions of (==). The 'parCommute' one
+-- can return 'False' sooner than the simpler def, but I doubt it'll
+-- return 'True' any sooner.
+
+instance Ord a => Ord (Improving a) where
+ min = (result.result) fst minI
+ (<=) = (result.result) snd minI
+ max = (result.result) fst maxI
+
+-- | Efficient combination of 'min' and '(<=)'
+minI :: Ord a => Improving a -> Improving a -> (Improving a,Bool)
+~(Imp u uComp) `minI` ~(Imp v vComp) = (Imp uMinV wComp, uLeqV)
+ where
+ uMinV = if uLeqV then u else v
+ -- u <= v: Try @v `compare` u /= LT@ and @u `compare` v /= GT@.
+ uLeqV = (vComp u /= LT) `unamb` (uComp v /= GT)
+ wComp = liftA2 pmin uComp vComp
+
+-- -- (u `min` v) `compare` t: Try comparing according to whether u <= v,
+-- -- or go with either answer if they agree, e.g., if both say GT.
+-- -- And say GT if either comp says LT.
+-- wComp t = (uCt `asAgree` LT `unamb` vCt `asAgree` LT) -- LT cases
+-- `unamb` (uCt `min` vCt) -- EQ and GT case
+-- where
+-- uCt = uComp t
+-- vCt = vComp t
+
+-- | Efficient combination of 'max' and '(>=)'
+maxI :: Ord a => Improving a -> Improving a -> (Improving a,Bool)
+~(Imp u uComp) `maxI` ~(Imp v vComp) = (Imp uMaxV wComp, uGeqV)
+ where
+ uMaxV = if uGeqV then u else v
+ -- u >= v: Try @v `compare` u /= GT@ and @u `compare` v /= LT@.
+ uGeqV = (vComp u /= GT) `unamb` (uComp v /= LT)
+ wComp = liftA2 pmax uComp vComp
+
+-- -- (u `max` v) `compare` t: Try comparing according to whether u >= v,
+-- -- or go with either answer if they agree, e.g., if both say LT.
+-- -- And say LT if either comp says GT.
+-- wComp t = (uCt `asAgree` GT `unamb` vCt `asAgree` GT) -- GT cases
+-- `unamb` (uCt `max` vCt) -- EQ and LT case
+-- where
+-- uCt = uComp t
+-- vCt = vComp t
+
+-- TODO: reconsider these wComp tests and look for a smaller set.
+
+-- TODO: factor commonality out of 'minI' and 'maxI' or combine into
+-- a single function.
+
+-- TODO: Are the lazy patterns at all helpful?
+
+
+-- Experimental 'Bounded' instance. I'm curious about it as an
+-- alternative to using 'AddBounds'. However, it seems to lose the
+-- advantage of a knowably infinite value, which I use in a lot of
+-- optimization, including filter/join.
+
+-- instance Bounded (Improving a) where
+-- minBound = error "minBound not defined on Improving"
+-- maxBound = Imp (error "exact maxBound")
+-- (const GT)
+
+instance (Ord a, Bounded a) => Bounded (Improving a) where
+ minBound = exactly minBound
+ maxBound = exactly maxBound
+
+-- Hack: use 0 as lower bound
+-- No, this one won't work, because I'll need to extract the exact value
+-- in order to compare with maxBound
+
+-- instance (Ord a, Num a) => Bounded (Improving a) where
+-- minBound = exactly 0
+-- maxBound = -- exactly maxBound
+-- Imp (error "Improving maxBound evaluated")
+-- (const GT)
+
+
+-- TODO: consider 'undefined' instead 'error', for 'unamb'. However, we
+-- lose valuable information if the 'undefined' gets forced with no
+-- 'unamb' to handle it. Maybe make 'unamb' handle more exceptions.
+
+
+----
+
+
+-- Modify the result of a function. See
+-- <http://conal.net/blog/semantic-editor-combinators>.
+result :: (b -> b') -> ((a -> b) -> (a -> b'))
+result = (.)
+
+
+----
+
+-- For now, generate exactly-knowable values.
+-- TODO: generate trickier improving values.
+
+instance (Ord a, Arbitrary a) => Arbitrary (Improving a) where
+ arbitrary = exactly <$> arbitrary
+
+instance (CoArbitrary a) => CoArbitrary (Improving a) where
+ coarbitrary = coarbitrary . exact
+
+instance Model (Improving a) a where model = exact
+
+instance EqProp a => EqProp (Improving a) where
+ (=-=) = (=-=) `on` exact
+
+-- TODO: revisit (=-=). Maybe it doesn't have to test for full equality.
+
+genGE :: (Arbitrary a, Num a) => Improving a -> Gen (Improving a)
+genGE i = add i <$> oneof [pure 0, positive]
+
+-- I didn't use nonNegative in genGE, because I want zero pretty often,
+-- especially for the antiSymmetric law.
+
+add :: Num a => Improving a -> a -> Improving a
+add (Imp x comp) dx = Imp (x + dx) (comp . subtract dx)
+
+batch :: TestBatch
+batch = ( "Reactive.Improving"
+ , concatMap unbatch
+ [ ordI, semanticOrdI, partial ]
+ )
+ where
+ ordI = ord (genGE :: Improving NumT -> Gen (Improving NumT))
+ semanticOrdI = semanticOrd (undefined :: Improving NumT)
+
+partial :: TestBatch
+partial = ( "Partial"
+ , [ ("min after" , property (minAL :: NumT -> NumT -> Bool))
+ , ("max before", property (maxAL :: NumT -> NumT -> Bool))
+ ]
+ )
+
+minAL :: Ord a => a -> a -> Bool
+minAL x y = after x `min` after y >= exactly (x `min` y)
+
+maxAL :: Ord a => a -> a -> Bool
+maxAL x y = before x `max` before y <= exactly (x `max` y)
+
+
+-- Now I realize that the Ord laws are implied by semantic Ord property,
+-- assuming that the model satisfies the Ord laws.
+
80 src/FRP/Reactive/Internal/Behavior.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE TypeOperators, GeneralizedNewtypeDeriving
+ , FlexibleInstances, FlexibleContexts #-}
+{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
+----------------------------------------------------------------------
+-- |
+-- Module : FRP.Reactive.Internal.Behavior
+-- Copyright : (c) Conal Elliott 2008
+-- License : GNU AGPLv3 (see COPYING)
+--
+-- Maintainer : conal@conal.net
+-- Stability : experimental
+--
+-- Representation of reactive behaviors
+----------------------------------------------------------------------
+
+module FRP.Reactive.Internal.Behavior (BehaviorG(..), beh, unb) where
+
+import Prelude hiding (zip,unzip)
+
+import Data.Monoid (Monoid(..))
+import Control.Applicative (Applicative(pure),liftA2)
+
+-- TypeCompose
+import Control.Compose ((:.)(..),unO)
+import Data.Zip (Zip(..),Unzip(..))
+