ListLike (empty) → 1.0.0
raw patch · 12 files changed
+2721/−0 lines, 12 filesdep +basedep +haskell98dep +mtlbuild-type:Customsetup-changed
Dependencies added: base, haskell98, mtl
Files
- COPYING +510/−0
- COPYRIGHT +25/−0
- ListLike.cabal +43/−0
- Setup.hs +5/−0
- src/Data/ListLike.hs +256/−0
- src/Data/ListLike/Base.hs +630/−0
- src/Data/ListLike/FoldableLL.hs +100/−0
- src/Data/ListLike/IO.hs +125/−0
- src/Data/ListLike/Instances.hs +542/−0
- src/Data/ListLike/String.hs +78/−0
- src/Data/ListLike/Utils.hs +63/−0
- testsrc/runtests.hs +344/−0
+ COPYING view
@@ -0,0 +1,510 @@++ GNU LESSER GENERAL PUBLIC LICENSE+ Version 2.1, February 1999++ Copyright (C) 1991, 1999 Free Software Foundation, Inc.+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++[This is the first released version of the Lesser GPL. It also counts+ as the successor of the GNU Library Public License, version 2, hence+ the version number 2.1.]++ Preamble++ The licenses for most software are designed to take away your+freedom to share and change it. By contrast, the GNU General Public+Licenses are intended to guarantee your freedom to share and change+free software--to make sure the software is free for all its users.++ This license, the Lesser General Public License, applies to some+specially designated software packages--typically libraries--of the+Free Software Foundation and other authors who decide to use it. You+can use it too, but we suggest you first think carefully about whether+this license or the ordinary General Public License is the better+strategy to use in any particular case, based on the explanations+below.++ When we speak of free software, we are referring to freedom of use,+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 this service if you wish); that you receive source code or can get+it if you want it; that you can change the software and use pieces of+it in new free programs; and that you are informed that you can do+these things.++ To protect your rights, we need to make restrictions that forbid+distributors to deny you these rights or to ask you to surrender these+rights. These restrictions translate to certain responsibilities for+you if you distribute copies of the library or if you modify it.++ For example, if you distribute copies of the library, whether gratis+or for a fee, you must give the recipients all the rights that we gave+you. You must make sure that they, too, receive or can get the source+code. If you link other code with the library, you must provide+complete object files to the recipients, so that they can relink them+with the library after making changes to the library and recompiling+it. And you must show them these terms so they know their rights.++ We protect your rights with a two-step method: (1) we copyright the+library, and (2) we offer you this license, which gives you legal+permission to copy, distribute and/or modify the library.++ To protect each distributor, we want to make it very clear that+there is no warranty for the free library. Also, if the library is+modified by someone else and passed on, the recipients should know+that what they have is not the original version, so that the original+author's reputation will not be affected by problems that might be+introduced by others.++ Finally, software patents pose a constant threat to the existence of+any free program. We wish to make sure that a company cannot+effectively restrict the users of a free program by obtaining a+restrictive license from a patent holder. Therefore, we insist that+any patent license obtained for a version of the library must be+consistent with the full freedom of use specified in this license.++ Most GNU software, including some libraries, is covered by the+ordinary GNU General Public License. This license, the GNU Lesser+General Public License, applies to certain designated libraries, and+is quite different from the ordinary General Public License. We use+this license for certain libraries in order to permit linking those+libraries into non-free programs.++ When a program is linked with a library, whether statically or using+a shared library, the combination of the two is legally speaking a+combined work, a derivative of the original library. The ordinary+General Public License therefore permits such linking only if the+entire combination fits its criteria of freedom. The Lesser General+Public License permits more lax criteria for linking other code with+the library.++ We call this license the "Lesser" General Public License because it+does Less to protect the user's freedom than the ordinary General+Public License. It also provides other free software developers Less+of an advantage over competing non-free programs. These disadvantages+are the reason we use the ordinary General Public License for many+libraries. However, the Lesser license provides advantages in certain+special circumstances.++ For example, on rare occasions, there may be a special need to+encourage the widest possible use of a certain library, so that it+becomes a de-facto standard. To achieve this, non-free programs must+be allowed to use the library. A more frequent case is that a free+library does the same job as widely used non-free libraries. In this+case, there is little to gain by limiting the free library to free+software only, so we use the Lesser General Public License.++ In other cases, permission to use a particular library in non-free+programs enables a greater number of people to use a large body of+free software. For example, permission to use the GNU C Library in+non-free programs enables many more people to use the whole GNU+operating system, as well as its variant, the GNU/Linux operating+system.++ Although the Lesser General Public License is Less protective of the+users' freedom, it does ensure that the user of a program that is+linked with the Library has the freedom and the wherewithal to run+that program using a modified version of the Library.++ The precise terms and conditions for copying, distribution and+modification follow. Pay close attention to the difference between a+"work based on the library" and a "work that uses the library". The+former contains code derived from the library, whereas the latter must+be combined with the library in order to run.++ GNU LESSER GENERAL PUBLIC LICENSE+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++ 0. This License Agreement applies to any software library or other+program which contains a notice placed by the copyright holder or+other authorized party saying it may be distributed under the terms of+this Lesser General Public License (also called "this License").+Each licensee is addressed as "you".++ A "library" means a collection of software functions and/or data+prepared so as to be conveniently linked with application programs+(which use some of those functions and data) to form executables.++ The "Library", below, refers to any such software library or work+which has been distributed under these terms. A "work based on the+Library" means either the Library or any derivative work under+copyright law: that is to say, a work containing the Library or a+portion of it, either verbatim or with modifications and/or translated+straightforwardly into another language. (Hereinafter, translation is+included without limitation in the term "modification".)++ "Source code" for a work means the preferred form of the work for+making modifications to it. For a library, complete source code means+all the source code for all modules it contains, plus any associated+interface definition files, plus the scripts used to control+compilation and installation of the library.++ Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope. The act of+running a program using the Library is not restricted, and output from+such a program is covered only if its contents constitute a work based+on the Library (independent of the use of the Library in a tool for+writing it). Whether that is true depends on what the Library does+and what the program that uses the Library does.++ 1. You may copy and distribute verbatim copies of the Library's+complete source code as you receive it, in any medium, provided that+you conspicuously and appropriately publish on each copy an+appropriate copyright notice and disclaimer of warranty; keep intact+all the notices that refer to this License and to the absence of any+warranty; and distribute a copy of this License along with the+Library.++ You may charge a fee for the physical act of transferring a copy,+and you may at your option offer warranty protection in exchange for a+fee.++ 2. You may modify your copy or copies of the Library or any portion+of it, thus forming a work based on the Library, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++ a) The modified work must itself be a software library.++ b) You must cause the files modified to carry prominent notices+ stating that you changed the files and the date of any change.++ c) You must cause the whole of the work to be licensed at no+ charge to all third parties under the terms of this License.++ d) If a facility in the modified Library refers to a function or a+ table of data to be supplied by an application program that uses+ the facility, other than as an argument passed when the facility+ is invoked, then you must make a good faith effort to ensure that,+ in the event an application does not supply such function or+ table, the facility still operates, and performs whatever part of+ its purpose remains meaningful.++ (For example, a function in a library to compute square roots has+ a purpose that is entirely well-defined independent of the+ application. Therefore, Subsection 2d requires that any+ application-supplied function or table used by this function must+ be optional: if the application does not supply it, the square+ root function must still compute square roots.)++These requirements apply to the modified work as a whole. If+identifiable sections of that work are not derived from the Library,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works. But when you+distribute the same sections as part of a whole which is a work based+on the Library, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote+it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Library.++In addition, mere aggregation of another work not based on the Library+with the Library (or with a work based on the Library) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++ 3. You may opt to apply the terms of the ordinary GNU General Public+License instead of this License to a given copy of the Library. To do+this, you must alter all the notices that refer to this License, so+that they refer to the ordinary GNU General Public License, version 2,+instead of to this License. (If a newer version than version 2 of the+ordinary GNU General Public License has appeared, then you can specify+that version instead if you wish.) Do not make any other change in+these notices.++ Once this change is made in a given copy, it is irreversible for+that copy, so the ordinary GNU General Public License applies to all+subsequent copies and derivative works made from that copy.++ This option is useful when you wish to copy part of the code of+the Library into a program that is not a library.++ 4. You may copy and distribute the Library (or a portion or+derivative of it, under Section 2) in object code or executable form+under the terms of Sections 1 and 2 above provided that you accompany+it with the complete corresponding machine-readable source code, which+must be distributed under the terms of Sections 1 and 2 above on a+medium customarily used for software interchange.++ If distribution of object code is made by offering access to copy+from a designated place, then offering equivalent access to copy the+source code from the same place satisfies the requirement to+distribute the source code, even though third parties are not+compelled to copy the source along with the object code.++ 5. A program that contains no derivative of any portion of the+Library, but is designed to work with the Library by being compiled or+linked with it, is called a "work that uses the Library". Such a+work, in isolation, is not a derivative work of the Library, and+therefore falls outside the scope of this License.++ However, linking a "work that uses the Library" with the Library+creates an executable that is a derivative of the Library (because it+contains portions of the Library), rather than a "work that uses the+library". The executable is therefore covered by this License.+Section 6 states terms for distribution of such executables.++ When a "work that uses the Library" uses material from a header file+that is part of the Library, the object code for the work may be a+derivative work of the Library even though the source code is not.+Whether this is true is especially significant if the work can be+linked without the Library, or if the work is itself a library. The+threshold for this to be true is not precisely defined by law.++ If such an object file uses only numerical parameters, data+structure layouts and accessors, and small macros and small inline+functions (ten lines or less in length), then the use of the object+file is unrestricted, regardless of whether it is legally a derivative+work. (Executables containing this object code plus portions of the+Library will still fall under Section 6.)++ Otherwise, if the work is a derivative of the Library, you may+distribute the object code for the work under the terms of Section 6.+Any executables containing that work also fall under Section 6,+whether or not they are linked directly with the Library itself.++ 6. As an exception to the Sections above, you may also combine or+link a "work that uses the Library" with the Library to produce a+work containing portions of the Library, and distribute that work+under terms of your choice, provided that the terms permit+modification of the work for the customer's own use and reverse+engineering for debugging such modifications.++ You must give prominent notice with each copy of the work that the+Library is used in it and that the Library and its use are covered by+this License. You must supply a copy of this License. If the work+during execution displays copyright notices, you must include the+copyright notice for the Library among them, as well as a reference+directing the user to the copy of this License. Also, you must do one+of these things:++ a) Accompany the work with the complete corresponding+ machine-readable source code for the Library including whatever+ changes were used in the work (which must be distributed under+ Sections 1 and 2 above); and, if the work is an executable linked+ with the Library, with the complete machine-readable "work that+ uses the Library", as object code and/or source code, so that the+ user can modify the Library and then relink to produce a modified+ executable containing the modified Library. (It is understood+ that the user who changes the contents of definitions files in the+ Library will not necessarily be able to recompile the application+ to use the modified definitions.)++ b) Use a suitable shared library mechanism for linking with the+ Library. A suitable mechanism is one that (1) uses at run time a+ copy of the library already present on the user's computer system,+ rather than copying library functions into the executable, and (2)+ will operate properly with a modified version of the library, if+ the user installs one, as long as the modified version is+ interface-compatible with the version that the work was made with.++ c) Accompany the work with a written offer, valid for at least+ three years, to give the same user the materials specified in+ Subsection 6a, above, for a charge no more than the cost of+ performing this distribution.++ d) If distribution of the work is made by offering access to copy+ from a designated place, offer equivalent access to copy the above+ specified materials from the same place.++ e) Verify that the user has already received a copy of these+ materials or that you have already sent this user a copy.++ For an executable, the required form of the "work that uses the+Library" must include any data and utility programs needed for+reproducing the executable from it. However, as a special exception,+the materials to be distributed need not include anything that is+normally distributed (in either source or binary form) with the major+components (compiler, kernel, and so on) of the operating system on+which the executable runs, unless that component itself accompanies+the executable.++ It may happen that this requirement contradicts the license+restrictions of other proprietary libraries that do not normally+accompany the operating system. Such a contradiction means you cannot+use both them and the Library together in an executable that you+distribute.++ 7. You may place library facilities that are a work based on the+Library side-by-side in a single library together with other library+facilities not covered by this License, and distribute such a combined+library, provided that the separate distribution of the work based on+the Library and of the other library facilities is otherwise+permitted, and provided that you do these two things:++ a) Accompany the combined library with a copy of the same work+ based on the Library, uncombined with any other library+ facilities. This must be distributed under the terms of the+ Sections above.++ b) Give prominent notice with the combined library of the fact+ that part of it is a work based on the Library, and explaining+ where to find the accompanying uncombined form of the same work.++ 8. You may not copy, modify, sublicense, link with, or distribute+the Library except as expressly provided under this License. Any+attempt otherwise to copy, modify, sublicense, link with, or+distribute the Library is void, and will automatically terminate your+rights under this License. However, parties who have received copies,+or rights, from you under this License will not have their licenses+terminated so long as such parties remain in full compliance.++ 9. You are not required to accept this License, since you have not+signed it. However, nothing else grants you permission to modify or+distribute the Library or its derivative works. These actions are+prohibited by law if you do not accept this License. Therefore, by+modifying or distributing the Library (or any work based on the+Library), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Library or works based on it.++ 10. Each time you redistribute the Library (or any work based on the+Library), the recipient automatically receives a license from the+original licensor to copy, distribute, link with or modify the Library+subject to these terms and conditions. You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties with+this License.++ 11. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+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+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Library at all. For example, if a patent+license would not permit royalty-free redistribution of the Library by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Library.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply, and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system which is+implemented by public license practices. Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++ 12. If the distribution and/or use of the Library is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Library under this License+may add an explicit geographical distribution limitation excluding those+countries, so that distribution is permitted only in or among+countries not thus excluded. In such case, this License incorporates+the limitation as if written in the body of this License.++ 13. The Free Software Foundation may publish revised and/or new+versions of the Lesser 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 Library+specifies a version number of this License which applies to it and+"any later version", you have the option of following the terms and+conditions either of that version or of any later version published by+the Free Software Foundation. If the Library does not specify a+license version number, you may choose any version ever published by+the Free Software Foundation.++ 14. If you wish to incorporate parts of the Library into other free+programs whose distribution conditions are incompatible with these,+write to the author to ask for permission. For software which is+copyrighted by the Free Software Foundation, write to the Free+Software Foundation; we sometimes make exceptions for this. Our+decision will be guided by the two goals of preserving the free status+of all derivatives of our free software and of promoting the sharing+and reuse of software generally.++ NO WARRANTY++ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR+OTHER PARTIES PROVIDE THE LIBRARY "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+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY+AND/OR REDISTRIBUTE THE LIBRARY 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+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH+DAMAGES.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Libraries++ If you develop a new library, and you want it to be of the greatest+possible use to the public, we recommend making it free software that+everyone can redistribute and change. You can do so by permitting+redistribution under these terms (or, alternatively, under the terms+of the ordinary General Public License).++ To apply these terms, attach the following notices to the library.+It is safest to attach them to the start of each source file to most+effectively convey 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 library's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This library is free software; you can redistribute it and/or+ modify it under the terms of the GNU Lesser General Public+ License as published by the Free Software Foundation; either+ version 2.1 of the License, or (at your option) any later version.++ This library 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+ Lesser General Public License for more details.++ You should have received a copy of the GNU Lesser General Public+ License along with this library; if not, write to the Free Software+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA++Also add information on how to contact you by electronic and paper mail.++You should also get your employer (if you work as a programmer) or+your school, if any, to sign a "copyright disclaimer" for the library,+if necessary. Here is a sample; alter the names:++ Yoyodyne, Inc., hereby disclaims all copyright interest in the+ library `Frob' (a library for tweaking knobs) written by James+ Random Hacker.++ <signature of Ty Coon>, 1 April 1990+ Ty Coon, President of Vice++That's all there is to it!++
+ COPYRIGHT view
@@ -0,0 +1,25 @@+listlike+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All code is under the following license unless otherwise noted:+ This program is free software; you can redistribute it and/or modify+ it under the terms of the GNU Lesser General Public License as published by+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program; if not, write to the Free Software+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA++The GNU General Public License is available in the file COPYING in the source+distribution. Debian GNU/Linux users may find this in+/usr/share/common-licenses/LGPL-2.1.++If the LGPL is unacceptable for your uses, please e-mail me; alternative+terms can be negotiated for your project.+
+ ListLike.cabal view
@@ -0,0 +1,43 @@+Name: ListLike+Version: 1.0.0+License: LGPL+Maintainer: John Goerzen <jgoerzen@complete.org>+Author: John Goerzen+Copyright: Copyright (c) 2007 John Goerzen+license-file: COPYRIGHT+extra-source-files: COPYING+Category: Generics+homepage: http://software.complete.org/listlike+synopsis: Generic support for list-like structures+Description: Generic support for list-like structures in Haskell.+ .+ The ListLike module provides a common interface to the various Haskell+ types that are list-like. Predefined interfaces include standard+ Haskell lists, Arrays, ByteStrings, and lazy ByteStrings. Custom+ types can easily be made ListLike instances as well.+ .+ ListLike also provides for String-like types, such as String and+ ByteString, for types that support input and output, and for types that can handle+ infinite lists.+Stability: Stable+Hs-Source-Dirs: src+Exposed-Modules: Data.ListLike,+ Data.ListLike.Base,+ Data.ListLike.FoldableLL,+ Data.ListLike.IO,+ Data.ListLike.Instances,+ Data.ListLike.String,+ Data.ListLike.Utils+-- Other-Modules: Data.ConfigFile.Lexer+Extensions: ExistentialQuantification, OverlappingInstances, + UndecidableInstances+Build-Depends: base,+ haskell98, mtl+GHC-Options: -O2++Executable: runtests+Buildable: False+Main-Is: runtests.hs+HS-Source-Dirs: testsrc, .+Extensions: ExistentialQuantification, OverlappingInstances,+ UndecidableInstances, CPP
+ Setup.hs view
@@ -0,0 +1,5 @@+#!/usr/bin/env runhaskell+import Distribution.Simple++main = defaultMain+
+ src/Data/ListLike.hs view
@@ -0,0 +1,256 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++{- |+ Module : Data.ListLike+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++Generic operations over list-like structures++Written by John Goerzen, jgoerzen\@complete.org++Please start with the introduction at "Data.ListLike#intro".+-}++module Data.ListLike + (-- * Introduction+ -- $intro+ + -- * Creation & Basic Functions+ empty, singleton, + cons, snoc, append, head, last, tail, init, null, length,+ -- * List transformations+ map, rigidMap, reverse, intersperse,+ -- ** Conversions+ toList, fromList, fromListLike,+ -- * Reducing lists (folds), from "FoldableLL"+ foldl, foldl', foldl1, foldr, foldr', foldr1,+ -- ** Special folds+ concat, concatMap, rigidConcatMap,+ and, or,+ any, all,+ sum, product,+ maximum, minimum,+ fold, foldMap,+ -- * Building lists+ -- ** Scans+ -- ** Accumulating maps+ -- ** Infinite lists+ iterate, repeat, replicate, cycle,+ -- ** Unfolding+ -- * Sublists+ -- ** Extracting sublists+ take, drop, splitAt, takeWhile, dropWhile, span, break,+ group, inits, tails, + -- ** Predicates+ isPrefixOf, isSuffixOf, isInfixOf,+ -- * Searching lists+ -- ** Searching by equality+ elem, notElem,+ -- ** Searching with a predicate+ find, filter, partition,+ -- * Indexing lists+ index, elemIndex, elemIndices, findIndex, findIndices,+ -- * Zipping and unzipping lists+ zip, zipWith, unzip,+ -- * Monadic Operations+ sequence, sequence_, mapM, rigidMapM, mapM_,+ -- * Input and Output+ ListLikeIO(..),+ -- * Special lists+ -- ** Strings+ toString, fromString, lines, words,+ -- ** \"Set\" operations+ nub, delete, deleteFirsts, union, intersect,+ -- ** Ordered lists+ sort, insert,+ -- * Generalized functions+ -- ** The \"By\" operations+ -- *** User-supplied equality (replacing an Eq context)+ nubBy, deleteBy, deleteFirstsBy, unionBy, intersectBy,+ groupBy,+ -- *** User-supplied comparison (replacing an Ord context)+ sortBy, insertBy, -- maximumBy, minimumBy,+ -- ** The \"generic\" operations+ genericLength, genericTake, genericDrop, genericSplitAt,+ -- genericIndex,+ genericReplicate,+ -- * Notes on specific instances+ -- ** Lists+ -- $noteslist++ -- ** Arrays+ -- $notesarray++ -- ** Maps+ -- $notesmap++ -- ** ByteStrings+ -- $notesbytestring+ + -- * Base Typeclasses+ -- ** The ListLike class+ ListLike,+ -- ** The FoldableLL class+ FoldableLL,+ -- ** The StringLike class+ StringLike,+ -- ** The InfiniteListLike class+ InfiniteListLike+ )+ where+import Prelude hiding (length, head, last, null, tail, map, filter, concat, + any, lookup, init, all, foldl, foldr, foldl1, foldr1,+ maximum, minimum, iterate, span, break, takeWhile,+ dropWhile, reverse, zip, zipWith, sequence,+ sequence_, mapM, mapM_, concatMap, and, or, sum,+ product, repeat, replicate, cycle, take, drop,+ splitAt, elem, notElem, unzip, lines, words,+ unlines, unwords)+import Data.ListLike.Base+import Data.ListLike.FoldableLL+import Data.ListLike.Instances()+import Data.ListLike.String+import Data.ListLike.Utils+import Data.ListLike.IO++{- $intro+ #intro#+Welcome to ListLike.++This module provides abstractions over typical list operations.+It is designed to let you freely interchange different ways to represent+sequences of data. It works with lists, various types of ByteStrings,+and much more.++In this module, you'll find generic versions of most of the functions+you're used to using in the "Prelude", "Data.List", and "System.IO".+They carry the+same names, too. Therefore, you'll want to be careful how you import+the module. I suggest using:++>import qualified ListLike as LL++Then, you can use LL.fold, LL.map, etc. to get the generic version of+the functions you want. Alternatively, you can hide the other versions+from Prelude and import specific generic functions from here, such as:++>import Prelude hiding (map)+>import ListLike (map)++The I\/O features of ListLike may a+The module "Data.ListLike" actually simply re-exports the items found+in a number of its sub-modules. If you want a smaller subset of+"Data.ListLike", look at the documentation for its sub-modules and import+the relevant one.++In most cases, functions here can act as drop-in replacements for their+list-specific counterparts. They will use the same underlying implementations+for lists, so there should be no performance difference.+ +You can make your own types instances of 'ListLike' as well. For more+details, see the notes for the 'ListLike' typeclass.+-}++{- $noteslist++Functions for operating on regular lists almost all use the native+implementations in "Data.List", "Prelude", or similar standard+modules. The exceptions are:++* 'mapM' uses the default 'ListLike' implementation++* 'hGet' does not exist for 'String' in the Haskell modules.+ It is implemented in terms of "Data.ByteString.Lazy".++* 'hGetNonBlocking' is the same way. -}++{- $notesarray++'Data.Array.Array' is an instance of 'ListLike'. Here are some notes about it:++* The index you use must be an integral++* 'ListLike' functions that take an index always take a 0-based index+ for compatibility with other 'ListLike' instances.+ This is translated by the instance functions into the proper offset from+ the bounds in the Array.++* 'ListLike' functions preserve the original Array index numbers when+ possible. Functions such as 'cons' will reduce the lower bound to do+ their job. 'snoc' and 'append' increase the upper bound. 'drop' raises+ the lower bound and 'take' lowers the upper bound.++* Functions that change the length of the array by an amount not known+ in advance, such as 'filter', will generate a new array with the lower+ bound set to 0. Furthermore, these functions cannot operate on infinite+ lists because they must know their length in order to generate the+ array. 'hGetContents' and its friends will therefore require the+ entire file to be read into memory before processing is possible.++* 'empty', 'singleton', and 'fromList' also generate an array with the+ lower bound set to 0.++* Many of these functions will generate runtime exceptions if you have+ not assigned a value to every slot in the array.+-}++{- $notesmap++'Data.Map.Map' is an instance of 'ListLike' and is a rather interesting one at+that. The \"item\" for the Map instance is a @(key, value)@ pair. This+permits you to do folds, maps, etc. over a Map just like you would on a list.++The nature of a Map -- that every key is unique, and that it is internally+sorted -- means that there are some special things to take note of:++* 'cons' may or may not actually increase the size of the Map. If the given+ key is already in the map, its value will simply be updated. Since+ a Map has a set internal ordering, it is also not guaranteed that cons+ will add something to the beginning of the Map.++* 'snoc' is the same operation as 'cons'.++* 'append' is 'Data.Map.union'++* 'nub', 'nubBy',+ 'reverse', 'sort', 'sortBy', etc. are the identity function and don\'t+ actually perform any computation++* 'insert' is the same as 'cons'.++* 'replicate' and 'genericReplicate' ignore the count and return a Map+ with a single element.+-}++{- $notesbytestring++Both strict and lazy ByteStreams can be used with 'ListLike'.++Most 'ListLike' operations map directly to ByteStream options. Notable+exceptions:++* 'map' uses the 'ListLike' implementation. 'rigidMap' is more efficient.+ The same goes for 'concatMap' vs. 'rigidConcatMap'.++* 'isInfixOf', 'sequence', 'mapM' and similar monad operations, 'insert', + 'union', 'intersect', 'sortBy', and similar functions are not implemented+ in 'ByteStream' and use a naive default implementation.++* The lazy ByteStream module implements fewer funtions than the strict+ ByteStream module. In some cases, default implementations are used.+ In others, notably related to I\/O, the lazy ByteStreams are converted+ back and forth to strict ones as appropriate.++-}
+ src/Data/ListLike/Base.hs view
@@ -0,0 +1,630 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++{- |+ Module : Data.ListLike.Base+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++Generic operations over list-like structures++Written by John Goerzen, jgoerzen\@complete.org+-}++module Data.ListLike.Base + (+ ListLike(..),+ InfiniteListLike(..),+ zip, zipWith, sequence_+ ) where+import Prelude hiding (length, head, last, null, tail, map, filter, concat, + any, lookup, init, all, foldl, foldr, foldl1, foldr1,+ maximum, minimum, iterate, span, break, takeWhile,+ dropWhile, reverse, zip, zipWith, sequence,+ sequence_, mapM, mapM_, concatMap, and, or, sum,+ product, repeat, replicate, cycle, take, drop,+ splitAt, elem, notElem, unzip, lines, words,+ unlines, unwords)+import qualified Data.List as L+import Data.ListLike.FoldableLL+import qualified Control.Monad as M+import Data.Monoid+import Data.Maybe++{- | The class implementing list-like functions.++It is worth noting that types such as 'Data.Map.Map' can be instances of+'ListLike'. Due to their specific ways of operating, they may not behave+in the expected way in some cases. For instance, 'cons' may not increase+the size of a map if the key you have given is already in the map; it will+just replace the value already there.++Implementators must define at least:++* singleton++* head++* tail++* null or genericLength+-}+class (FoldableLL full item, Monoid full) =>+ ListLike full item | full -> item where++ ------------------------------ Creation+ {- | The empty list -}+ empty :: full+ empty = mempty++ {- | Creates a single-itement list out of an itement -}+ singleton :: item -> full++ ------------------------------ Basic Functions++ {- | Like (:) for lists: adds an itement to the beginning of a list -}+ cons :: item -> full -> full+ cons item l = append (singleton item) l++ {- | Adds an itement to the *end* of a 'ListLike'. -}+ snoc :: full -> item -> full+ snoc l item = append l (singleton item)++ {- | Combines two lists. Like (++). -}+ append :: full -> full -> full + append = mappend++ {- | Extracts the first itement of a 'ListLike'. -}+ head :: full -> item++ {- | Extracts the last itement of a 'ListLike'. -}+ last :: full -> item+ last l = case genericLength l of+ (0::Integer) -> error "Called last on empty list"+ 1 -> head l+ _ -> last (tail l)++ {- | Gives all itements after the head. -}+ tail :: full -> full ++ {- | All elements of the list except the last one. See also 'inits'. -}+ init :: full -> full+ init l+ | null l = error "init: empty list"+ | null xs = empty+ | otherwise = cons (head l) (init xs)+ where xs = tail l++ {- | Tests whether the list is empty. -}+ null :: full -> Bool+ null x = genericLength x == (0::Integer)++ {- | Length of the list. See also 'genericLength'. -}+ length :: full -> Int+ length = genericLength++ ------------------------------ List Transformations++ {- | Apply a function to each element, returning any other+ valid 'ListLike'. 'rigidMap' will always be at least+ as fast, if not faster, than this function and is recommended+ if it will work for your purposes. See also 'mapM'. -}+ map :: ListLike full' item' => (item -> item') -> full -> full'+ map func inp + | null inp = empty+ | otherwise = cons (func (head inp)) (map func (tail inp))++ {- | Like 'map', but without the possibility of changing the type of+ the item. This can have performance benefits for things such as+ ByteStrings, since it will let the ByteString use its native+ low-level map implementation. -}+ rigidMap :: (item -> item) -> full -> full+ rigidMap = map++ {- | Reverse the elements in a list. -}+ reverse :: full -> full + reverse l = rev l empty+ where rev rl a+ | null rl = a+ | otherwise = rev (tail rl) (cons (head rl) a)+ {- | Add an item between each element in the structure -}+ intersperse :: item -> full -> full+ intersperse sep l+ | null l = empty+ | null xs = singleton x+ | otherwise = cons x (cons sep (intersperse sep xs))+ where x = head l+ xs = tail l++ ------------------------------ Reducing Lists (folds)+ -- See also functions in FoldableLLL++ ------------------------------ Special folds+ {- | Flatten the structure. -}+ concat :: (ListLike full' full, Monoid full) => full' -> full+ concat = fold++ {- | Map a function over the items and concatenate the results.+ See also 'rigidConcatMap'.-}+ concatMap :: (ListLike full' item') =>+ (item -> full') -> full -> full'+ concatMap = foldMap++ {- | Like 'concatMap', but without the possibility of changing+ the type of the item. This can have performance benefits+ for some things such as ByteString. -}+ rigidConcatMap :: (item -> full) -> full -> full+ rigidConcatMap = concatMap++ {- | True if any items satisfy the function -}+ any :: (item -> Bool) -> full -> Bool+ any p = getAny . foldMap (Any . p)++ {- | True if all items satisfy the function -}+ all :: (item -> Bool) -> full -> Bool+ all p = getAll . foldMap (All . p)++ {- | The maximum value of the list -}+ maximum :: Ord item => full -> item+ maximum = foldr1 max++ {- | The minimum value of the list -}+ minimum :: Ord item => full -> item+ minimum = foldr1 min++ ------------------------------ Infinite lists+ {- | Generate a structure with the specified length with every element+ set to the item passed in. See also 'genericReplicate' -}+ replicate :: Int -> item -> full+ replicate = genericReplicate++ ------------------------------ Sublists+ {- | Takes the first n elements of the list. See also 'genericTake'. -}+ take :: Int -> full -> full+ take = genericTake++ {- | Drops the first n elements of the list. See also 'genericDrop' -}+ drop :: Int -> full -> full+ drop = genericDrop++ {- | Equivalent to @('take' n xs, 'drop' n xs)@. See also 'genericSplitAt'. -}+ splitAt :: Int -> full -> (full, full)+ splitAt = genericSplitAt++ {- | Returns all elements at start of list that satisfy the function. -}+ takeWhile :: (item -> Bool) -> full -> full+ takeWhile func l + | null l = empty+ | func x = cons x (takeWhile func (tail l))+ | otherwise = empty+ where x = head l++ {- | Drops all elements form the start of the list that satisfy the+ function. -}+ dropWhile :: (item -> Bool) -> full -> full+ dropWhile func l+ | null l = empty+ | func (head l) = dropWhile func (tail l)+ | otherwise = l++ {- | The equivalent of @('takeWhile' f xs, 'dropWhile' f xs)@ -}+ span :: (item -> Bool) -> full -> (full, full)+ span func l+ | null l = (empty, empty)+ | func x = (cons x ys, zs) + | otherwise = (empty, l)+ where (ys, zs) = span func (tail l)+ x = head l+ {- | The equivalent of @'span' ('not' . f)@ -}+ break :: (item -> Bool) -> full -> (full, full)+ break p = span (not . p)++ {- | Split a list into sublists, each which contains equal arguments.+ For order-preserving types, concatenating these sublists will produce+ the original list. See also 'groupBy'. -}+ group :: (ListLike full' full, Eq item) => full -> full'+ group = groupBy (==)++ {- | All initial segments of the list, shortest first -}+ inits :: (ListLike full' full) => full -> full'+ inits l+ | null l = singleton empty+ | otherwise =+ append (singleton empty)+ (map (cons (head l)) theinits)+ where theinits = asTypeOf (inits (tail l)) [l]++ {- | All final segnemts, longest first -}+ tails :: ListLike full' full => full -> full'+ tails l+ | null l = singleton empty+ | otherwise = cons l (tails (tail l))++ ------------------------------ Predicates+ {- | True when the first list is at the beginning of the second. -}+ isPrefixOf :: Eq item => full -> full -> Bool+ isPrefixOf needle haystack+ | null needle = True+ | null haystack = False+ | otherwise = (head needle) == (head haystack) && + isPrefixOf (tail needle) (tail haystack)++ {- | True when the first list is at the beginning of the second. -}+ isSuffixOf :: Eq item => full -> full -> Bool+ isSuffixOf needle haystack = isPrefixOf (reverse needle) (reverse haystack)++ {- | True when the first list is wholly containted within the second -}+ isInfixOf :: Eq item => full -> full -> Bool+ isInfixOf needle haystack = + any (isPrefixOf needle) thetails+ where thetails = asTypeOf (tails haystack) [haystack]++ ------------------------------ Searching+ {- | True if the item occurs in the list -}+ elem :: Eq item => item -> full -> Bool+ elem i = any (== i)++ {- | True if the item does not occur in the list -}+ notElem :: Eq item => item -> full -> Bool+ notElem i = all (/= i)++ {- | Take a function and return the first matching element, or Nothing+ if there is no such element. -}+ find :: (item -> Bool) -> full -> Maybe item+ find f l = case findIndex f l of+ Nothing -> Nothing+ Just x -> Just (index l x)++ {- | Returns only the elements that satisfy the function. -}+ filter :: (item -> Bool) -> full -> full + filter func l + | null l = empty+ | func (head l) = cons (head l) (filter func (tail l))+ | otherwise = filter func (tail l)++ {- | Returns the lists that do and do not satisfy the function.+ Same as @('filter' p xs, 'filter' ('not' . p) xs)@ -}+ partition :: (item -> Bool) -> full -> (full, full)+ partition p xs = (filter p xs, filter (not . p) xs)++ ------------------------------ Indexing+ {- | The element at 0-based index i. Raises an exception if i is out+ of bounds. Like (!!) for lists. -}+ index :: full -> Int -> item+ index l i + | null l = error "index: index not found"+ | i < 0 = error "index: index must be >= 0"+ | i == 0 = head l+ | otherwise = index (tail l) (i - 1)++ {- | Returns the index of the element, if it exists. -}+ elemIndex :: Eq item => item -> full -> Maybe Int+ elemIndex e l = findIndex (== e) l++ {- | Returns the indices of the matching elements. See also + 'findIndices' -}+ elemIndices :: (Eq item, ListLike result Int) => item -> full -> result+ elemIndices i l = findIndices (== i) l++ {- | Take a function and return the index of the first matching element,+ or Nothing if no element matches -}+ findIndex :: (item -> Bool) -> full -> Maybe Int+ findIndex f = listToMaybe . findIndices f++ {- | Returns the indices of all elements satisfying the function -}+ findIndices :: (ListLike result Int) => (item -> Bool) -> full -> result+ findIndices p xs = map snd $ filter (p . fst) $ thezips+ where thezips = asTypeOf (zip xs [0..]) [(head xs, 0::Int)]++ ------------------------------ Monadic operations+ {- | Evaluate each action in the sequence and collect the results -}+ sequence :: (Monad m, ListLike fullinp (m item)) =>+ fullinp -> m full+ sequence l = foldr func (return empty) l+ where func litem results = + do x <- litem+ xs <- results+ return (cons x xs)++ {- | A map in monad space. Same as @'sequence' . 'map'@ + + See also 'rigidMapM' -}+ mapM :: (Monad m, ListLike full' item') => + (item -> m item') -> full -> m full'+ mapM func l = sequence mapresult+ where mapresult = asTypeOf (map func l) []++ {- | Like 'mapM', but without the possibility of changing the type+ of the item. This can have performance benefits with some types. -}+ rigidMapM :: Monad m => (item -> m item) -> full -> m full+ rigidMapM = mapM+ + {- | A map in monad space, discarding results. Same as+ @'sequence_' . 'map'@ -}+ mapM_ :: (Monad m) => (item -> m b) -> full -> m ()+ mapM_ func l = sequence_ mapresult+ where mapresult = asTypeOf (map func l) []+++ ------------------------------ "Set" operations+ {- | Removes duplicate elements from the list. See also 'nubBy' -}+ nub :: Eq item => full -> full+ nub = nubBy (==)++ {- | Removes the first instance of the element from the list.+ See also 'deleteBy' -}+ delete :: Eq item => item -> full -> full+ delete = deleteBy (==)++ {- | List difference. Removes from the first list the first instance+ of each element of the second list. See '(\\)' and 'deleteFirstsBy' -}+ deleteFirsts :: Eq item => full -> full -> full+ deleteFirsts = foldl (flip delete)++ {- | List union: the set of elements that occur in either list.+ Duplicate elements in the first list will remain duplicate.+ See also 'unionBy'. -}+ union :: Eq item => full -> full -> full+ union = unionBy (==)++ {- | List intersection: the set of elements that occur in both lists.+ See also 'intersectBy' -}+ intersect :: Eq item => full -> full -> full+ intersect = intersectBy (==)++ ------------------------------ Ordered lists+ {- | Sorts the list. On data types that do not preserve ordering,+ or enforce their own ordering, the result may not be what+ you expect. See also 'sortBy'. -}+ sort :: Ord item => full -> full+ sort = sortBy compare++ {- | Inserts the itement at the last place where it is still less than or+ equal to the next itement. On data types that do not preserve + ordering, or enforce their own ordering, the result may not+ be what you expect. On types such as maps, this may result in+ changing an existing item. See also 'insertBy'. -}+ insert :: Ord item => item -> full -> full + insert = insertBy compare++ ------------------------------ Conversions++ {- | Converts the structure to a list. This is logically equivolent+ to 'fromListLike', but may have a more optimized implementation. -}+ toList :: full -> [item]+ toList = fromListLike++ {- | Generates the structure from a list. -}+ fromList :: [item] -> full + fromList [] = empty+ fromList (x:xs) = cons x (fromList xs)++ {- | Converts one ListLike to another. See also 'toList'.+ Default implementation is @fromListLike = map id@ -}+ fromListLike :: ListLike full' item => full -> full'+ fromListLike = map id++ ------------------------------ Generalized functions+ {- | Generic version of 'nub' -}+ nubBy :: (item -> item -> Bool) -> full -> full+ nubBy f l+ | null l = empty+ | otherwise =+ cons (head l) (nubBy f (filter (\y -> not (f (head l) y)) (tail l)))++ {- | Generic version of 'deleteBy' -}+ deleteBy :: (item -> item -> Bool) -> item -> full -> full+ deleteBy func i l+ | null l = empty+ | otherwise =+ if func i (head l)+ then tail l+ else cons (head l) (deleteBy func i (tail l))++ {- | Generic version of 'deleteFirsts' -}+ deleteFirstsBy :: (item -> item -> Bool) -> full -> full -> full+ deleteFirstsBy func = foldl (flip (deleteBy func))++ {- | Generic version of 'union' -}+ unionBy :: (item -> item -> Bool) -> full -> full -> full+ unionBy func x y =+ append x $ foldl (flip (deleteBy func)) (nubBy func y) x++ {- | Generic version of 'intersect' -}+ intersectBy :: (item -> item -> Bool) -> full -> full -> full+ intersectBy func xs ys = filter (\x -> any (func x) ys) xs++ {- | Generic version of 'group'. -}+ groupBy :: (ListLike full' full, Eq item) => + (item -> item -> Bool) -> full -> full'+ groupBy eq l+ | null l = empty+ | otherwise = cons (cons x ys) (groupBy eq zs)+ where (ys, zs) = span (eq x) xs+ x = head l+ xs = tail l++ {- | Sort function taking a custom comparison function -}+ sortBy :: Ord item => (item -> item -> Ordering) -> full -> full + sortBy cmp = foldr (insertBy cmp) empty++ {- | Like 'insert', but with a custom comparison function -}+ insertBy :: Ord item => (item -> item -> Ordering) -> item ->+ full -> full + insertBy cmp x ys+ | null ys = singleton x+ | otherwise = case cmp x (head ys) of+ GT -> cons (head ys) (insertBy cmp x (tail ys))+ _ -> cons x ys++ ------------------------------ Generic Operations+ {- | Length of the list -}+ genericLength :: Num a => full -> a+ genericLength l = calclen 0 l+ where calclen accum cl =+ if null cl+ then accum+ else calclen (accum + 1) (tail cl)++ {- | Generic version of 'take' -}+ genericTake :: Integral a => a -> full -> full+ genericTake n l+ | n <= 0 = empty+ | null l = empty+ | otherwise = cons (head l) (genericTake (n - 1) (tail l))++ {- | Generic version of 'drop' -}+ genericDrop :: Integral a => a -> full -> full+ genericDrop n l + | n <= 0 = l+ | null l = l+ | otherwise = genericDrop (n - 1) (tail l)++ {- | Generic version of 'splitAt' -}+ genericSplitAt :: Integral a => a -> full -> (full, full)+ genericSplitAt n l = (genericTake n l, genericDrop n l)++ {- | Generic version of 'replicate' -}+ genericReplicate :: Integral a => a -> item -> full+ genericReplicate count x + | count <= 0 = empty+ | otherwise = map (\_ -> x) [1..count]++{-+instance (ListLike full item) => Monad full where+ m >>= k = foldr (append . k) empty m+ m >> k = foldr (append . (\_ -> k)) empty m+ return x = singleton x+ fail _ = empty++instance (ListLike full item) => M.MonadPlus full where+ mzero = empty+ mplus = append+-}++{- | An extension to 'ListLike' for those data types that are capable+of dealing with infinite lists. Some 'ListLike' functions are capable+of working with finite or infinite lists. The functions here require+infinite list capability in order to work at all. -}+class (ListLike full item) => InfiniteListLike full item | full -> item where+ {- | An infinite list of repeated calls of the function to args -}+ iterate :: (item -> item) -> item -> full+ iterate f x = cons x (iterate f (f x))++ {- | An infinite list where each element is the same -}+ repeat :: item -> full+ repeat x = xs+ where xs = cons x xs++ {- | Converts a finite list into a circular one -}+ cycle :: full -> full+ cycle xs + | null xs = error "ListLike.cycle: empty list"+ | otherwise = xs' where xs' = append xs xs'++--------------------------------------------------+-- This instance is here due to some default class functions++instance ListLike [a] a where+ empty = []+ singleton x = [x]+ cons x l = x : l+ snoc l x = l ++ [x]+ append = (++)+ head = L.head+ last = L.last+ tail = L.tail+ init = L.init+ null = L.null+ length = L.length+ map f = fromList . L.map f+ rigidMap = L.map+ reverse = L.reverse+ intersperse = L.intersperse+ toList = id+ fromList = id+ -- fromListLike = toList+ concat = L.concat . toList+ -- concatMap func = fromList . L.concatMap func+ rigidConcatMap = L.concatMap+ any = L.any+ all = L.all+ maximum = L.maximum+ minimum = L.minimum+ -- fold+ -- foldMap+ replicate = L.replicate+ take = L.take+ drop = L.drop+ splitAt = L.splitAt+ takeWhile = L.takeWhile+ dropWhile = L.dropWhile+ span = L.span+ break = L.break+ group = fromList . L.group+ inits = fromList . L.inits+ tails = fromList . L.tails+ isPrefixOf = L.isPrefixOf+ isSuffixOf = L.isSuffixOf+ isInfixOf = L.isInfixOf+ elem = L.elem+ notElem = L.notElem+ find = L.find+ filter = L.filter+ partition = L.partition+ index = (L.!!)+ elemIndex = L.elemIndex+ elemIndices item = fromList . L.elemIndices item+ findIndex = L.findIndex+ sequence = M.sequence . toList+ -- mapM = M.mapM+ mapM_ = M.mapM_+ nub = L.nub+ delete = L.delete+ deleteFirsts = (L.\\)+ union = L.union+ intersect = L.intersect+ sort = L.sort+ groupBy func = fromList . L.groupBy func+ unionBy = L.unionBy+ intersectBy = L.intersectBy+ sortBy = L.sortBy+ insert = L.insert+++--------------------------------------------------+-- These utils are here instead of in Utils.hs because they are needed+-- by default class functions++{- | Takes two lists and returns a list of corresponding pairs. -}+zip :: (ListLike full item,+ ListLike fullb itemb,+ ListLike result (item, itemb)) =>+ full -> fullb -> result+zip = zipWith (\a b -> (a, b))++{- | Takes two lists and combines them with a custom combining function -}+zipWith :: (ListLike full item,+ ListLike fullb itemb,+ ListLike result resultitem) =>+ (item -> itemb -> resultitem) -> full -> fullb -> result+zipWith f a b+ | null a = empty+ | null b = empty+ | otherwise = cons (f (head a) (head b)) (zipWith f (tail a) (tail b))++{- | Evaluate each action, ignoring the results -}+sequence_ :: (Monad m, ListLike mfull (m item)) => mfull -> m ()+sequence_ l = foldr (>>) (return ()) l++
+ src/Data/ListLike/FoldableLL.hs view
@@ -0,0 +1,100 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT+-}++{- |+ Module : Data.ListLike.FoldableLL+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++Generic tools for data structures that can be folded.++Written by John Goerzen, jgoerzen\@complete.org++-}+module Data.ListLike.FoldableLL + (-- * FoldableLL Class+ FoldableLL(..),+ -- * Utilities+ fold, foldMap+ ) where +import Prelude hiding (foldl, foldr, foldr1)+import qualified Data.Foldable as F+import Data.Monoid+import Data.Maybe+import qualified Data.List as L++{- | This is the primary class for structures that are to be considered +foldable. A minimum complete definition provides 'foldl' and 'foldr'.++Instances of 'FoldableLL' can be folded, and can be many and varied.++These functions are used heavily in "Data.ListLike". -}+class FoldableLL full item | full -> item where+ {- | Left-associative fold -}+ foldl :: (a -> item -> a) -> a -> full -> a++ {- | Strict version of 'foldl'. -}+ foldl' :: (a -> item -> a) -> a -> full -> a+ -- This implementation from Data.Foldable+ foldl' f a xs = foldr f' id xs a+ where f' x k z = k $! f z x++ -- | A variant of 'foldl' with no base case. Requires at least 1+ -- list element.+ foldl1 :: (item -> item -> item) -> full -> item+ -- This implementation from Data.Foldable+ foldl1 f xs = fromMaybe (error "fold1: empty structure")+ (foldl mf Nothing xs)+ where mf Nothing y = Just y+ mf (Just x) y = Just (f x y)+ {- | Right-associative fold -}+ foldr :: (item -> b -> b) -> b -> full -> b++ -- | Strict version of 'foldr'+ foldr' :: (item -> b -> b) -> b -> full -> b+ -- This implementation from Data.Foldable+ foldr' f a xs = foldl f' id xs a+ where f' k x z = k $! f x z++ -- | Like 'foldr', but with no starting value+ foldr1 :: (item -> item -> item) -> full -> item+ -- This implementation from Data.Foldable+ foldr1 f xs = fromMaybe (error "foldr1: empty structure")+ (foldr mf Nothing xs)+ where mf x Nothing = Just x+ mf x (Just y) = Just (f x y)++{- | Combine the elements of a structure using a monoid.+ @'fold' = 'foldMap' id@ -}+fold :: (FoldableLL full item, Monoid item) => full -> item+fold = foldMap id++{- | Map each element to a monoid, then combine the results -}+foldMap :: (FoldableLL full item, Monoid m) => (item -> m) -> full -> m+foldMap f = foldr (mappend . f) mempty++instance FoldableLL [a] a where+ foldl = L.foldl+ foldl1 = L.foldl1+ foldl' = L.foldl'+ foldr = L.foldr+ foldr1 = L.foldr1+ foldr' = F.foldr'+{-+instance (F.Foldable f) => FoldableLL (f a) a where+ foldl = F.foldl+ foldl1 = F.foldl1+ foldl' = F.foldl'+ foldr = F.foldr+ foldr1 = F.foldr1+ foldr' = F.foldr'+-}
+ src/Data/ListLike/IO.hs view
@@ -0,0 +1,125 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++{- |+ Module : Data.ListLike.IO+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++String-like functions++Written by John Goerzen, jgoerzen\@complete.org+-}++module Data.ListLike.IO+ ( ListLikeIO(..)+ )+ where+import Prelude hiding (length, head, last, null, tail, map, filter, concat, + any, lookup, init, all, foldl, foldr, foldl1, foldr1,+ maximum, minimum, iterate, span, break, takeWhile,+ dropWhile, reverse, zip, zipWith, sequence,+ sequence_, mapM, mapM_, concatMap, and, or, sum,+ product, repeat, replicate, cycle, take, drop,+ splitAt, elem, notElem, unzip, lines, words,+ unlines, unwords, putStr, getContents)+import qualified System.IO as IO+import Data.ListLike.Base++{- | An extension to 'ListLike' for those data types that support+I\/O. These functions mirror those in "System.IO" for the most part. They+also share the same names; see the comments in "Data.ListLike" for help+importing them.++Note that some types may not be capable of lazy reading or writing.+Therefore, the usual semantics of "System.IO" functions regarding laziness+may or may not be available from a particular implementation.+ +Minimal complete definition:++* hGetLine++* hGetContents++* hGet++* hGetNonBlocking++* hPutStr+-}+class (ListLike full item) => ListLikeIO full item | full -> item where+ {- | Reads a line from the specified handle -}+ hGetLine :: IO.Handle -> IO full++ -- | Read entire handle contents. May be done lazily like+ -- 'System.IO.hGetContents'.+ hGetContents :: IO.Handle -> IO full++ -- | Read specified number of bytes. See 'System.IO.hGet' for+ -- particular semantics.+ hGet :: IO.Handle -> Int -> IO full++ -- | Non-blocking read. See 'System.IO.hGetNonBlocking' for more.+ hGetNonBlocking :: IO.Handle -> Int -> IO full++ -- | Writing entire data.+ hPutStr :: IO.Handle -> full -> IO ()++ -- | Write data plus newline character.+ hPutStrLn :: IO.Handle -> full -> IO ()+ hPutStrLn fp x =+ do hPutStr fp x+ IO.hPutStrLn fp ""++ -- | Read one line+ getLine :: IO full+ getLine = hGetLine IO.stdin++ -- | Read entire content from stdin. See 'hGetContents'.+ getContents :: IO full+ getContents = hGetContents IO.stdin++ -- | Write data to stdout.+ putStr :: full -> IO ()+ putStr = hPutStr IO.stdout++ -- | Write data plus newline character to stdout.+ putStrLn :: full -> IO ()+ putStrLn = hPutStrLn IO.stdout++ -- | Interact with stdin and stdout by using a function to transform+ -- input to output. May be lazy. See 'System.IO.interact' for more.+ interact :: (full -> full) -> IO ()+ interact func = + do c <- getContents+ putStr (func c)++ -- | Read file. May be lazy.+ readFile :: FilePath -> IO full+ readFile fn =+ do fp <- IO.openFile fn IO.ReadMode+ hGetContents fp++ -- | Write data to file.+ writeFile :: FilePath -> full -> IO ()+ writeFile fn x =+ do fp <- IO.openFile fn IO.WriteMode+ hPutStr fp x+ IO.hClose fp++ -- | Append data to file.+ appendFile :: FilePath -> full -> IO ()+ appendFile fn x =+ do fp <- IO.openFile fn IO.AppendMode+ hPutStr fp x+ IO.hClose fp
+ src/Data/ListLike/Instances.hs view
@@ -0,0 +1,542 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++{- |+ Module : Data.ListLike.Instances+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++Instances of 'Data.ListLike.ListLike' and related classes.+Re-exported by "Data.ListLike".++Written by John Goerzen, jgoerzen\@complete.org+-}++module Data.ListLike.Instances () where+import Prelude hiding (length, head, last, null, tail, map, filter, concat, + any, lookup, init, all, foldl, foldr, foldl1, foldr1,+ maximum, minimum, iterate, span, break, takeWhile,+ dropWhile, reverse, zip, zipWith, sequence,+ sequence_, mapM, mapM_, concatMap, and, or, sum,+ product, repeat, replicate, cycle, take, drop,+ splitAt, elem, notElem, unzip, lines, words,+ unlines, unwords)+import qualified Data.List as L+import Data.ListLike.Base+import Data.ListLike.String+import Data.ListLike.IO+import Data.ListLike.FoldableLL+import Data.Int+import Data.Monoid+import qualified Data.ByteString as BS+import qualified Data.Foldable as F+import qualified Data.Array.IArray as A+import Data.Array.IArray((!), (//), Ix(..))+import qualified Data.ByteString.Lazy as BSL+import qualified System.IO as IO+import Data.Word+import qualified Data.Map as Map++--------------------------------------------------+-- []++-- Basic list instance is in Base.hs+-- FoldableLL instance implied by Foldable++instance ListLikeIO String Char where+ hGetLine = IO.hGetLine+ hGetContents = IO.hGetContents+ hGet h c = BSL.hGet h c >>= (return . toString)+ hGetNonBlocking h i = BSL.hGetNonBlocking h i >>= (return . toString)+ hPutStr = IO.hPutStr+ hPutStrLn = IO.hPutStrLn+ getLine = IO.getLine+ getContents = IO.getContents+ putStr = IO.putStr+ putStrLn = IO.putStrLn+ interact = IO.interact+ readFile = IO.readFile+ writeFile = IO.writeFile++instance StringLike String where+ toString = id+ fromString = id++instance InfiniteListLike [a] a where+ iterate = L.iterate+ repeat = L.repeat+ cycle = L.cycle++--------------------------------------------------+-- ByteString++instance FoldableLL BS.ByteString Word8 where+ foldl = BS.foldl+ foldl' = BS.foldl'+ foldl1 = BS.foldl1+ foldr = BS.foldr+ foldr' = BS.foldr'+ foldr1 = BS.foldr1++instance ListLike BS.ByteString Word8 where+ empty = BS.empty+ singleton = BS.singleton+ cons = BS.cons+ snoc = BS.snoc+ append = BS.append+ head = BS.head+ last = BS.last+ tail = BS.tail+ init = BS.init+ null = BS.null+ length = BS.length+ -- map = BS.map+ rigidMap = BS.map+ reverse = BS.reverse+ intersperse = BS.intersperse+ concat = BS.concat . toList+ --concatMap = BS.concatMap+ rigidConcatMap = BS.concatMap+ any = BS.any+ all = BS.all+ maximum = BS.maximum+ minimum = BS.minimum+ replicate = BS.replicate+ take = BS.take+ drop = BS.drop+ splitAt = BS.splitAt+ takeWhile = BS.takeWhile+ dropWhile = BS.dropWhile+ span = BS.span+ break = BS.break+ group = fromList . BS.group+ inits = fromList . BS.inits+ tails = fromList . BS.tails+ isPrefixOf = BS.isPrefixOf+ isSuffixOf = BS.isSuffixOf+ --isInfixOf = BS.isInfixOf+ elem = BS.elem+ notElem = BS.notElem+ find = BS.find+ filter = BS.filter+ --partition = BS.partition+ index = BS.index+ elemIndex = BS.elemIndex+ elemIndices x = fromList . BS.elemIndices x+ findIndex = BS.findIndex+ findIndices x = fromList . BS.findIndices x+ --sequence = BS.sequence+ --mapM = BS.mapM+ --mapM_ = BS.mapM_+ --nub = BS.nub+ --delete = BS.delete+ --deleteFirsts = BS.deleteFirsts+ --union = BS.union+ --intersect = BS.intersect+ sort = BS.sort+ --insert = BS.insert+ toList = BS.unpack+ fromList = BS.pack+ fromListLike = fromList . toList+ --nubBy = BS.nubBy+ --deleteBy = BS.deleteBy+ --deleteFirstsBy = BS.deleteFirstsBy+ --unionBy = BS.unionBy+ --intersectBy = BS.intersectBy+ groupBy f = fromList . BS.groupBy f+ --sortBy = BS.sortBy+ --insertBy = BS.insertBy+ genericLength = fromInteger . fromIntegral . BS.length+ genericTake i = BS.take (fromIntegral i)+ genericDrop i = BS.drop (fromIntegral i)+ genericSplitAt i = BS.splitAt (fromIntegral i)+ genericReplicate i = BS.replicate (fromIntegral i)++instance ListLikeIO BS.ByteString Word8 where+ hGetLine = BS.hGetLine+ hGetContents = BS.hGetContents+ hGet = BS.hGet+ hGetNonBlocking = BS.hGetNonBlocking+ hPutStr = BS.hPutStr+ hPutStrLn = BS.hPutStrLn+ getLine = BS.getLine+ getContents = BS.getContents+ putStr = BS.putStr+ putStrLn = BS.putStrLn+ interact = BS.interact+ readFile = BS.readFile+ writeFile = BS.writeFile+ appendFile = BS.appendFile++instance StringLike BS.ByteString where+ toString = map (toEnum . fromIntegral) . BS.unpack+ fromString = BS.pack . map (fromIntegral . fromEnum)++--------------------------------------------------+-- ByteString.Lazy++instance FoldableLL BSL.ByteString Word8 where+ foldl = BSL.foldl+ foldl' = BSL.foldl'+ foldl1 = BSL.foldl1+ foldr = BSL.foldr+ --foldr' = BSL.foldr'+ foldr1 = BSL.foldr1++mi64toi :: Maybe Int64 -> Maybe Int+mi64toi Nothing = Nothing+mi64toi (Just x) = Just (fromIntegral x)++instance ListLike BSL.ByteString Word8 where+ empty = BSL.empty+ singleton = BSL.singleton+ cons = BSL.cons+ snoc = BSL.snoc+ append = BSL.append+ head = BSL.head+ last = BSL.last+ tail = BSL.tail+ init = BSL.init+ null = BSL.null+ length = fromIntegral . BSL.length+ -- map = BSL.map+ rigidMap = BSL.map+ reverse = BSL.reverse+ --intersperse = BSL.intersperse+ concat = BSL.concat . toList+ --concatMap = BSL.concatMap+ rigidConcatMap = BSL.concatMap+ any = BSL.any+ all = BSL.all+ maximum = BSL.maximum+ minimum = BSL.minimum+ replicate i = BSL.replicate (fromIntegral i)+ take i = BSL.take (fromIntegral i)+ drop i = BSL.drop (fromIntegral i)+ splitAt i = BSL.splitAt (fromIntegral i)+ takeWhile = BSL.takeWhile+ dropWhile = BSL.dropWhile+ span = BSL.span+ break = BSL.break+ group = fromList . BSL.group+ inits = fromList . BSL.inits+ tails = fromList . BSL.tails+ isPrefixOf = BSL.isPrefixOf+ --isSuffixOf = BSL.isSuffixOf+ --isInfixOf = BSL.isInfixOf+ elem = BSL.elem+ notElem = BSL.notElem+ find = BSL.find+ filter = BSL.filter+ --partition = BSL.partition+ index l i = BSL.index l (fromIntegral i)+ elemIndex i = mi64toi . BSL.elemIndex i + --elemIndices x = fromList . L.map fromIntegral . BSL.elemIndices x+ findIndex f = mi64toi . BSL.findIndex f+ --findIndices x = fromList . L.map fromIntegral . BSL.findIndices x+ --sequence = BSL.sequence+ --mapM = BSL.mapM+ --mapM_ = BSL.mapM_+ --nub = BSL.nub+ --delete = BSL.delete+ --deleteFirsts = BSL.deleteFirsts+ --union = BSL.union+ --intersect = BSL.intersect+ --sort = BSL.sort+ --insert = BSL.insert+ toList = BSL.unpack+ fromList = BSL.pack+ fromListLike = fromList . toList+ --nubBy = BSL.nubBy+ --deleteBy = BSL.deleteBy+ --deleteFirstsBy = BSL.deleteFirstsBy+ --unionBy = BSL.unionBy+ --intersectBy = BSL.intersectBy+ -- BSL.groupBy is broken. groupBy f = fromList . BSL.groupBy f+ -- the below works on ghc but generates a type error on hugs+ -- groupBy func = map fromList . L.groupBy func . toList+ --sortBy = BSL.sortBy+ --insertBy = BSL.insertBy+ genericLength = fromInteger . fromIntegral . BSL.length+ genericTake i = BSL.take (fromIntegral i)+ genericDrop i = BSL.drop (fromIntegral i)+ genericSplitAt i = BSL.splitAt (fromIntegral i)+ genericReplicate i = BSL.replicate (fromIntegral i)++strict2lazy :: BS.ByteString -> IO BSL.ByteString+strict2lazy b = return (BSL.fromChunks [b])+instance ListLikeIO BSL.ByteString Word8 where+ hGetLine h = BS.hGetLine h >>= strict2lazy+ hGetContents = BSL.hGetContents+ hGet = BSL.hGet+ hGetNonBlocking = BSL.hGetNonBlocking+ hPutStr = BSL.hPut+ --hPutStrLn = BSL.hPutStrLn+ getLine = BS.getLine >>= strict2lazy+ getContents = BSL.getContents+ putStr = BSL.putStr+ putStrLn = BSL.putStrLn+ interact = BSL.interact+ readFile = BSL.readFile+ writeFile = BSL.writeFile+ appendFile = BSL.appendFile++instance StringLike BSL.ByteString where+ toString = map (toEnum . fromIntegral) . BSL.unpack+ fromString = BSL.pack . map (fromIntegral . fromEnum)++--------------------------------------------------+-- Map++instance (Ord key) => FoldableLL (Map.Map key val) (key, val) where+ foldr f start m = Map.foldWithKey func start m+ where func k v accum = f (k, v) accum+ foldl f start m = L.foldl f start (Map.toList m)++l2m :: (Ord k, Ord k2) => ([(k, v)], [(k2, v2)]) -> (Map.Map k v, Map.Map k2 v2)+l2m (l1, l2) = (Map.fromList l1, Map.fromList l2)+instance (Ord key, Eq val) => ListLike (Map.Map key val) (key, val) where+ empty = Map.empty+ singleton (k, v) = Map.singleton k v+ cons (k, v) m = Map.insert k v m+ snoc = flip cons+ append = Map.union+ head = Map.elemAt 0+ last m = Map.elemAt (Map.size m - 1) m+ -- was deleteAt 0, but that is broken in GHC 6.6+ tail = drop 1+ -- broken in GHC 6.6: init m = Map.deleteAt (Map.size m - 1) m+ init = Map.fromAscList . L.init . Map.toAscList+ null = Map.null+ length = Map.size+ map f = fromList . map f . Map.toList+ rigidMap f = Map.fromList . L.map f . Map.toList+ reverse = id+ intersperse i f+ | Map.size f <= 1 = f+ | otherwise = cons i f+ -- concat+ -- concatMap+ -- rigidConcatMap+ -- any+ -- all+ -- maximum+ -- minimum+ replicate = genericReplicate+ take n = Map.fromAscList . L.take n . Map.toAscList+ drop n = Map.fromAscList . L.drop n . Map.toAscList+ splitAt n = l2m . L.splitAt n . Map.toList+ takeWhile f = Map.fromAscList . L.takeWhile f . Map.toAscList+ dropWhile f = Map.fromAscList . L.dropWhile f . Map.toAscList+ span f = l2m . L.span f . Map.toList+ break f = span (not . f)+ group m+ | null m = empty+ | otherwise = cons (singleton (head m)) (group (tail m))+ -- group+ -- inits+ -- tails+ isPrefixOf f1 f2 = L.isPrefixOf (Map.toList f1) (Map.toList f2)+ isSuffixOf f1 f2 = L.isSuffixOf (Map.toList f1) (Map.toList f2)+ isInfixOf = Map.isSubmapOf+ --elem = Map.member+ --notElem = Map.notMember+ -- find+ filter f m = Map.filterWithKey func m+ where func k v = f (k, v)+ index = flip Map.elemAt+ elemIndex (k, v) m =+ case Map.lookupIndex k m of+ Nothing -> fail "elemIndex: no matching key"+ Just i -> if snd (Map.elemAt i m) == v+ then Just i+ else fail "elemIndex on Map: matched key but not value"+ elemIndices i m = + case elemIndex i m of+ Nothing -> empty+ Just x -> singleton x+ -- findIndex+ -- findIndices+ -- sequence+ -- mapM+ -- rigidMapM+ -- mapM_+ nub = id+ delete (k, v) m =+ case Map.lookup k m of+ Nothing -> m+ Just x -> if x == v+ then Map.delete k m+ else m+ union = Map.union+ -- intersect+ sort = id+ insert = cons+ toList = Map.toList+ fromList = Map.fromList+ nubBy func = Map.fromAscList . L.nubBy func . Map.toAscList+ --deleteBy+ deleteFirstsBy func m1 m2 = Map.fromAscList $ + L.deleteFirstsBy func (Map.toAscList m1)+ (Map.toAscList m2)+ --deleteFirstsBy+ unionBy func m1 m2 = Map.fromList $ + L.unionBy func (Map.toList m1) (Map.toList m2)+ --intersectBy+ --groupBy+ sortBy _ = id+ insertBy _ = insert+ genericLength = fromIntegral . Map.size+ genericTake n = Map.fromAscList . L.genericTake n . Map.toAscList+ genericDrop n = Map.fromAscList . L.genericDrop n . Map.toAscList+ genericSplitAt n = l2m . L.genericSplitAt n . Map.toList+ genericReplicate count item+ | count <= 0 = empty+ | otherwise = singleton item++--------------------------------------------------+-- Arrays++instance (Ix i) => FoldableLL (A.Array i e) e where+ foldl = F.foldl+ foldl1 = F.foldl1+ foldl' = F.foldl'+ foldr = F.foldr+ foldr1 = F.foldr1+ foldr' = F.foldr'++instance (Integral i, Ix i) => Monoid (A.Array i e) where+ mempty = A.listArray (0, -1) []+ mappend l1 l2 =+ A.array (blow, newbhigh)+ (A.assocs l1 ++ zip [(bhigh + 1)..newbhigh] (A.elems l2))+ where newlen = genericLength newelems+ newelems = A.elems l2+ newbhigh = bhigh + newlen+ (blow, bhigh) = A.bounds l1++instance (Integral i, Ix i) => ListLike (A.Array i e) e where+ empty = mempty+ singleton i = A.listArray (0, 0) [i]+ cons i l = + -- To add something to the beginning of an array, we must+ -- change the bounds and set the first element.+ (A.ixmap (blow - 1, bhigh) id l) // [(blow - 1, i)]+ where (blow, bhigh) = A.bounds l+ snoc l i = + -- Here we must change the bounds and set the last element+ (A.ixmap (blow, bhigh + 1) id l) // [(bhigh + 1, i)]+ where (blow, bhigh) = A.bounds l+ append = mappend+ head l = l ! (fst (A.bounds l))+ last l = l ! (snd (A.bounds l))+ tail l = A.array (blow + 1, bhigh) (tail (A.assocs l))+ where (blow, bhigh) = A.bounds l+ init l = A.array (blow, bhigh - 1) (init (A.assocs l))+ where (blow, bhigh) = A.bounds l+ null l = genericLength l == (0::Integer)+ length = genericLength+ -- map+ rigidMap = A.amap+ reverse l = A.listArray (A.bounds l) (L.reverse (A.elems l)) + -- intersperse+ -- concat+ -- concatMap+ -- rigidConcatMap+ any x = L.any x . A.elems+ all x = L.all x . A.elems+ maximum = L.maximum . A.elems+ minimum = L.minimum . A.elems+ replicate = genericReplicate+ take = genericTake+ drop = genericDrop+ -- splitAt+ -- takeWhile+ -- dropWhile+ -- span+ -- break+ -- group+ -- inits+ -- tails+ isPrefixOf l1 l2 = L.isPrefixOf (toList l1) (toList l2)+ isSuffixOf l1 l2 = L.isSuffixOf (toList l1) (toList l2)+ isInfixOf l1 l2 = L.isInfixOf (toList l1) (toList l2)+ elem i l = L.elem i (toList l)+ -- notElem+ filter f = fromList . L.filter f . toList+ -- partition+ index l i = l ! ((fromIntegral i) + offset)+ where offset = (fst $ A.bounds l)+ elemIndex i = L.elemIndex i . toList+ elemIndices i = fromList . L.elemIndices i . toList+ findIndex f = L.findIndex f . toList+ findIndices f = fromList . L.findIndices f . toList+ -- sequence = M.sequence . toList+ -- mapM f = M.mapM f . toList+ -- rigidMapM = mapM+ -- mapM_ f = M.mapM_ f . toList+ nub = fromList . L.nub . toList+ -- delete+ -- deleteFirsts+ -- union+ -- intersect+ sort l = A.listArray (A.bounds l) (L.sort (A.elems l))+ -- insert+ toList = A.elems+ fromList l = A.listArray (0, genericLength l - 1) l+ -- fromListLike+ nubBy f = fromList . L.nubBy f . toList+ -- deleteBy+ -- deleteFirstsBy+ -- unionBy+ -- intersectBy+ -- groupBy+ sortBy f l = A.listArray (A.bounds l) (L.sortBy f (A.elems l))+ -- insertBy+ genericLength l = fromIntegral (bhigh - blow + 1)+ where (blow, bhigh) = A.bounds l+ genericTake count l + | count > genericLength l = l+ | count <= 0 = empty+ | otherwise = A.listArray (blow, blow + (fromIntegral count) - 1)+ (L.genericTake count (A.elems l))+ where (blow, _) = A.bounds l+ genericDrop count l = A.listArray (blow + (fromIntegral count), bhigh)+ (L.genericDrop count (A.elems l))+ where (blow, bhigh) = A.bounds l+ -- geneicSplitAt+ genericReplicate count i = A.listArray (0, (fromIntegral count) - 1) + (L.genericReplicate count i)+++instance (Integral i, Ix i) => StringLike (A.Array i Char) where+ toString = toList+ fromString = fromList+ -- lines+ -- words++instance (Integral i, Ix i) => ListLikeIO (A.Array i Char) Char where+ hGetLine h = IO.hGetLine h >>= (return . fromList)+ hGetContents h = IO.hGetContents h >>= (return . fromList)+ hGet h i = ((hGet h i)::IO String) >>= (return . fromList)+ hGetNonBlocking h i = ((hGetNonBlocking h i):: IO String) >>= (return . fromList)+ hPutStr h = hPutStr h . toString+ hPutStrLn h = hPutStrLn h . toString+ getLine = IO.getLine >>= (return . fromString)+ getContents = IO.getContents >>= (return . fromString)+ putStr = IO.putStr . toString+ putStrLn = IO.putStrLn . toString+ -- interact+ -- readFile+ -- writeFile+ -- appendFile
+ src/Data/ListLike/String.hs view
@@ -0,0 +1,78 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++{- |+ Module : Data.ListLike.String+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++String-like functions++Written by John Goerzen, jgoerzen\@complete.org+-}++module Data.ListLike.String+ ( StringLike(..)+ )+ where+import Prelude hiding (length, head, last, null, tail, map, filter, concat, + any, lookup, init, all, foldl, foldr, foldl1, foldr1,+ maximum, minimum, iterate, span, break, takeWhile,+ dropWhile, reverse, zip, zipWith, sequence,+ sequence_, mapM, mapM_, concatMap, and, or, sum,+ product, repeat, replicate, cycle, take, drop,+ splitAt, elem, notElem, unzip, lines, words,+ unlines, unwords)+import qualified Data.List as L+import Data.ListLike.Base++{- | An extension to 'ListLike' for those data types that are similar+to a 'String'. Minimal complete definition is 'toString' and+'fromString'. -}+class StringLike s where+ {- | Converts the structure to a 'String' -}+ toString :: s -> String+ + {- | Converts a 'String' to a list -}+ fromString :: String -> s++ {- | Breaks a string into a list of strings -}+ lines :: (ListLike full s) => s -> full+ --lines = map fromString . L.lines . toString + lines = myLines++ {- | Breaks a string into a list of words -}+ words :: ListLike full s => s -> full+ words = myWords++ {- | Joins lines -}+ unlines :: ListLike full s => full -> s+ unlines = myUnlines++ {- | Joins words -}+ unwords :: ListLike full s => full -> s+ unwords = myUnwords++-- For some reason, Hugs required splitting these out into+-- separate functions.+myLines :: (StringLike s, ListLike full s) => s -> full+myLines = map fromString . L.lines . toString++myWords :: (StringLike s, ListLike full s) => s -> full+myWords = map fromString . L.words . toString++myUnlines :: (StringLike s, ListLike full s) => full -> s+myUnlines = fromString . L.unlines . map toString++myUnwords :: (StringLike s, ListLike full s) => full -> s+myUnwords = fromString . L.unwords . map toString
+ src/Data/ListLike/Utils.hs view
@@ -0,0 +1,63 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++{- |+ Module : Data.ListLike.Utils+ Copyright : Copyright (C) 2007 John Goerzen+ License : LGPL++ Maintainer : John Goerzen <jgoerzen@complete.org>+ Stability : provisional+ Portability: portable++Utilities for 'Data.ListLike.ListLike' and friends. More functions+similar to 'Data.List' but not part of the main typeclass.++Written by John Goerzen, jgoerzen\@complete.org+-}++module Data.ListLike.Utils+ (and, or, sum, product, zip, zipWith, unzip, sequence_+ ) where+import Prelude hiding (length, head, last, null, tail, map, filter, concat, + any, lookup, init, all, foldl, foldr, foldl1, foldr1,+ maximum, minimum, iterate, span, break, takeWhile,+ dropWhile, reverse, zip, zipWith, sequence,+ sequence_, mapM, mapM_, concatMap, and, or, sum,+ product, repeat, replicate, cycle, take, drop,+ splitAt, elem, notElem, unzip, lines, words,+ unlines, unwords)+import Data.ListLike.Base+import Data.ListLike.FoldableLL+import Data.Monoid++-- | Returns True if all elements are True+and :: ListLike full Bool => full -> Bool+and = all (== True)++-- | Returns True if any element is True+or :: ListLike full Bool => full -> Bool+or = any (== True)++-- | The sum of the list+sum :: (Num a, ListLike full a) => full -> a+sum = getSum . foldMap Sum++-- | The product of the list+product :: (Num a, ListLike full a) => full -> a+product = getProduct . foldMap Product++------------------------------ Zipping+-- zip, zipWith in Base+{- | Converts a list of pairs into two separate lists of elements -}+unzip :: (ListLike full (itema, itemb),+ ListLike ra itema,+ ListLike rb itemb) => full -> (ra, rb)+unzip inp = foldr convert (empty, empty) inp+ where convert (a, b) (as, bs) = ((cons a as), (cons b bs))
+ testsrc/runtests.hs view
@@ -0,0 +1,344 @@+{-+Copyright (C) 2007 John Goerzen <jgoerzen@complete.org>++All rights reserved.++For license and copyright information, see the file COPYRIGHT++-}++import Test.QuickCheck+import Test.QuickCheck.Batch+import qualified Data.ByteString as BS+import qualified Data.Array as A+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ListLike as LL+import qualified Data.Map as Map+import qualified Data.Array as A+import qualified Data.Foldable as F+import System.Random+import qualified Test.HUnit as HU+import System.IO+import Text.Printf+import Data.Word+import Data.List+import Data.Monoid+import TestInfrastructure+import Data.Foldable(foldr', fold, foldMap)+import System.Info+++-- prop_singleton :: (Eq i,LL.ListLike f i) => f -> i -> Bool+--prop_singleton :: (Eq i, LL.ListLike f i, Arbitrary f, Show f, Show i, Arbitrary i) => f -> i -> Bool+prop_singleton f x = (LL.toList $ asTypeOf (LL.singleton x) f) == [x]++prop_empty f = (LL.toList l == []) && (LL.null l) && (LL.length l == 0)+ where l = asTypeOf LL.empty f++prop_tofromlist f = + LL.toList f == l && + LL.length f == length l &&+ f == (LL.fromList . LL.toList $ f)+ where l = LL.toList f++prop_length f = LL.length f == length (LL.toList f)+prop_cons f i = llcmp (LL.cons i f) (i : (LL.toList f))+prop_append f1 f2 = llcmp (LL.append f1 f2) (LL.toList f1 ++ LL.toList f2)+prop_head f = not (LL.null f) ==> LL.head f == head (LL.toList f)+prop_last f = not (LL.null f) ==> LL.last f == last (LL.toList f)+prop_tail f = not (LL.null f) ==> llcmp (LL.tail f) (tail (LL.toList f))+prop_init f = not (LL.null f) ==> llcmp (LL.init f) (init (LL.toList f))+prop_null f = LL.null f == null (LL.toList f)+prop_length2 f = checkLengths f (LL.toList f)+prop_length3 f1 f2 = llcmp (LL.append f1 f2) (LL.toList f1 ++ LL.toList f2)++prop_map :: forall full item. (TestLL full item, TestLL [item] item) => full -> (item -> item) -> Result+prop_map f func = llcmp llmap (map func (LL.toList f))+ where llmap = asTypeOf (LL.map func f) (LL.toList f)++prop_rigidMap f func = llcmp (LL.rigidMap func f) (map func (LL.toList f))+prop_reverse f = llcmp (LL.reverse f) (reverse (LL.toList f))+prop_intersperse f i = llcmp (LL.intersperse i f) (intersperse i (LL.toList f))++prop_concat f = + llcmp (LL.concat f) (concat $ map LL.toList (LL.toList f))++prop_concatmap :: forall full item. (TestLL full item, TestLL [item] item) => full -> (item -> [item]) -> Result+prop_concatmap f func =+ llcmp (LL.concatMap func f)+ (concatMap func (LL.toList f))++prop_rigidConcatMap f func =+ llcmp (LL.rigidConcatMap func f)+ (concatMap (LL.toList . func) (LL.toList f))++prop_any f func = (LL.any func f) @?= (any func (LL.toList f))+prop_all f func = (LL.all func f) @?= (all func (LL.toList f))+prop_maximum f = not (LL.null f) ==> LL.maximum f @=? maximum (LL.toList f)+prop_minimum f = not (LL.null f) ==> LL.minimum f @=? minimum (LL.toList f)+prop_replicate f count i = + llcmp res (replicate count i)+ where res = asTypeOf (LL.replicate count i) f+prop_take f count = llcmp (LL.take count f) (take count (LL.toList f))+prop_drop f count = count >= 0 ==> llcmp (LL.drop count f) (drop count (LL.toList f))+prop_splitAt f count = count >= 0 ==>+ llcmp [(\(x, y) -> (LL.toList x, LL.toList y)) . LL.splitAt count $ f] + [LL.splitAt count (LL.toList f)]+prop_takeWhile f func = llcmp (LL.takeWhile func f) + (takeWhile func (LL.toList f))+prop_dropWhile f func = llcmp (LL.dropWhile func f) + (dropWhile func (LL.toList f))+prop_span f func = + llcmp [(\(x, y) -> (LL.toList x, LL.toList y)) . LL.span func $ f]+ [span func (LL.toList f)]+prop_break f func = + llcmp [(\(x, y) -> (LL.toList x, LL.toList y)) . LL.break func $ f]+ [break func (LL.toList f)]+prop_group f =+ -- llcmp (map LL.toList (LL.group f)) (group (LL.toList f))+ (map LL.toList (LL.group f)) @?= (group (LL.toList f))+prop_inits f = (map LL.toList (LL.inits f)) @?= (inits (LL.toList f))+prop_tails f = (map LL.toList (LL.tails f)) @?= (tails (LL.toList f))+prop_isPrefixOf f1 f2 = LL.isPrefixOf f1 f2 @?= + (isPrefixOf (LL.toList f1) (LL.toList f2))+prop_isSuffixOf f1 f2 = LL.isSuffixOf f1 f2 @?=+ (isSuffixOf (LL.toList f1) (LL.toList f2))+prop_isInfixOf f1 f2 = LL.isInfixOf f1 f2 @?=+ (isInfixOf (LL.toList f1) (LL.toList f2))+prop_elem f i = LL.elem i f @?= elem i (LL.toList f)+prop_notElem f i = LL.notElem i f @?= notElem i (LL.toList f)+prop_find f func = LL.find func f @?= find func (LL.toList f)+prop_filter f func = llcmp (LL.filter func f) (filter func (LL.toList f))+prop_partition f func = + (LL.toList f1, LL.toList f2) @?= partition func (LL.toList f)+ where (f1, f2) = LL.partition func f+prop_index f i = (i >= 0 && i < LL.length f) ==>+ (LL.index f i @?= ((LL.toList f) !! i))+prop_elemIndex f i = LL.elemIndex i f @?= elemIndex i (LL.toList f)+prop_elemIndices f i = LL.elemIndices i f @?= elemIndices i (LL.toList f)+prop_findIndex f func = LL.findIndex func f @?= findIndex func (LL.toList f)+prop_findIndices f func =+ LL.findIndices func f @?= findIndices func (LL.toList f)++prop_sequence f =+ case (llres, sequence testit) of+ (Just ll, Just l) -> llcmp ll l+ _ -> error "Error!"+ where testit = map Just (LL.toList f)+ llres = asTypeOf (LL.sequence testit) (Just f)++prop_mapM :: forall full item. (TestLL full item, TestLL [item] item) => full -> (item -> Maybe item) -> Result+prop_mapM f func = llmapM @?= (mapM func (LL.toList f))+ where llmapM = asTypeOf (LL.mapM func f) (Just (LL.toList f))++prop_rigidMapM :: forall full item. (TestLL full item, TestLL [item] item) => full -> (item -> Maybe item) -> Result+prop_rigidMapM f func = + case (LL.rigidMapM func f, mapM func (LL.toList f)) of+ (Just ll, Just l) -> llcmp ll l+ _ -> error "error in prop_rigidMapM"++-- FIXME: can we test mapM_?++prop_nub f = llcmp (LL.nub f) (nub (LL.toList f))+prop_delete f i = llcmp (LL.delete i f) (delete i (LL.toList f))+prop_deleteFirsts f1 f2 = llcmp (LL.deleteFirsts f1 f2) + ((LL.toList f1) \\ (LL.toList f2))+prop_union f1 f2 = llcmp (LL.union f1 f2) + (union (LL.toList f1) (LL.toList f2))+prop_intersect f1 f2 = llcmp (LL.intersect f1 f2) + (intersect (LL.toList f1) (LL.toList f2))+prop_sort f1 = llcmp (LL.sort f1) (sort (LL.toList f1))+prop_insert f i = llcmp (LL.insert i f) (insert i (LL.toList f))+prop_nubBy f func = llcmp (LL.nubBy func f) (nubBy func (LL.toList f))+prop_deleteBy f func i = llcmp (LL.deleteBy func i f) + (deleteBy func i (LL.toList f))+prop_deleteFirstsBy f1 f2 func = llcmp (LL.deleteFirstsBy func f1 f2)+ (deleteFirstsBy func (LL.toList f1) (LL.toList f2))+prop_unionBy f1 f2 func = llcmp (LL.unionBy func f1 f2)+ (unionBy func (LL.toList f1) (LL.toList f2))+prop_intersectBy f1 f2 func = llcmp (LL.intersectBy func f1 f2)+ (intersectBy func (LL.toList f1) (LL.toList f2))+prop_groupBy f func =+ (map LL.toList (LL.groupBy func f)) @?= (groupBy func (LL.toList f))+prop_sortBy1 f = llcmp (LL.sortBy compare f) (sortBy compare (LL.toList f))+prop_sortBy2 f = llcmp (LL.sortBy func f) (sortBy func (LL.toList f))+ where func x y = compare y x+prop_sortBy f func = llcmp (LL.sortBy func f) (sortBy func (LL.toList f))+prop_insertBy1 f i = llcmp (LL.insertBy compare i f)+ (insertBy compare i (LL.toList f))+prop_insertBy2 f i = llcmp (LL.insertBy func i f)+ (insertBy func i (LL.toList f))+ where func x y = compare y x+prop_genericLength f =+ LL.genericLength f @?= genericLength (LL.toList f)+prop_genericTake f (i::Integer) = (i >= 0) ==>+ llcmp (LL.genericTake i f) (genericTake i (LL.toList f))+prop_genericDrop f (i::Integer) = (i >= 0) ==>+ llcmp (LL.genericDrop i f) (genericDrop i (LL.toList f))+prop_genericSplitAt f (i::Integer) = i >= 0 ==>+ llcmp [(\(x, y) -> (LL.toList x, LL.toList y)) . LL.genericSplitAt i $ f]+ [LL.genericSplitAt i (LL.toList f)]+prop_genericReplicate f (count::Integer) i = count >= 0 ==>+ llcmp res (genericReplicate count i)+ where res = asTypeOf (LL.genericReplicate count i) f++--prop_zip :: (LL.ListLike full item, LL.ListLike result (item, Int)) =>+-- full -> Result+prop_zip f = LL.zip f f2 @?= zip (LL.toList f) f2+ where f2 = [(-5::Int)..]+prop_zipWith f = + LL.toList res @?= (zipWith func (LL.toList f) f2)+ where f2 = [(100::Int)..(-100)]+ func x y = (y + 5, x)+ res = asTypeOf (LL.zipWith func f f2) [(5::Int, LL.head f)]+--FIXME: prop_unzip +--FIXME: prop_and+--FIXME: prop_or+--FIXME: prop_sum+--FIXME: prop_product+prop_foldl f func (i::Int) = LL.foldl func i f @?= foldl func i (LL.toList f)+prop_foldl' f func (i::Integer) =+ LL.foldl' func i f @?= foldl' func i (LL.toList f)+prop_foldl1 f func = not (LL.null f) ==> + (LL.foldl1 func f) @?= (foldl1 func (LL.toList f))+prop_foldr f func (i::Int) = LL.foldr func i f @?= foldr func i (LL.toList f)+prop_foldr' f func (i::Integer) =+ LL.foldr' func i f @?= foldr' func i (LL.toList f)+prop_foldr1 f func = not (LL.null f) ==>+ LL.foldl1 func f @?= foldl1 func (LL.toList f)+prop_fold f = llcmp res resl+ where res = LL.fold f+ resl = fold (map LL.toList (LL.toList f))+prop_foldMap :: (LL.ListLike full item, Eq full) => full -> (item -> [Int]) -> Result+prop_foldMap f func = res @?= resl+ where res = LL.foldMap func f+ resl = foldMap func (LL.toList f) -- asTypeOf (foldMap (LL.toList f)) (head f)++prop_toString f =+ ((LL.fromString . LL.toString $ f) == f)+ where l = LL.toList f+prop_fromString f x = + LL.toString (asTypeOf (LL.fromString x) f) @?= x+prop_lines f = map LL.toString res @?= lines (LL.toString f)+ where res = asTypeOf (LL.lines f) [f]+prop_words f = map LL.toString res @?= words (LL.toString f)+ where res = asTypeOf (LL.words f) [f]++allt = [apf "empty" (t prop_empty),+ apf "length" (t prop_length),+ apf "to/fromList" (t prop_tofromlist),+ apf "singleton" (t prop_singleton),+ apf "cons" (t prop_cons),+ apf "append" (t prop_append),+ apf "head" (t prop_head),+ apf "last" (t prop_last),+ apf "tail" (t prop_tail),+ apf "init" (t prop_init),+ apf "null" (t prop_null),+ apf "length2" (t prop_length2),+ apf "length3" (t prop_length3),+ apf "map" (t prop_map),+ apf "rigidMap" (t prop_rigidMap),+ apf "reverse" (t prop_reverse),+ apf "intersperse" (t prop_intersperse),+ apw "concat" (LLWrap prop_concat),+ apf "concatMap" (t prop_concatmap),+ apf "rigidConcatMap" (t prop_rigidConcatMap),+ apf "any" (t prop_any),+ apf "all" (t prop_all),+ apf "maximum" (t prop_maximum),+ apf "minimum" (t prop_minimum),+ apf "replicate" (t prop_replicate),+ apf "take" (t prop_take),+ apf "drop" (t prop_drop),+ apf "splitAt" (t prop_splitAt),+ apf "takeWhile" (t prop_takeWhile),+ apf "dropWhile" (t prop_dropWhile),+ apf "span" (t prop_span),+ apf "break" (t prop_break),+ apf "group" (t prop_group),+ apf "inits" (t prop_inits),+ apf "tails" (t prop_tails),+ apf "isPrefixOf" (t prop_isPrefixOf),+ apf "isSuffixOf" (t prop_isSuffixOf),+ apf "isInfixOf" (t prop_isInfixOf),+ apf "elem" (t prop_elem),+ apf "notElem" (t prop_notElem),+ apf "find" (t prop_find),+ apf "filter" (t prop_filter),+ apf "partition" (t prop_partition),+ apf "index" (t prop_index),+ apf "elemIndex" (t prop_elemIndex),+ apf "elemIndices" (t prop_elemIndices),+ apf "findIndex" (t prop_findIndex),+ apf "findIndices" (t prop_findIndices),+ apf "sequence" (t prop_sequence),+ apf "mapM" (t prop_mapM),+ apf "rigidMapM" (t prop_rigidMapM),+ -- FIXME: mapM_ ?+ apf "nub" (t prop_nub),+ apf "delete" (t prop_delete),+ apf "deleteFirsts" (t prop_deleteFirsts),+ apf "union" (t prop_union),+ apf "intersect" (t prop_intersect),+ apf "sort" (t prop_sort),+ apf "insert" (t prop_insert),+ -- toList+ -- fromList+ -- fromListLike+ apf "nubBy" (t prop_nubBy),+ apf "deleteBy" (t prop_deleteBy),+ apf "deleteFirstsBy" (t prop_deleteFirstsBy),+ apf "unionBy" (t prop_unionBy),+ apf "intersectBy" (t prop_intersectBy),+ apf "groupBy" (t prop_groupBy),+ apf "sortBy1" (t prop_sortBy1),+ apf "sortBy2" (t prop_sortBy2),+ apf "insertBy1" (t prop_insertBy1),+ apf "insertBy2" (t prop_insertBy2),+ apf "genericLength" (t prop_genericLength),+ apf "genericTake" (t prop_genericTake),+ apf "genericDrop" (t prop_genericDrop),+ apf "genericSplitAt" (t prop_genericSplitAt),+ apf "genericReplicate" (t prop_genericReplicate),+ apf "zip" (t prop_zip),+ apf "zipWith" (t prop_zipWith) + -- apf "unzip" (t prop_unzip),+ -- apf "and" (t prop_and),+ -- apf "or" (t prop_or),+ -- apf "sum" (t prop_sum),+ -- apf "propduct" (t prop_product),+ -- sequence_ + ]++allf = (if compilerName == "hugs" then [] else [ apf "foldl" (t prop_foldl),+ apf "foldr1" (t prop_foldr1),+ apf "foldl1" (t prop_foldl1)])+ +++ [+ apf "foldl'" (t prop_foldl'),+ apf "foldr" (t prop_foldr),+ apf "foldr'" (t prop_foldr'),+ apw "fold" (LLWrap prop_fold),+ apf "foldMap" (t prop_foldMap) + ]++alls = [+ aps "toString" (t prop_toString),+ aps "fromString" (t prop_fromString),+ aps "lines" (t prop_lines),+ aps "words" (t prop_words) + -- FIXME: aps (t prop_unlines),+ -- FIXME: aps (t prop_unwords)+ ]+allTests = HU.TestList $ reverse $+ [HU.TestLabel "ListLike" (HU.TestList allt),+ HU.TestLabel "FoldableLL" (HU.TestList allf),+ HU.TestLabel "StringLike" (HU.TestList alls)]++testh = HU.runTestTT $ allTests+testv = runVerbTestText (HU.putTextToHandle stderr True) $ allTests+ +main = + do testv+ return ()