packages feed

ranged-list (empty) → 0.1.0.0

raw patch · 22 files changed

+3608/−0 lines, 22 filesdep +basedep +doctestdep +ranged-listsetup-changed

Dependencies added: base, doctest, ranged-list, typecheck-plugin-nat-simple

Files

+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for ranged-list++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Yoshikuni Jujo (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Yoshikuni Jujo nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,885 @@+# ranged-list++## What's this++This package provides lists whose lengths are determined by the type and+lists whose ranges of lengths are determined by the type.++```haskell+sample1 :: LengthL 3 Integer+sample1 = 1 :. 2 :. 3 :. NilL++sample2 :: LengthR 3 Integer+sample2 = NilR :+ 1 :+ 2 :+ 3++sample3 :: RangeL 2 5 Integer+sample3 = 1 :. 2 :. 3 :.. 4 :.. NilL++sample4 :: RangeR 2 5 Integer+sample4 = NilR :++ 1 :++ 2 :+ 3 :+ 4+```++`LengthL 3 Integer` and `LengthR 3 Integer` are lists who have just 3 `Integer`.+`RangeL 2 5 Integer` and `RangeR 2 5 Integer` are lists whose element numbers+are 2 at minimum and 5 at maximum.+`LengthL 3 Integer` and `RangeL 2 5 Integer` are+pushed or poped a element from left.+`LengthR 3 Integer` and `RangeR 2 5 Integer` are+pushed or poped a element from right.++## Motivation++Suppose you want to take elements from list. You can use `take` like following.++```+xs = take 3 "Hello, world!"+```++The length of `xs` is lesser or equal `3`.+But you cannot use this knowledge when you write next code.+You should check the argument of a next function.++```haskell+fun :: [Char] -> ...+fun [] = ...+fun [x] = ...+fun [x, y] = ...+fun [x, y, z] = ...+fun _ = error "bad argument"+```+If you use `LengthL 3 Char`,+you don't need to mind the argument has more than 3 elements.++```haskell+fun :: LengthL 3 Char -> ...+fun (x :. y :. z :. NilL) = ...+```++## LengthL++### To make rectangles from a number list++Suppose you want to make a value which represent a rectangle.+You have a number list.+The numbers are a left border, a top border, a width and a height of+a rectangle in order.+The numbers of the first rectangle are followed by+the numbers of a second rectangle,+and the numbers of the second rectangle are followed by+the numbers of a third rectangle,+and so on.++```+[left1, top1, width1, height1, left2, top2, width2, height2, left3, ...]+```++The list of numbers defined above are covert to a following list.++```+[Rect left1 top1 width1 height1, Rect left2 top2 width2 height2, Rect left3 ...]+```++The code is following. (View `sample/rectangle.hs`)++```haskell:sample/rectangle.hs+import Data.Length.Length++data Rect = Rect {+	left :: Double, top :: Double,+	width :: Double, height :: Double } derivins Show++makeRect :: Length 4 Double -> Rect+makeRect (l :. t :. w :. h :. NilL) = Rect l t w h++main :: IO ()+main = print $ map makeRect . fst $ chunksL [3, 5, 15, 2, 8, 4, 1, 9, 3, 5]+```++The function `chunksL` return a value of type `([LengthL n a], RangeL 0 (n - 1) a)`.+The first value of this tuple is a list of `n` elements of type `a`.+And the second value of this tuple is rest elements.+The number of the rest elements is `0` at minimum and `n - 1` at maximum.++Try running.++```+% stack ghc sample/rectangle.hs+% ./sample/rectangle+[Rect {left = 3.0, top = 5.0, width = 15.0, height = 2.0},+Rect {left = 8.0, top = 4.0, width = 1.0, height = 9.0)}+```++### To take Word64 from bit list++Let's define function to take a 64 bit word from bit list. (View `sample/word64.hs`)+The language extensions and the import list are following.++```haskell:sample/word64.hs+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE DAtaKinds, TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++import GHC.TypeNats+import Data.Foldable+import Data.List.Length+import Data.List.Range+import Data.Bits+import Data.Word+import Numeric+```++You define function `takeL` to take `n` elements from list.++```haskell:sample/word64.hs+takeL :: (LoosenLMax 0 (n - 1) n, Unfoldr 0 n n, ListToLengthL n) =>+	a -> [a] -> LengthL n a+takeL d = either ((`fillL` d) . loosenLMax) fst . splitL+```++The function `splitL` split a list and get n element lengthed list (`LengthL n a`) and a rest of the list.+If the list does not contain enough elements, then it returns a left value. It is a list of type `RangeL 0 (n - 1) a`.+The function `loosenLMax` convert the type `RangeL 0 (n - 1)` into `RangeL 0 n`.+And the function `fillL` fill the list with default value `d` to get a list `LengthL n a`.+Try it.++```+% stack ghci sample/word64.hs+> :set -XDataKinds+> takeL '@' "Hello, world!" :: LengthL 5 Char+'H' :. ('e' :. ('l' :. ('l' :. ('o' :. NilL))))+> takeL 'W' "Hi!" :: LengthL 5 Char+'H' :. ('i' :. ('!' :. ('@' :. ('@' :. NilL))))+```++You define data type which represent a bit as follow.++```haskell:sample/word64.hs+data Bit = O | I deriving Show++boolToBit :: Bool -> Bit+boolToBit = \case False -> O; True -> I++bitToNum63 :: (Num n, Bits n) => Bit -> n+bitToNum63 = \case O -> 0; I -> 1 `shiftL` 63+```++`O` is 0 and `I` is 1.+Function `boolToBit` converts a value of `Bool` into a value of `Bit`.+Function `bitToNum63` converts a value of `Bit` into a number.+It converte the bit as a 63rd bit.++You define the function which convert a bit list into 64 bit word.++```haskell:sample/word64.hs+bitsToWord64 :: LengthL 64 Bit -> Word64+bitsToWord64 = foldl' (\w b -> w `shiftR` 1 .|. bitToNum63 b) 0+```++It gets a bit from the left end.+It put the bit on a 63rd position of a 64 bit word.+Then it gets a next bit.+It shifts 64 bit word to the right.+And it put the bit on a 63rd position of a 64 bit word.+It continue in the same way.++You define the function which take 64 bit word from a bit list expressed+as string.++```haskell:sample/word64.hs+takeWord64 :: String -> Word64+takeWord64 = bitsToWord64 . takeL O . (boolToBit . (== '*') <$>)+```++The argument of this function is a string.+The string represent a bit sequence.+Character \'\*\' is 1 and character \'.\' is 0.++You define sample string and try it in function `main`.++```haskell:sample/word64.hs+sample1, sample2 :: String+sample1 = "...*..*..*...........*...**********...*************............******"+sample2 = "...*..*..*...........*.."++main :: IO ()+main = do+	putStrLn $ takeWord64 sample1 `showHex` ""+	putStrLn $ takeWord64 sample2 `showHex` ""+```++Try it.++```+% stack ghc sample/word64.hs+% ./sample/word64+8007ffc7fe200248+200248+```++## LengthR++### To push and pop from right++A value of the type `LengthR n a` is a list of values of the type `a`.+The length of the list is `n`.+And you can push and pop an element from right.+Try it. (view `sample/LengthR.hs`)++```haskell:sample/LengthR.hs+{-# LANGUAGE DataKinds #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module LengthR where++import Data.List.Length++hello :: LengthR 5 Char+hello = NilR :+ 'h' :+ 'e' :+ 'l' :+ 'l' :+ 'o'+```++The value `hello` is a list of characters which length is `5`.+Let\'s push the character `'!'` from right.++```+% stack ghci sample/LengthR.hs+> hello+((((NilR :+ 'h') :+ 'e') :+ 'l') :+ 'l') :+ 'o'+> hello :+ '!'+(((((NilR :+ 'h') :+ 'e') :+ 'l') :+ 'l') :+ 'o') :+ '!'+```++### To show 4 points of rectangles++#### function `fourPoints` and headers++You want to calculate four points of rectangle+from the left-top point, width and height of the rectangle.+You define function `fourPoints`. (View `sample/fourPointsOfRect.hs`)++```haskell:sample/fourPointsOfRect.hs+fourPoints :: LengthR 4 Double -> LengthR 4 (Double, Double)+fourPoints (NilR :+ l :+ t :+ w :+ h) =+	NilR :+ (l, t) :+ (l + w, t) :+ (l, t + h) :+ (l + w, t + h)+```++You add language extensions and modules to import.++```haskell:sample/fourPointsOfRect.hs+{-# LANGUAGE BlockArguments, LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++import GHC.TypeNats+import Control.Monad.Fix+import Control.Monad.Catch+import Data.List.Length+import Text.Read+```++Try it.++```+% stack ghci sample/fourPointsOfRect.hs+> fourPoints $ NilR :+ 300 :+ 200 :+ 50 :+ 30+(((NilR :+ (300.0,200.0)) :+ (350.0,200.0)) :+ (300.0,230.0)) :+ (350.0,230.0)+```++#### to input values interactively++You want to input values of a left bound, a top bound, a width and a height+interactively.+You want to delete the last value and reinput a new value.+First of all, you define two data type,+`DeleteOr a` and `NothingToDeleteException`.++```haskell:sample/fourPointsOfRect.hs+data DeleteOr a = Delete | Value a deriving Show+data NothingToDeleteException = NothingToDeleteException deriving Show+instance Exception NothingToDeleteException+```++And you define the function `getElems` as a class function.++```haskell:sample/fourPointsOfRect.hs+class GetElems n v where+	getElems :: MonadThrow m =>+		LengthR n a -> m (Maybe (DeleteOr a)) -> m (LengthR (n + v) a)++instance GetElems 0 0 where getElems NilR _ = pure NilR++instance {-# OVERLAPPABLE #-} 1 <= n => GetElems n 0 where+	getElems xs@(_ :+ _) _ = pure xs++instance {-# OVERLAPPABLE #-} GetElems 1 (v - 1) => GetElems 0 v where+	getElems NilR gt = gt >>= \case+		Nothing -> getElems NilR gt+		Just Delete -> throwM NothingToDeleteException+		Just (Value x) -> getElem @1 @(v - 1) (NilR :+ x) gt++instance {-# OVERLAPPABLE #-}+	(1 <= n, GetElems (n - 1) (v + 1), GetElems (n + 1) (v - 1)) =>+	GetElems n v where+	getElems xa@(xs :+ _) gt = gt >>= \case+		Nothing -> getElems xa gt+		Just Delete -> getElems @(n - 1) @(v + 1) xs gt+		Just (Value x) -> getElems @(n + 1) @(v - 1) (xa :+ x) gt+```++##### class GetElems n v++The class function `getElems` has two arguments.+The first argument is a list of values which are already inputed.+The second argument is a monad which returns 3 kinds of values,+a value which represents to delete, a new value to push to the list+or a value which represents to do nothing.++##### instance GetElems 0 0++`n == 0` and `v == 0` means that the function `getElems` get+ a list of no elements and return a list of no elements.++##### instance GetElems n 0++`v == 0` means that the function `getElems` get a list and+return the list as it is.++##### instance GetElems 0 v++`n == 0` means that there are no already inputed elements.+The monad returns 3 kind of values.+If it returns `Nothing`, then it rerun the whole as `getElems NilR gt`.+If it returns `Just Delete`, then `NothingToDeleteException` occurs.+If it returns `Just (Value x)`,+then it set the already-inputed elements to `NilR :+ x` and rerun the whole.++##### instance GetElems n v++The monad `gt` returns 3 kind of values.+If it returns `Nothing`, then rerun the whole as `getElems xa gt`.+If it returns `Just Delete`,+then it remove an element from the already-inputed list+and rerun the whole.+If it returns `Just (Value x)`,+then it set the already-inputed elements to `xa :+ x` and rerun the whole.++##### to try it++Try it.++```+% stack ghci sample/fourPointsOfRect.hs+> :set -XDataKinds -XBlockArguments -XLambdaCase+> getElems NilR (Just . Value <$> getLine) :: IO (LengthR 3 String)+foo+bar+baz+((NilR :+ "foo") :+ "bar") :+ "baz"+> gt = (<$> getLine) \case "" -> Nothing; "d' -> Just Delete; s -> Just (Value s)+> getElems NilR gt :: IO (LengthR 3 String)+foo+bar+d+boo++baz+((NilR :+ "foo") :+ "boo") :+ "baz"+> getElems NilR gt :: IO (LengthR 3 String)+foo+bar+d+d+hoge+piyo+baz+((NilR :+ "hoge") :+ "piyo") :+ "baz"+> getElems NilR gt :: IO (LengthR 3 String)+foo+bar+d+d+d+*** Exception: NothingToDeleteException+```++### function `titles`++You define the function `titles` which show values as string with title.++```haskell:sample/fourPointsOfRect.hs+titles :: (Show a, Applicative (LengthR n)) =>+	Int -> LengthR n String -> LengthR n a -> LengthR n String+titles n ts xs = (\t x -> t ++ replicate (n - length t) ' ' ++ ": " ++ show x)+	<$> ts <*> xs+```++Try it.++```+% stack ghci sample/fourPointsOfRect.hs+> titles 5 (NilR :+ "foo" :+ "bar" :+ "baz") (NilR :+ 123 :+ 456 :+ 789)+((NilR :+ "foo  : 123") :+ "bar  : 456") :+ "baz  : 789"+```++### function `printResult`++You define the function `printResult` which show values expressing a rectangle+and 4 points of rectangle.++```haskell:sample/fourPointsOfRect.hs+printResult :: LengthR 4 Double -> IO ()+printResult r = do+	putStrLn ""+	putStrLn `mapM_` titles 6 t r; putStrLn ""+	putStrLn `mapM_` titles 12 u (fourPoints r); putStrLn ""+	where+	t = NilR :+ "left :+ "top" :+ "width" :+ "height"+	u = NIlR :+ "left-top" :+ "right-top" :+ "left-bottom" :+ "right-bottom"+```++Try it.++```+% stack ghci sample/fourPointsOfRect.hs+> printResult $ NilR :+ 300 :+ 200 :+ 70 :+ 50++left  : 300.0+top   : 200.0+width : 70.0+height: 50.0++left-top    : (300.0,200.0)+right-top   : (370.0,200.0)+left-bottom : (300.0,250.0)+right-bottom: (370.0,250.0)+```++### function `getRect`++You define the function `getRect` which gets user input to make rectangle.++```haskell:sample/fourPointsOfRect.hs+getRect :: forall n . GetElems n (4 - n) =>+	LengthR n Double -> IO (LengthR 4 Double)+getRect xs = (<$) <$> id <*> printRect =<<+	getElems @n @(4 - n) xs ((<$> getLine) \case+		"d" -> Just Delete; l -> Value <*> readMaybe l)+	`catch`+	\(_ :: NothingToDeleteException) ->+		putStrLn *** Nothing to delete." >> getRect @0 NilR+```++It gets a user input with `getLine`.+If it is `"d"`, then it deletes the last input.+If there are nothing to delete, then `NothingToDeleteException` occur.+It catches this exception and shows error message and rerun `getRect`.++### function `main`++You define function `main`.++```haskell:sample/fourPointsOfRect.hs+main :: IO ()+main = getRect NilR >>= fix \go xa@(xs :+ _) -> getLine >>= \case+	"q" -> pure ()+	"d" -> go =<< getRect xs+	_ -> putStrLn "q or d" >> go xa+```++It call function `getRect` with list of `0` elements (`NilR`).+And it repeats function `getRect` with list of `4 - 1` elements (`xs`)+if you input `"d"`.++```+% stack ghc sample/fourPointsOfRect.hs+% ./sample/fourPointsOfRect+500+300+75+50++left  : 500.0+top   : 300.0+width : 75.0+height: 50.0++left-top    : (500.0,300.0)+right-top   : (575.0,300.0)+left-bottom : (500.0,350.0)+right-bottom: (575.0,350.0)++d+d+125+100++left  : 500.0+top   : 300.0+width : 125.0+height: 100.0++left-top    : (500.0,300.0)+right-top   : (625.0,300.0)+left-bottom : (500.0,400.0)+right-bottom: (625.0,400.0)++d+d+d+d+d+*** Nothing to delete.+2000+1500+90+50++left  : 2000.0+top   : 1500.0+width : 90.0+height: 50.0++left-top    : (2000.0,1500.0)+right-top   : (2090.0,1500.0)+left-bottom : (2000.0,1550.0)+right-bottom: (2090.0,1550.0)++q+```++## RangeL and RangeR++### To specify the range of a number of elements of a list++You can specify the range of a number of elements of a list.+There is a data type `RangeL n m a`.+It represents a list which have a type `a` element.+And its length is `n` at minimum and `m` at maximum.++```+% stack ghci+> :module Data.List.Range+> :set -XDataKinds+> 'h' :. 'e' :. 'l' :. 'l' :.. 'o' :.. NilL :: RangeL 3 8 Char+'h' :. ('e' :. ('l' :. ('l' :.. ('o' :.. NilL))))+```++### To get passwords++Suppose you want to get a password+whose length is 8 at minimum and 127 at maximum.+First of all, you define headers.++```haskell:sample/password.hs+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++import Data.List.Range+import System.IO++import qualified Data.ByteString.Char8 as BSC+```++You define `type Password`.++```haskell:sample/password.hs+type Password = RangeL 8 127 Char+```++It is a list of `Char`.+Its length is 8 at minimum and 127 at maximum.++You define a function `getRangedString`.+It recieves a user input.+It return a just value if the length of the input is within range.+It return a nothing value if the length of the input is out of range.++```haskell:sample/password.hs+getRangedPassword :: Unfoldr 0 n m => IO (Maybe (RangeL n m Char))+getRangedPassword = do+	e <- hGetEcho stdin+	hSetEcho stdin False+	unfoldrMRangeMaybe ((/= '\n') <$> hLookAhead stdin) getChar+		<* hSetEcho stdin e+```++It makes echo of stdin off.+It gets characters until you input `'\n'`.+And it makes echo of stdin on.++```+% stack ghci sample/password.hs+> :set -XDataKinds+> getRangedPassword :: IO (Maybe Password)+(Input "foobarbaz")+Just ('f' :. ('o' :. ('o' :. ('b' :. ('a' :. ('r' :. ('b' :. ('a' :. ('z' :..NilL)))))))))+> getRangedPassword :: IO (Maybe Password)+(Input "foo")+Nothing+> getRangedPassword :: IO (Maybe (RangeL 2 5 Char))+(Input "foobar")+Nothing+> r+```++You want to convert a value of type `Password` into a value of `ByteString`.+You can use other packages if you get password as a value of `ByteString`.++```haskell:sample/password.hs+passwordToByteString :: Password -> BSC.ByteString+passwordToByteString = foldr BSC.cons ""+```++You define function `main` to try it.++```haskell:sample/password.hs+main :: IO ()+main = do+	p <- getRangedPassword+	print p+	maybe (eror "bad password length") BSC.putStrLn $ passwordToByteString <$> p+```++Try it.++```+% stack ghc sample/password.hs+% ./sample/password+(Input "foobarbaz")+Just ('f' :. ('o' :. ('o' :. ('b' :. ('a' :. ('r' :. ('b' :. ('a' :. ('z' :.. NilL)))))))))+foobarbaz+```++### Finger Tree++The next example is Finger Tree.++[Finger Trees: A Simple General-purpose Data Structure](https://www.staff.city.ac.uk/~ross/papers/FingerTree.html)++#### Language Extension and Import List++Let's make headers.++```haskell:sample/fingertree.hs+{-# LANGUAGE ScopedTypeVariables, TypeApplications, InstanceSigs #-}+{-# LANGUAGE DataKinds, TypeOperators #-}You+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++import GHC.TypeNats+import Data.List.Range+```++#### Types++You can describe Finger Tree as follows.++```haskell:sample/fingertree.hs+data FingerTree a+	= Enpty | Single a+	| Deep (DigitL a) (FingerTree (Node a)) (DigitR a)+	deriving Show++type Node = RangeL 2 3+type DigitL = RangeL 1 4+type DigitR = RangeR 1 4+```++A list of type `Node a` contains two or three elements of type `a`.+A list of type `DigitL a` contains one elements at minimum and+four elements at maximum.+A list of type `DigitR a` contains the same number of elements as `DigitL a`.+But you can push and pop a element from right.++#### To push from left++You define the function which Add a new element to the left of the sequence.+First of all you define the function to push an element to a list of type `DigitL a`.++```haskell:sample/fingertree.hs+infixr 5 <||++(<||) :: a -> DigitL a -> Either (DigitL a) (DigitL a, Node a)+a <|| b :. NilL = Left $ a :. b :.. NilL+a <|| b :. c :.. NilL = Left $ a :. b :.. c :.. NilL+a <|| b :. c :.. d :.. NilL = Left $ a :. b :.. c :.. d :.. NilL+a <|| b :. c :.. d :.. e :.. NilL =+	Right (a :. b :.. NilL, c :. d :. e :.. NilL)+```++If the original list has fewer elements than four,+then it return a left value list which contains the added value.+If the original list has just four elements,+then it returns a right value tuple which contain the value of type `DigitL a`+and the value of type `Node a`.++You can define the function which add a new element to the left of the sequence.++```haskell:sample/fingertree.hs+infixr 5 <|++(<|) :: a -> FingerTree a -> FingerTree a+a <| Empty = Single a+a <| Single a = Deep (a :. NilL) Empty (NilR :+ b)+a <| Deep pr m sf = case a <|| pr of+	Left pr' -> Deep pr' m sf+	Right (pr', n3) -> Deep pr' (n3 <| m) sf+```++It pushes three of the elements as a `Node`, leaving two behind.++You also require the liftings of `<|`.++```haskell:sample/fingertree.hs+infixr 5 <|.++(<|.) :: Foldable t => t a -> FingerTree a -> FingerTree a+(<|.) = flip $ foldr (<|)+```++To make finger tree from a list or other foldable structure,+you define a function `toTree`.++```haskell:sample/fingertree.hs+toTree :: Foldable t => t a -> FingerTree a+toTree = (<|. Empty)+```++#### To push from right++Adding to the right end of the sequence is the mirror image of the above.++```haskell:sample/fingertree.hs+infixl 5 ||>, |>, |>.++(||>) :: DigitR a -> a -> Either (DigitR a) (Node a, DigitR a)+NilR :+ a ||> b = Left $ NilR :++ a :+ b+NilR :++ a :+ b ||> c = Left $ NilR :++ a :++ b :+ c+NIlR :++ a :++ b :+ c ||> d = Left $ NilR :++ a :++ b :++ c :+ d+NilR :++ a :++ b :++ c :+ d ||> e =+	Right (a :. b :. c :.. NilL, NilR :++ d :+ e)++(|>) :: FingerTree a -> a -> FingerTree a+Empty |> a = Single a+Single a |> b = Deep (a :. NilL) Empty (NilR :+ b)+Deep pr m sf |> a = case sf ||> a of+	Left sf' -> Deep pr m sf'+	Right (n3, sf') -> Deep pr (m |> n3) sf'++(|>.) :: Foldable t => FingerTree a -> t a -> FingerTree a+(|>.) = foldl (|>)+```++#### To pop from left++To deconstruct a sequence, you define a function `uncons`.++```haskell:sample/fingertree.hs+uncons :: FingerTree a -> Maybe (a, FingerTree a)+uncons Empty = Nothing+uncons (Single x) = Just (x, Empty)+uncons (Deep (a :. pr') m sf) = Just (a, deepL pr' m sf)++deepL :: RangeL 0 3 a -> FingerTree (Node a) -> DigitR a -> FingerTree a+deepL NilL m sf = case uncons m of+	Nothing -> toTree sf+	Just (n, m') -> Deep (loosenL n) m' sf+deepL (a :.. pr) m sf = Deep (loosenL $ a :. pr) m sf+```++Since the prefix `pr` of a `Deep` tree contains at least one element,+you can get its head.+However, the tail of the prefix may be empty,+and thus unsuitable as a first argument to the Deep constructor.+Hence you define a smart constructor that differs from `Deep` by allowing the+prefix to contain zero to three elements,+and in the empty case uses a `uncons` of the middle tree to construct a tree of+the correct shape.++#### Concatenation++First of all you define a function which devide a list into a list of `Node`.+The original list has 3 elements at minimum and 12 elements at maximum.+The returned list has 1 node at minimum and 4 nodes at maximum.+The function has a type like the following.++```haskell+fun :: RangeL 3 12 a -> RangeL 1 4 (Node a)+```++You can define a more general function like the following.++```haskell+fun :: RangeL 3 m a -> RangeL 1 w (Node a)+```++`m` is 3 times `w`.++You define a class.++```haskell:sample/fingertree.hs+class Nodes m w where nodes :: RangeL 3 m a -> RangeL 1 w (Node a)+```++And you define instance when `m` is 3 and `w` is 1.++```haskell:sample/fingertree.hs+instance Nodes 3 1 where nodes = (:. NilL) . loosenL	+```++And you define instance of general case.++```haskell:sample/fingertree.hs+instance {-# OVERLAPPABLE #-} (2 <= w, Nodes (m - 3) (w - 1)) => Nodes m w where+	nodes :: forall a . RangeL 3 m a -> RangeL 1 w (Node a)+	nodes (a :. b :. c :. NilL) = (a :. b :. c :.. NilL) :. NilL+	nodes (a :. b :. c :. d :.. NilL) =+		(a :. b :. NilL) :. (c :. d :. NilL) :.. NilL+	nodes (a :. b :. c :. d :.. e :.. NilL) =+		(a :. b :. c :.. NilL) :. (d :. e :. NilL) :.. NilL+	nodes (a :. b :. c :. d :.. e :.. f :.. xs) =+		(a :. b :. c :.. NilL) .:..+			nodes @(m - 3) @(w - 1) (d :. e :. f :. xs)+```++Try it.++```+% stack ghci sample/fingertree.hs+> :set -XTypeApplications -XDataKinds+> xs = 1 :. 2 :. 3 :. 4 :.. 5 :.. 6 :.. 7 :.. 8 :.. NilL :: RangeL 3 12 Integer+> nodes @12 @4 xs+(1 :. (2 :. (3 :.. NilL))) :. ((4 :. (5 :. (6 :.. NilL))) :.. ((7 :. (8 :. NilL)) :.. NilL))+> :type it+it :: Num a => RangeL 1 4 (Node a)+```++You can combine the two digit argument into a list of Nodes+with the function `nodes`.+You can obtain a recursive function by+generalizing the concatenation function to take an additional list of elements.++```haskell:sample/fingertree.hs+app3 :: FingerTree a -> RangeL 1 4 a -> FingerTree a -> FingerTree a+app3 Empty m xs = m <|. xs+app3 xs m Empty = xs |>. m+app3 (Single x) m xs = x <| m <|. xs+app3 xs m (Single x) = xs |>. m |> x+app3 (Deep pr1 m1 sf1) m (Deep pr2 m2 sf2) =+	Deep pr1 (app3 m1 (nodes $ sf1 ++.. m ++. pr2) m2) sf2+```++To concatenate two finger trees, you take a head element from a second sequence.++```haskell:sample/fingertree.hs+(><) :: FingerTree a -> FingerTree a -> FingerTree a+l >< r = case uncons r of Nothing -> l; Just (x, r') -> app3 l (x :. NilL) r'+```
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ranged-list.cabal view
@@ -0,0 +1,85 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 42c7def6fb4ed75b8b978a1de4cdf116653323fb1cee0e251bceaa00ef7be780++name:           ranged-list+version:        0.1.0.0+synopsis:       The list like structure whose length or range of length can be specified+description:    Please see the README on GitHub at <https://github.com/YoshikuniJujo/ranged-list#readme>+category:       List+homepage:       https://github.com/YoshikuniJujo/ranged-list#readme+bug-reports:    https://github.com/YoshikuniJujo/ranged-list/issues+author:         Yoshikuni Jujo+maintainer:     PAF01143@nifty.ne.jp+copyright:      Yoshikuni Jujo+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md+data-files:+    rectangle.hs+    word64.hs+    LengthR.hs+    fourPointsOfRect.hs+    password.hs+    fingertree.hs+data-dir:       sample++source-repository head+  type: git+  location: https://github.com/YoshikuniJujo/ranged-list++library+  exposed-modules:+      Data.List.Length+      Data.List.Range+      Data.List.Range.Nat+  other-modules:+      Control.Monad.Identity+      Control.Monad.State+      Data.List.Length.LengthL+      Data.List.Length.LengthR+      Data.List.Range.RangeL+      Data.List.Range.RangeR+      Paths_ranged_list+  hs-source-dirs:+      src+  build-depends:+      base >=4.7 && <5+    , typecheck-plugin-nat-simple+  default-language: Haskell2010++test-suite ranged-list-doctest+  type: exitcode-stdio-1.0+  main-is: doctests.hs+  other-modules:+      Paths_ranged_list+  hs-source-dirs:+      test+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , doctest+    , ranged-list+    , typecheck-plugin-nat-simple+  default-language: Haskell2010++test-suite ranged-list-test+  type: exitcode-stdio-1.0+  main-is: spec.hs+  other-modules:+      Paths_ranged_list+  hs-source-dirs:+      test+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , ranged-list+    , typecheck-plugin-nat-simple+  default-language: Haskell2010
+ sample/LengthR.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE DataKinds #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module LengthR where++import Data.List.Length++hello :: LengthR 5 Char+hello = NilR :+ 'h' :+ 'e' :+ 'l' :+ 'l' :+ 'o'
+ sample/fingertree.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE ScopedTypeVariables, TypeApplications, InstanceSigs #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++import GHC.TypeNats+import Data.List.Range++data FingerTree a+	= Empty | Single a+	| Deep (DigitL a) (FingerTree (Node a)) (DigitR a)+	deriving Show++type Node = RangeL 2 3+type DigitL = RangeL 1 4+type DigitR = RangeR 1 4++infixr 5 <||++(<||) :: a -> DigitL a -> Either (DigitL a) (DigitL a, Node a)+a <|| b :. NilL = Left $ a :. b :.. NilL+a <|| b :. c :.. NilL = Left $ a :. b :.. c :.. NilL+a <|| b :. c :.. d :.. NilL = Left $ a :. b :.. c :.. d :.. NilL+a <|| b :. c :.. d :.. e :.. NilL =+	Right (a :. b :.. NilL, c :. d :. e :.. NilL)++infixr 5 <|++(<|) :: a -> FingerTree a -> FingerTree a+a <| Empty = Single a+a <| Single b = Deep (a :. NilL) Empty (NilR :+ b)+a <| Deep pr m sf = case a <|| pr of+	Left pr' -> Deep pr' m sf+	Right (pr', n3) -> Deep pr' (n3 <| m) sf++infixr 5 <|.++(<|.) :: Foldable t => t a -> FingerTree a -> FingerTree a+(<|.) = flip $ foldr (<|)++toTree :: Foldable t => t a -> FingerTree a+toTree = (<|. Empty)++infixl 5 ||>, |>, |>.++(||>) :: DigitR a -> a -> Either (DigitR a) (Node a, DigitR a)+NilR :+ a ||> b = Left $ NilR :++ a :+ b+NilR :++ a :+ b ||> c = Left $ NilR :++ a :++ b :+ c+NilR :++ a :++ b :+ c ||> d = Left $ NilR :++ a :++ b :++ c :+ d+NilR :++ a :++ b :++ c :+ d ||> e =+	Right (a :. b :. c :.. NilL, NilR :++ d :+ e)++(|>) :: FingerTree a -> a -> FingerTree a+Empty |> a = Single a+Single a |> b = Deep (a :. NilL) Empty (NilR :+ b)+Deep pr m sf |> a = case sf ||> a of+	Left sf' -> Deep pr m sf'+	Right (n3, sf') -> Deep pr (m |> n3) sf'++(|>.) :: Foldable t => FingerTree a -> t a -> FingerTree a+(|>.) = foldl (|>)++uncons :: FingerTree a -> Maybe (a, FingerTree a)+uncons Empty = Nothing+uncons (Single x) = Just (x, Empty)+uncons (Deep (a :. pr') m sf) = Just (a, deepL pr' m sf)++deepL :: RangeL 0 3 a -> FingerTree (Node a) -> DigitR a -> FingerTree a+deepL NilL m sf = case uncons m of+	Nothing -> toTree sf+	Just (n, m') -> Deep (loosenL n) m' sf+deepL (a :.. pr) m sf = Deep (loosenL $ a :. pr) m sf++class Nodes m w where nodes :: RangeL 3 m a -> RangeL 1 w (Node a)++instance Nodes 3 1 where nodes = (:. NilL) . loosenL++instance {-# OVERLAPPABLE #-} (2 <= w, Nodes (m - 3) (w - 1)) => Nodes m w where+	nodes :: forall a . RangeL 3 m a -> RangeL 1 w (Node a)+	nodes (a :. b :. c :. NilL) = (a :. b :. c :.. NilL) :. NilL+	nodes (a :. b :. c :. d :.. NilL) =+		(a :. b :. NilL) :. (c :. d :. NilL) :.. NilL+	nodes (a :. b :. c :. d :.. e :.. NilL) =+		(a :. b :. c :.. NilL) :. (d :. e :. NilL) :.. NilL+	nodes (a :. b :. c :. d :.. e :.. f :.. xs) =+		(a :. b :. c :.. NilL) .:..+			nodes @(m - 3) @(w - 1) (d :. e :. f :. xs)++app3 :: FingerTree a -> RangeL 1 4 a -> FingerTree a -> FingerTree a+app3 Empty m xs = m <|. xs+app3 xs m Empty = xs |>. m+app3 (Single x) m xs = x <| m <|. xs+app3 xs m (Single x) = xs |>. m |> x+app3 (Deep pr1 m1 sf1) m (Deep pr2 m2 sf2) =+	Deep pr1 (app3 m1 (nodes $ sf1 ++.. m ++. pr2) m2) sf2++(><) :: FingerTree a -> FingerTree a -> FingerTree a+l >< r = case uncons r of Nothing -> l; Just (x, r') -> app3 l (x :. NilL) r'++main :: IO ()+main = do+	let	h = toTree "Hello, "+		w = toTree "world!"+	print h+	print $ uncons h+	print $ h >< w
+ sample/fourPointsOfRect.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE BlockArguments, LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++import GHC.TypeNats+import Control.Monad.Fix+import Control.Monad.Catch+import Data.List.Length+import Text.Read++fourPoints :: LengthR 4 Double -> LengthR 4 (Double, Double)+fourPoints (NilR :+ l :+ t :+ w :+ h) =+	NilR :+ (l, t) :+ (l + w, t) :+ (l, t + h) :+ (l + w, t + h)++data DeleteOr a = Delete | Value a deriving Show+data NothingToDeleteException = NothingToDeleteException deriving Show+instance Exception NothingToDeleteException++class GetElems n v where+	getElems :: MonadThrow m =>+		LengthR n a -> m (Maybe (DeleteOr a)) -> m (LengthR (n + v) a)++instance GetElems 0 0 where getElems NilR _ = pure NilR++instance {-# OVERLAPPABLE #-} 1 <= n => GetElems n 0 where+	getElems xs@(_ :+ _) _ = pure xs++instance {-# OVERLAPPABLE #-} GetElems 1 (v - 1) => GetElems 0 v where+	getElems NilR gt = gt >>= \case+		Nothing -> getElems NilR gt+		Just Delete -> throwM NothingToDeleteException+		Just (Value x) -> getElems @1 @(v - 1) (NilR :+ x) gt++instance {-# OVERLAPPABLE #-}+	(1 <= n, GetElems (n - 1) (v + 1), GetElems (n + 1) (v - 1)) =>+	GetElems n v where+	getElems xa@(xs :+ _) gt = gt >>= \case+		Nothing -> getElems xa gt+		Just Delete -> getElems @(n - 1) @(v + 1) xs gt+		Just (Value x) -> getElems @(n + 1) @(v - 1) (xa :+ x) gt++titles :: (Show a, Applicative (LengthR n)) =>+	Int -> LengthR n String -> LengthR n a -> LengthR n String+titles n ts xs = (\t x -> t ++ replicate (n - length t) ' ' ++ ": " ++ show x)+	<$> ts <*> xs++printResult :: LengthR 4 Double -> IO ()+printResult r = do+	putStrLn ""+	putStrLn `mapM_` titles 6 t r; putStrLn ""+	putStrLn `mapM_` titles 12 u (fourPoints r); putStrLn ""+	where+	t = NilR :+ "left" :+ "top" :+ "width" :+ "height"+	u = NilR :+ "left-top" :+ "right-top" :+ "left-bottom" :+ "right-bottom"++getRect :: forall n . GetElems n (4 - n) =>+	LengthR n Double -> IO (LengthR 4 Double)+getRect xs = (<$) <$> id <*> printResult =<<+	getElems @n @(4 - n) xs ((<$> getLine) \case+		"d" -> Just Delete; l -> Value <$> readMaybe l)+	`catch`+	\(_ :: NothingToDeleteException) ->+		putStrLn "*** Nothing to delete." >> getRect @0 NilR++main :: IO ()+main = getRect NilR >>= fix \go xa@(xs :+ _) -> getLine >>= \case+	"q" -> pure ();+	"d" -> go =<< getRect xs+	_ -> putStrLn "q or d" >> go xa
+ sample/password.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++import Data.List.Range+import System.IO++import qualified Data.ByteString.Char8 as BSC++type Password = RangeL 8 127 Char++getRangedPassword :: Unfoldr 0 n m => IO (Maybe (RangeL n m Char))+getRangedPassword = do+	e <- hGetEcho stdin+	hSetEcho stdin False+	unfoldrMRangeMaybe ((/= '\n') <$> hLookAhead stdin) getChar+		<* hSetEcho stdin e++passwordToByteString :: Password -> BSC.ByteString+passwordToByteString = foldr BSC.cons ""++main :: IO ()+main = do+	p <- getRangedPassword+	print p+	maybe (error "bad password length") BSC.putStrLn $ passwordToByteString <$> p
+ sample/rectangle.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++import Data.List.Length++data Rect = Rect {+	left :: Double, top :: Double,+	width :: Double, height :: Double } deriving Show++makeRect :: LengthL 4 Double -> Rect+makeRect (l :. t :. w :. h :. NilL) = Rect l t w h++main :: IO ()+main = print $ map makeRect . fst $ chunksL [3, 5, 15, 2, 8, 4, 1, 9, 3, 5]
+ sample/word64.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++import GHC.TypeNats+import Data.Foldable+import Data.List.Length+import Data.List.Range+import Data.Bits+import Data.Word+import Numeric++takeL :: (LoosenLMax 0 (n - 1) n, Unfoldr 0 n n, ListToLengthL n) =>+	a -> [a] -> LengthL n a+takeL d = either ((`fillL` d) . loosenLMax) fst . splitL++data Bit = O | I deriving Show++boolToBit :: Bool -> Bit+boolToBit = \case False -> O; True -> I++bitToNum63 :: (Num n, Bits n) => Bit -> n+bitToNum63 = \case O -> 0; I -> 1 `shiftL` 63++bitsToWord64 :: LengthL 64 Bit -> Word64+bitsToWord64 = foldl' (\w b -> w `shiftR` 1 .|. bitToNum63 b) 0++takeWord64 :: String -> Word64+takeWord64 = bitsToWord64 . takeL O . (boolToBit . (== '*') <$>)++main :: IO ()+main = do+	putStrLn $ takeWord64 sample1 `showHex` ""+	putStrLn $ takeWord64 sample2 `showHex` ""++sample1, sample2 :: String+sample1 = "...*..*..*...........*...**********...*************............******"+sample2 = "...*..*..*...........*.."
+ src/Control/Monad/Identity.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Control.Monad.Identity (Identity(..)) where++newtype Identity a = Identity { runIdentity :: a } deriving Show++instance Functor Identity where fmap = (Identity .) . (. runIdentity)++instance Applicative Identity where+	pure = Identity; Identity f <*> Identity x = Identity $ f x++instance Monad Identity where Identity x >>= f = f x
+ src/Control/Monad/State.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE BlockArguments #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Control.Monad.State (StateL(..), StateR(..)) where++import Control.Arrow (first, second)++---------------------------------------------------------------------------++-- * STATE LEFT+-- * STATE RIGHT++---------------------------------------------------------------------------+-- STATE LEFT+---------------------------------------------------------------------------++newtype StateL s a = StateL { runStateL :: s -> (a, s) }++instance Functor (StateL s) where f `fmap` StateL k = StateL $ (f `first`) . k++instance Applicative (StateL s) where+	pure = StateL . (,)+	StateL kf <*> mx =+		StateL \s -> let (f, s') = kf s in (f <$> mx) `runStateL` s'++instance Monad (StateL s) where+	StateL k >>= f = StateL \s -> let (x, s') = k s in f x `runStateL` s'++---------------------------------------------------------------------------+-- STATE RIGHT+---------------------------------------------------------------------------++newtype StateR s a = StateR { runStateR :: s -> (s, a) }++instance Functor (StateR s) where f `fmap` StateR k = StateR $ (f `second`) . k++instance Applicative (StateR s) where+	pure = StateR . flip (,)+	StateR kf <*> mx =+		StateR \s -> let (s', f) = kf s in (f <$> mx) `runStateR` s'++instance Monad (StateR s) where+	StateR k >>= f = StateR \s -> let (s', x) = k s in f x `runStateR` s'
+ src/Data/List/Length.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE BlockArguments, TupleSections #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Data.List.Length (+	-- * LENGTHED LIST LEFT+	-- ** Type+	LengthL, RangeL(NilL, (:.)),+	-- ** AddL+	AddL, (++.),+	-- ** Unfoldr+	-- *** class+	Unfoldr,+	-- *** without monad+	repeatL, fillL, unfoldr, unfoldrWithBase,+	-- *** with monad+	unfoldrM, unfoldrMWithBase,+	-- ** ZipL+	ZipL, zipL, zipWithL, zipWithML,+	-- ** ListToLengthL+	ListToLengthL, splitL, chunksL, chunksL',+	-- * LENGTHED LIST RIGHT+	-- ** Type+	LengthR, RangeR(NilR, (:+)),+	-- ** AddR+	AddR, (+++),+	-- ** Unfoldl+	-- *** class+	Unfoldl,+	-- *** without monad+	repeatR, fillR, unfoldl, unfoldlWithBase,+	-- *** with monad+	unfoldlM, unfoldlMWithBase,+	-- ** ZipR+	ZipR, zipR, zipWithR, zipWithMR,+	-- ** ListToLengthR+	ListToLengthR, listToLengthR, chunksR, chunksR',+	-- * LEFT TO RIGHT+	LeftToRight, (++.+), leftToRight,+	-- * RIGHT TO LEFT+	RightToLeft, (++..), rightToLeft ) where++import GHC.TypeNats (type (-))+import Control.Arrow (first, (***))+import Data.List.Range (+	RangeL(..), AddL, (++.), LoosenLMax, loosenLMax, Unfoldr,+	ZipL, zipL, zipWithL, zipWithML,+	RangeR(..), AddR, (+++), LoosenRMax, loosenRMax, Unfoldl,+	ZipR, zipR, zipWithR, zipWithMR,+	LeftToRight, (++.+), leftToRight, RightToLeft, (++..), rightToLeft )+import Data.List.Length.LengthL (+	LengthL, unfoldr, unfoldrWithBase, unfoldrM, unfoldrMWithBase,+	ListToLengthL, splitL )+import Data.List.Length.LengthR (+	LengthR, unfoldl, unfoldlWithBase, unfoldlM, unfoldlMWithBase,+	ListToLengthR, listToLengthR )++---------------------------------------------------------------------------++-- LENGTH LEFT+-- LENGTH RIGHT++---------------------------------------------------------------------------+-- LENGTH LEFT+---------------------------------------------------------------------------++repeatL :: Unfoldr 0 n n => a -> LengthL n a+repeatL = fillL NilL++{-^++To repeat a value of type @a@ to construct a list of type @LengthL n a@.++>>> :set -XDataKinds+>>> repeatL 'c' :: LengthL 5 Char+'c' :. ('c' :. ('c' :. ('c' :. ('c' :. NilL))))++-}++fillL :: Unfoldr n m m => RangeL n m a -> a -> LengthL m a+fillL = (`unfoldrWithBase` \x -> (x, x))++{-^++To fill a list of type @LengthL n a@ with a value of type @a@.++>>> :set -XDataKinds+>>> fillL ('a' :. 'b' :.. NilL) 'c' :: LengthL 5 Char+'a' :. ('b' :. ('c' :. ('c' :. ('c' :. NilL))))++-}++chunksL :: ListToLengthL n => [a] -> ([LengthL n a], RangeL 0 (n - 1) a)+chunksL = either ([] ,) (uncurry first . ((:) *** chunksL)) . splitL++{-^++To separate a list to multiple lengthed lists.+It return separeted lengthed lists and a not enough length fragment.++>>> :set -XTypeApplications -XDataKinds+>>> chunksL @3 "foo bar"+(['f' :. ('o' :. ('o' :. NilL)),' ' :. ('b' :. ('a' :. NilL))],'r' :.. NilL)++-}++chunksL' :: (Unfoldr 0 n n, LoosenLMax 0 (n - 1) n, ListToLengthL n) =>+	a -> [a] -> [LengthL n a]+chunksL' z xs = case chunksL xs of+	(cs, NilL) -> cs; (cs, rs) -> cs ++ [loosenLMax rs `fillL` z]++{-^++It is like chunksL.+But if there is a not enough length fragment, then it fill with a default value.++>>> :set -XTypeApplications -XDataKinds+>>> print `mapM_` chunksL' @3 '@' "foo bar"+'f' :. ('o' :. ('o' :. NilL))+' ' :. ('b' :. ('a' :. NilL))+'r' :. ('@' :. ('@' :. NilL))++-}++---------------------------------------------------------------------------+-- LENGTH RIGHT+---------------------------------------------------------------------------++repeatR :: Unfoldl 0 n n => a -> LengthR n a+repeatR = (`fillR` NilR)++{-^++To repeat a value of type @a@ to construct a list of type @LengthR n a@.++>>> :set -XDataKinds+>>> repeatR 'c' :: LengthR 5 Char+((((NilR :+ 'c') :+ 'c') :+ 'c') :+ 'c') :+ 'c'++-}++fillR :: Unfoldl n m m => a -> RangeR n m a -> LengthR m a+fillR = unfoldlWithBase \x -> (x, x)++{-^++To fill a list of type @LengthR n a@ with a default value.++>>> :set -XDataKinds+>>> fillR 'c' (NilR :++ 'a' :+ 'b') :: LengthR 5 Char+((((NilR :+ 'c') :+ 'c') :+ 'c') :+ 'a') :+ 'b'++-}++chunksR :: ListToLengthR n => [a] -> ([LengthR n a], RangeR 0 (n - 1) a)+chunksR = either ([] ,) (uncurry first . ((:) *** chunksR)) . listToLengthR++{-^++To separate a list to multiple lengthed lists.+It return separated lengthed lists and a not enough length fragment.++>>> :set -XTypeApplications -XDataKinds+>>> chunksR @3 "foo bar"+([((NilR :+ 'o') :+ 'o') :+ 'f',((NilR :+ 'a') :+ 'b') :+ ' '],NilR :++ 'r')++-}++chunksR' :: (Unfoldl 0 n n, LoosenRMax 0 (n - 1) n, ListToLengthR n) =>+	a -> [a] -> [LengthR n a]+chunksR' z xs = case chunksR xs of+	(cs, NilR) -> cs; (cs, rs) -> cs ++ [z `fillR` loosenRMax rs]++{-^++It is like @chunksR@.+But if there is a not enough length fragment, then it fill with a default value.++>>> :set -XTypeApplications -XDataKinds+>>> print `mapM_` chunksR' @3 '@' "foo bar"+((NilR :+ 'o') :+ 'o') :+ 'f'+((NilR :+ 'a') :+ 'b') :+ ' '+((NilR :+ '@') :+ '@') :+ 'r'++-}
+ src/Data/List/Length/LengthL.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Data.List.Length.LengthL (+	LengthL, unfoldr, unfoldrWithBase, unfoldrM, unfoldrMWithBase,+	ListToLengthL, splitL ) where++import GHC.TypeNats (type (-), type (<=))+import Control.Arrow (first, (+++))+import Control.Monad.State (StateL(..))+import Data.List.Range.RangeL (LengthL, RangeL(..), Unfoldr, unfoldrMRangeWithBase)++---------------------------------------------------------------------------++-- * TYPE+-- * UNFOLDR+-- * LIST TO LENGTH LEFT++---------------------------------------------------------------------------+-- TYPE+---------------------------------------------------------------------------++---------------------------------------------------------------------------+-- UNFOLDR+---------------------------------------------------------------------------++unfoldr :: Unfoldr 0 n n => (s -> (a, s)) -> s -> LengthL n a+unfoldr = unfoldrWithBase NilL++{-^++To evaluate function repeatedly to construct a list of type @LengthL n a@.+The function recieve a state and return an element value and a new state.++>>> :set -XDataKinds+>>> unfoldr (\n -> (2 * n, n + 1)) 0 :: LengthL 5 Integer+0 :. (2 :. (4 :. (6 :. (8 :. NilL))))++-}++unfoldrWithBase ::+	Unfoldr n m m => RangeL n m a -> (s -> (a, s)) -> s -> LengthL m a+unfoldrWithBase xs = (fst .) . runStateL . unfoldrMWithBase xs . StateL++{-^++It is like @unfoldr@. But it has already prepared values.++>>> :set -XDataKinds+>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer+>>> unfoldrWithBase xs (\n -> (2 * n, n + 1)) 0 :: LengthL 5 Integer+123 :. (456 :. (0 :. (2 :. (4 :. NilL))))++-}++unfoldrM :: (Monad m, Unfoldr 0 n n) => m a -> m (LengthL n a)+unfoldrM = unfoldrMWithBase NilL++{-^++It is like @unfoldr@. But it use a monad as an argument instead of a function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n <$ writeIORef r (n +1)+>>> unfoldrM count :: IO (LengthL 5 Integer)+1 :. (2 :. (3 :. (4 :. (5 :. NilL))))++-}++unfoldrMWithBase ::+	(Monad m, Unfoldr n w w) => RangeL n w a -> m a -> m (LengthL w a)+unfoldrMWithBase = (`unfoldrMRangeWithBase` undefined)++{-^++It is like @unfoldrM@. But it has already prepared values.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n <$ writeIORef r (n + 1)+>>> unfoldrMWithBase (123 :. 456 :.. NilL) count :: IO (LengthL 5 Integer)+123 :. (456 :. (1 :. (2 :. (3 :. NilL))))++-}++---------------------------------------------------------------------------+-- LIST TO LENGTH LEFT+---------------------------------------------------------------------------++class ListToLengthL n where+	splitL :: [a] -> Either (RangeL 0 (n - 1) a) (LengthL n a, [a])++	{-^++	To take a lengthed list from a list.+	If an original list has not enough elements, then it return+	a left value.++	>>> :set -XTypeApplications -XDataKinds+	>>> splitL @4 "Hi!"+	Left ('H' :.. ('i' :.. ('!' :.. NilL)))+	>>> splitL @4 "Hello!"+	Right ('H' :. ('e' :. ('l' :. ('l' :. NilL))),"o!")++	-}++instance ListToLengthL 1 where+	splitL = \case [] -> Left NilL; x : xs -> Right (x :. NilL, xs)++instance {-# OVERLAPPABLE #-}+	(1 <= n, 1 <= (n - 1), ListToLengthL (n - 1)) => ListToLengthL n where+	splitL = \case+		[] -> Left NilL+		x : xs -> (x :..) +++ ((x :.) `first`) $ splitL xs
+ src/Data/List/Length/LengthR.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Data.List.Length.LengthR (+	LengthR, unfoldl, unfoldlWithBase, unfoldlM, unfoldlMWithBase,+	ListToLengthR, listToLengthR ) where++import GHC.TypeNats (type (-), type (<=))+import Control.Arrow (first, (+++))+import Control.Monad.State (StateR(..))+import Data.List.Range.RangeR (RangeR(..), Unfoldl, unfoldlMRangeWithBase)++---------------------------------------------------------------------------++-- TYPE+-- UNFOLDL+-- LIST TO LENGTH RIGHT++---------------------------------------------------------------------------+-- TYPE+---------------------------------------------------------------------------++type LengthR n = RangeR n n++{-^++@LengthR n a@ is a list which have just n members of type @a@.+You can push and pop an element from right.++>>> :set -XDataKinds+>>> sampleLengthR = NilR :+ 'h' :+ 'e' :+ 'l' :+ 'l' :+ 'o' :: LengthR 5 Char++-}++---------------------------------------------------------------------------+-- UNFOLDL+---------------------------------------------------------------------------++unfoldl :: Unfoldl 0 n n => (s -> (s, a)) -> s -> LengthR n a+unfoldl f s = unfoldlWithBase f s NilR++{-^++To eveluate function repeatedly to construct a list of type @LengthR n a@.+The function recieve a state and return a new state and an element value.++>>> :set -XDataKinds+>>> unfoldl (\n -> (n + 1, 2 * n)) 0 :: LengthR 5 Integer+((((NilR :+ 8) :+ 6) :+ 4) :+ 2) :+ 0++-}++unfoldlWithBase ::+	Unfoldl n m m => (s -> (s, a)) -> s -> RangeR n m a -> LengthR m a+unfoldlWithBase f = (snd .) . flip (runStateR . unfoldlMWithBase (StateR f))++{-^++It is like @unfoldl@. But it has already prepared values.++>>> :set -XDataKinds+>>> xs = NilR :++ 123 :+ 456 :: RangeR 1 5 Integer+>>> unfoldlWithBase (\n -> (n + 1, 2 * n)) 0 xs :: LengthR 5 Integer+((((NilR :+ 4) :+ 2) :+ 0) :+ 123) :+ 456++-}++unfoldlM :: (Monad m, Unfoldl 0 n n) => m a -> m (LengthR n a)+unfoldlM = (`unfoldlMWithBase` NilR)++{-^++It is like @unfoldl@. But it use monad as an argument instead of function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n <$ writeIORef r (n + 1)+>>> unfoldlM count :: IO (LengthR 5 Integer)+((((NilR :+ 5) :+ 4) :+ 3) :+ 2) :+ 1++-}++unfoldlMWithBase ::+	(Monad m, Unfoldl n w w) => m a -> RangeR n w a -> m (LengthR w a)+unfoldlMWithBase = unfoldlMRangeWithBase undefined++{-^++It is like @unfoldlM@. But it has already prepared values.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n <$ writeIORef r (n + 1)+>>> unfoldlMWithBase count (NilR :++ 123 :+ 456) :: IO (LengthR 5 Integer)+((((NilR :+ 3) :+ 2) :+ 1) :+ 123) :+ 456++-}++---------------------------------------------------------------------------+-- LIST TO LENGTH RIGHT+---------------------------------------------------------------------------++class ListToLengthR n where+	listToLengthR :: [a] -> Either (RangeR 0 (n - 1) a) (LengthR n a, [a])++	{-^++	To take a lengthed list from a list.+	If an original list has not enough elements, then it return a left value.++	>>> :set -XTypeApplications -XDataKinds+	>>> listToLengthR @4 "Hi!"+	Left (((NilR :++ '!') :++ 'i') :++ 'H')+	>>> listToLengthR @4 "Hello!"+	Right ((((NilR :+ 'l') :+ 'l') :+ 'e') :+ 'H',"o!")++	-}++instance ListToLengthR 1 where+	listToLengthR = \case [] -> Left NilR; x : xs -> Right (NilR :+ x, xs)++instance {-# OVERLAPPABLE #-}+	(1 <= n, 1 <= (n - 1), ListToLengthR (n - 1)) => ListToLengthR n where+	listToLengthR = \case+		[] -> Left NilR+		x : xs -> (:++ x) +++ ((:+ x) `first`) $ listToLengthR xs
+ src/Data/List/Range.hs view
@@ -0,0 +1,372 @@+{-# LANGUAGE BlockArguments, LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# OPTIOnS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++module Data.List.Range (+	-- * RANGED LIST LEFT+	module Data.List.Range.RangeL,+	-- ** Repeat and Unfoldr Min and Max+	-- *** repeat+	repeatLMin, repeatLMax,+	-- *** unfoldr+	unfoldrMin, unfoldrMax,+	-- *** unfoldrM+	unfoldrMMin, unfoldrMMax,+	-- * RANGED LIST RIGHT+	module Data.List.Range.RangeR,+	-- ** Repeat and Unfoldl Min and Max+	-- *** repeat+	repeatRMin, repeatRMax,+	-- *** unfoldl+	unfoldlMin, unfoldlMax,+	-- *** unfoldlM+	unfoldlMMin, unfoldlMMax,+	-- * LEFT TO RIGHT+	LeftToRight, (++.+), leftToRight,+	-- * RIGHT TO LEFT+	RightToLeft, (++..), rightToLeft ) where++import GHC.TypeNats (type (+), type (-), type (<=))+import Data.List.Length.LengthL (unfoldr, unfoldrM)+import Data.List.Length.LengthR (unfoldl, unfoldlM)+import Data.List.Range.RangeL+import Data.List.Range.RangeR++---------------------------------------------------------------------------++-- * RANGED LIST LEFT+--	+ MIN+--	+ MAX+-- * RANGED LIST RIGHT+--	+ MIN+--	+ MAX+-- * LEFT TO RIGHT+--	+ CLASS+--	+ INSTANCE+--	+ FUNCTION+-- * RIGHT TO LEFT+--	+ CLASS+--	+ INSTANCE+--	+ FUNCTION++---------------------------------------------------------------------------+-- RANGED LIST LEFT+---------------------------------------------------------------------------++-- MIN++repeatLMin :: (LoosenLMax n n m, Unfoldr 0 n n) => a -> RangeL n m a+repeatLMin = unfoldrMin \x -> (x, x)++{-^++To repeat a value minimum number of times.++>>> :set -XDataKinds+>>> repeatLMin 123 :: RangeL 3 5 Integer+123 :. (123 :. (123 :. NilL))++-}++unfoldrMin ::+	(LoosenLMax n n m, Unfoldr 0 n n) => (s -> (a, s)) -> s -> RangeL n m a+unfoldrMin f = loosenLMax . unfoldr f++{-^++To evaluate a function to construct values minimum number of times.+The function recieve a state and return a value and a new state.++>>> :set -XDataKinds+>>> unfoldrMin (\n -> (n * 3, n + 1)) 1 :: RangeL 3 5 Integer+3 :. (6 :. (9 :. NilL))++-}++unfoldrMMin ::+	(Monad m, LoosenLMax n n w, Unfoldr 0 n n) => m a -> m (RangeL n w a)+unfoldrMMin f = loosenLMax <$> unfoldrM f++{-^++It is like @unfoldrMin@. But it use a monad instead of a function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldrMMin count :: IO (RangeL 3 5 Integer)+3 :. (6 :. (9 :. NilL))++-}++-- MAX++repeatLMax :: (LoosenLMin m m n, Unfoldr 0 m m) => a -> RangeL n m a+repeatLMax = unfoldrMax \x -> (x, x)++{-^++To repeat a value maximum number of times.++>>> :set -XDataKinds+>>> repeatLMax 123 :: RangeL 3 5 Integer+123 :. (123 :. (123 :. (123 :.. (123 :.. NilL))))++-}++unfoldrMax ::+	(LoosenLMin m m n, Unfoldr 0 m m) => (s -> (a, s)) -> s -> RangeL n m a+unfoldrMax f = loosenLMin . unfoldr f++{-^++To evaluate a function to construct values maximum number of times.+The function recieve a state and return a value and a new state.++>>> :set -XDataKinds+>>> unfoldrMax (\n -> (n * 3, n + 1)) 1 :: RangeL 3 5 Integer+3 :. (6 :. (9 :. (12 :.. (15 :.. NilL))))++-}++unfoldrMMax ::+	(Monad m, LoosenLMin w w n, Unfoldr 0 w w) => m a -> m (RangeL n w a)+unfoldrMMax f = loosenLMin <$> unfoldrM f++{-^++It is like @unfoldrMax@. But it use a monad instead of a function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldrMMax count :: IO (RangeL 3 5 Integer)+3 :. (6 :. (9 :. (12 :.. (15 :.. NilL))))++-}++---------------------------------------------------------------------------+-- RANGED LIST RIGHT+---------------------------------------------------------------------------++-- MIN++repeatRMin :: (LoosenRMax n n m, Unfoldl 0 n n) => a -> RangeR n m a+repeatRMin = unfoldlMin \x -> (x, x)++{-^++To repeat a value minimum number of times.++>>> :set -XDataKinds+>>> repeatRMin 123 :: RangeR 3 5 Integer+((NilR :+ 123) :+ 123) :+ 123++-}++unfoldlMin ::+	(LoosenRMax n n m, Unfoldl 0 n n) => (s -> (s, a)) -> s -> RangeR n m a+unfoldlMin f = loosenRMax . unfoldl f++{-^++To evaluate a function to construct values minimum number of times.+The function recieves a state and return a value and a new state.++>>> :set -XDataKinds+>>> unfoldlMin (\n -> (n + 1, n * 3)) 1 :: RangeR 3 5 Integer+((NilR :+ 9) :+ 6) :+ 3++-}++unfoldlMMin ::+	(Monad m, LoosenRMax n n w, Unfoldl 0 n n) => m a -> m (RangeR n w a)+unfoldlMMin f = loosenRMax <$> unfoldlM f++{-^++It is like @unfoldlMax@. But it uses a monad instead of a function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldlMMin count :: IO (RangeR 3 5 Integer)+((NilR :+ 9) :+ 6) :+ 3++-}++-- MAX++repeatRMax :: (LoosenRMin m m n, Unfoldl 0 m m) => a -> RangeR n m a+repeatRMax = unfoldlMax \x -> (x, x)++{-^++To repeat a value maximum number of times.++>>> :set -XDataKinds+>>> repeatRMax 123 :: RangeR 3 5 Integer+((((NilR :++ 123) :++ 123) :+ 123) :+ 123) :+ 123++-}++unfoldlMax ::+	(LoosenRMin m m n, Unfoldl 0 m m) => (s -> (s, a)) -> s -> RangeR n m a+unfoldlMax f = loosenRMin . unfoldl f++{-^++To eveluate a function to construct values maximum number of times.+The function recieves a state and return a value and a new state.++>>> :set -XDataKinds+>>> unfoldlMax (\n -> (n + 1, n * 3)) 1 :: RangeR 3 5 Integer+((((NilR :++ 15) :++ 12) :+ 9) :+ 6) :+ 3++-}++unfoldlMMax ::+	(Monad m, LoosenRMin w w n, Unfoldl 0 w w) => m a -> m (RangeR n w a)+unfoldlMMax f = loosenRMin <$> unfoldlM f++{-^++It is like @unfoldlMax@. But it uses a monad instead of function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldlMMax count :: IO (RangeR 3 5 Integer)+((((NilR :++ 15) :++ 12) :+ 9) :+ 6) :+ 3++-}++---------------------------------------------------------------------------+-- LEFT TO RIGHT+---------------------------------------------------------------------------++-- CLASS++infixl 5 ++.+++class LeftToRight n m v w where+	(++.+) :: RangeR n m a -> RangeL v w a -> RangeR (n + v) (m + w) a++	{-^++	To concatenate a right-list and a left-list and return a right-list.++	>>> :set -XDataKinds+	>>> sampleLeftToRight1 = NilR :++ 'f' :++ 'o' :+ 'o' :: RangeR 1 4 Char+	>>> sampleLeftToRight2 = 'b' :. 'a' :. 'r' :.. NilL :: RangeL 2 3 Char+	>>> sampleLeftToRight1 ++.+ sampleLeftToRight2+	(((((NilR :++ 'f') :++ 'o') :++ 'o') :+ 'b') :+ 'a') :+ 'r'+	>>> :type sampleLeftToRight1 ++.+ sampleLeftToRight2+	sampleLeftToRight1 ++.+ sampleLeftToRight2 :: RangeR 3 7 Char++	-}++-- INSTANCE++instance LeftToRight n m 0 0 where n ++.+ _ = n++instance {-# OVERLAPPABLE #-} (+	PushR (n - 1) (m - 1), LoosenRMax n m (m + w),+	LeftToRight n (m + 1) 0 (w - 1) ) => LeftToRight n m 0 w where+	(++.+) n = \case NilL -> loosenRMax n; x :.. v -> n .:++ x ++.+ v++instance {-# OVERLAPPABLE #-}+	(1 <= v, LeftToRight (n + 1) (m + 1) (v - 1) (w - 1)) =>+	LeftToRight n m v w where+	(++.+) :: forall a .+		RangeR n m a -> RangeL v w a -> RangeR (n + v) (m + w) a+	n ++.+ x :. v = (n :+ x :: RangeR (n + 1) (m + 1) a) ++.+ v++-- FUNCTION++leftToRight ::+	forall v w a . LeftToRight 0 0 v w => RangeL v w a -> RangeR v w a+leftToRight = ((NilR :: RangeR 0 0 a) ++.+)++{-^++To convert a left-list to a right-list.++>>> :set -XDataKinds -fno-warn-tabs+>>> :{+	sampleLeftToRight :: RangeL 3 8 Char+	sampleLeftToRight = 'h' :. 'e' :. 'l' :. 'l' :.. 'o' :.. NilL+:}++>>> leftToRight sampleLeftToRight+((((NilR :++ 'h') :++ 'e') :+ 'l') :+ 'l') :+ 'o'++-}++---------------------------------------------------------------------------+-- RIGHT TO LEFT+---------------------------------------------------------------------------++-- CLASS++infixr 5 ++..++class RightToLeft n m v w where+	(++..) :: RangeR n m a -> RangeL v w a -> RangeL (n + v) (m + w) a++	{-^++	To concatenate a right-list and a left-list and return a left-list.++	>>> :set -XDataKinds+	>>> sampleRightToLeft1 = NilR :++ 'f' :++ 'o' :+ 'o' :: RangeR 1 4 Char+	>>> sampleRightToLeft2 = 'b' :. 'a' :. 'r' :.. NilL :: RangeL 2 3 Char+	>>> sampleRightToLeft1 ++.. sampleRightToLeft2+	'f' :. ('o' :. ('o' :. ('b' :.. ('a' :.. ('r' :.. NilL)))))++	-}++-- INSTANCE++instance RightToLeft 0 0 v w where _ ++.. v = v++instance {-# OVERLAPPABLE #-} (+	PushL (v - 1) (w - 1), LoosenLMax v w (m + w),+	RightToLeft 0 (m - 1) v (w + 1) ) => RightToLeft 0 m v w where+	(++..) = \case NilR -> loosenLMax; n :++ x -> (n ++..) . (x .:..)++instance {-# OVERLAPPABLE #-} (+	1 <= n, RightToLeft (n - 1) (m - 1) (v + 1) (w + 1) ) =>+	RightToLeft n m v w where+	(++..) :: forall a .+		RangeR n m a -> RangeL v w a -> RangeL (n + v) (m + w) a+	n :+ x ++.. v = n ++.. (x :. v :: RangeL (v + 1) (w + 1) a)++-- FUNCTION++rightToLeft ::+	forall n m a . RightToLeft n m 0 0 => RangeR n m a -> RangeL n m a+rightToLeft = (++.. (NilL :: RangeL 0 0 a))++{-^++To convert a right-list to a left-list.++>>> :set -XDataKinds+>>> :{+	sampleRightToLeft :: RangeR 3 8 Char+	sampleRightToLeft = NilR :++ 'h' :++ 'e' :+ 'l' :+ 'l' :+ 'o'+:}++>>> rightToLeft sampleRightToLeft+'h' :. ('e' :. ('l' :. ('l' :.. ('o' :.. NilL))))++-}
+ src/Data/List/Range/Nat.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DataKinds, TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Data.List.Range.Nat (+	-- * RangedNatL+	RangedNatL, natL, toIntL, fromIntL, splitAtL,+	-- * RangedNatR+	RangedNatR, natR, toIntR, fromIntR, splitAtR ) where++import GHC.TypeNats (type (-))+import Data.Bool (bool)+import Data.List.Length (repeatL, repeatR)+import Data.List.Range (+	RangeL, Unfoldr, unfoldrRangeMaybe, ZipL, zipWithL,+	RangeR, Unfoldl, unfoldlRangeMaybe, ZipR, zipWithR )++---------------------------------------------------------------------------++-- * RANGED NAT LEFT+-- * RANGED NAT RIGHT++---------------------------------------------------------------------------+-- RANGED NAT LEFT+---------------------------------------------------------------------------++type RangedNatL n m = RangeL n m ()++natL :: Unfoldr 0 n n => RangedNatL n n+natL = repeatL ()++{-^++To make @RangedNatL@.++>>> :set -XTypeApplications -XDataKinds+>>> :module + Data.List.Range+>>> loosenL (natL @5) :: RangedNatL 3 8+() :. (() :. (() :. (() :.. (() :.. NilL))))++-}++toIntL :: Foldable (RangeL n m) => RangedNatL n m -> Int+toIntL = length++{-^++To convert from @RangedNatL@ to @Int@.++>>> :set -XTypeApplications -XDataKinds+>>> :module + Data.List.Range+>>> toIntL (loosenL (natL @5) :: RangedNatL 3 8)+5++-}++fromIntL :: Unfoldr 0 n m => Int -> Maybe (RangedNatL n m)+fromIntL = unfoldrRangeMaybe \s -> bool Nothing (Just ((), s - 1)) (s > 0)++{-^++To convert from @Int@ to @RangedNatL@.++>>> :set -XDataKinds+>>> fromIntL 5 :: Maybe (RangedNatL 3 8)+Just (() :. (() :. (() :. (() :.. (() :.. NilL)))))++-}++splitAtL :: ZipL n m v w => RangedNatL n m ->+	RangeL v w a -> (RangeL n m a, RangeL (v - m) (w - n) a)+splitAtL = zipWithL $ flip const++{-^++To split a list at position which is specified by number.++>>> :set -XTypeApplications -XDataKinds+>>> :module + Data.List.Range+>>> xs = 'h' :. 'e' :. 'l' :. 'l' :.. 'o' :.. NilL :: RangeL 3 8 Char+>>> splitAtL (natL @2) xs+('h' :. ('e' :. NilL),'l' :. ('l' :.. ('o' :.. NilL)))+>>> :type splitAtL (natL @2) xs+splitAtL (natL @2) xs :: (RangeL 2 2 Char, RangeL 1 6 Char)++-}++---------------------------------------------------------------------------+-- RANGED NAT RIGHT+---------------------------------------------------------------------------++type RangedNatR n m = RangeR n m ()++natR :: Unfoldl 0 n n => RangedNatR n n+natR = repeatR ()++{-^++To make @RangedNatR@.++>>> :set -XTypeApplications -XDataKinds+>>> :module + Data.List.Range+>>> loosenR (natR @5) :: RangedNatR 3 8+((((NilR :++ ()) :++ ()) :+ ()) :+ ()) :+ ()++-}++toIntR :: Foldable (RangeR n m) => RangedNatR n m -> Int+toIntR = length++{-^++To convert from @RangedNatR@ to @Int@.++>>> :set -XTypeApplications -XDataKinds+>>> :module + Data.List.Range+>>> toIntR (loosenR (natR @5) :: RangedNatR 3 8)+5++-}++fromIntR :: Unfoldl 0 n m => Int -> Maybe (RangedNatR n m)+fromIntR = unfoldlRangeMaybe \s -> bool Nothing (Just (s - 1, ())) (s > 0)++{-^++To convert @Int@ to @RangedNatR@.++>>> :set -XDataKinds+>>> fromIntR 5 :: Maybe (RangedNatR 3 8)+Just (((((NilR :++ ()) :++ ()) :+ ()) :+ ()) :+ ())++-}++splitAtR :: ZipR n m v w => RangeR n m a ->+	RangedNatR v w -> (RangeR (n - w) (m - v) a, RangeR v w a)+splitAtR = zipWithR const++{-^++To split a list at position which is specified by number.++>>> :set -XTypeApplications -XDataKinds+>>> :module + Data.List.Range+>>> xs = NilR :++ 'h' :++ 'e' :+ 'l' :+ 'l' :+ 'o' :: RangeR 3 8 Char+>>> splitAtR xs (natR @2)+(((NilR :++ 'h') :++ 'e') :+ 'l',(NilR :+ 'l') :+ 'o')+>>> :type splitAtR xs (natR @2)+splitAtR xs (natR @2) :: (RangeR 1 6 Char, RangeR 2 2 Char)++-}
+ src/Data/List/Range/RangeL.hs view
@@ -0,0 +1,643 @@+{-# LANGUAGE BlockArguments, LambdaCase, TupleSections #-}+{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}+{-# LANGUAGE DataKinds, KindSignatures, TypeOperators #-}+{-# LANGUAGE GADTs, TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++module Data.List.Range.RangeL (+	LengthL,+	-- ** Type+	RangeL(..),+	-- ** PushL+	PushL, (.:..),+	-- ** AddL+	AddL, (++.),+	-- ** LoosenLMin and LoosenLMax+	-- *** loosenL+	loosenL,+	-- *** loosenLMin+	LoosenLMin, loosenLMin,+	-- *** loosenLMax+	LoosenLMax, loosenLMax,+	-- ** Unfoldr+	-- *** class+	Unfoldr,+	-- *** unfoldrRange+	-- **** without monad+	unfoldrRange, unfoldrRangeWithBase, unfoldrRangeWithBaseWithS,+	-- **** with monad+	unfoldrMRange, unfoldrMRangeWithBase,+	-- *** unfoldrRangeMaybe+	-- **** without monad+	unfoldrRangeMaybe, unfoldrRangeMaybeWithBase,+	-- **** with monad+	unfoldrMRangeMaybe, unfoldrMRangeMaybeWithBase,+	-- ** ZipL+	ZipL, zipL, zipWithL, zipWithML ) where++import GHC.TypeNats (Nat, type (+), type (-), type (<=))+import GHC.Exts (IsList(..))+import Control.Arrow (first, second, (***), (&&&))+import Control.Monad.Identity (Identity(..))+import Control.Monad.State (StateL(..))+import Data.Foldable (toList)+import Data.Bool (bool)+import Data.Maybe (isJust, fromMaybe)+import Data.String++type LengthL n = RangeL n n++{-^++The value of @LengthL n a@ is a list which have just @n@ members of type @a@.+You can push and pop an element from left.++>>> :set -XDataKinds+>>> sampleLengthL = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :. NilL :: LengthL 5 Char++-}++---------------------------------------------------------------------------++-- * TYPE+--	+ RANGE LEFT+--	+ INSTANCE FUNCTOR+--	+ INSTANCE FOLDABLE+-- * PUSH+-- * ADD+-- * LOOSEN+-- 	+ LOOSEN LEFT+-- 	+ LOOSEN LEFT MIN+-- 	+ LOOSEN LEFT MAX+-- * UNFOLDR+-- 	+ CLASS+-- 	+ INSTANCE+-- 	+ UNFOLDR RANGE+-- 	+ UNFOLDR RANGE MAYBE+-- * ZIP+--	+ CLASS+--	+ FUNCTION++---------------------------------------------------------------------------+-- TYPE+---------------------------------------------------------------------------++-- RANGE LEFT++data RangeL :: Nat -> Nat -> * -> * where+	NilL :: 0 <= m => RangeL 0 m a+	(:..) :: 1 <= m => a -> RangeL 0 (m - 1) a -> RangeL 0 m a+	(:.) :: (1 <= n, 1 <= m) =>+		a -> RangeL (n - 1) (m - 1) a -> RangeL n m a++{-^++The value of @RangeL n m a@ is a list of type @a@ values whose element number is+at minimum @n@, and at maximum @m@.+You can push and pop an element from left.++>>> :set -XDataKinds+>>> sampleRangeL = 'h' :. 'e' :. 'l' :. 'l' :.. 'o' :.. NilL :: RangeL 3 8 Char++-}++infixr 6 :., :..++deriving instance Show a => Show (RangeL n m a)++-- INSTANCE FUNCTOR++instance Functor (RangeL 0 0) where _ `fmap` NilL = NilL++instance {-# OVERLAPPABLE #-}+	Functor (RangeL 0 (m - 1)) => Functor (RangeL 0 m) where+	fmap f = \case NilL -> NilL; x :.. xs -> f x :.. (f <$> xs)++instance {-# OVERLAPPABLE #-}+	(1 <= n, Functor (RangeL (n - 1) (m - 1))) => Functor (RangeL n m) where+	f `fmap` (x :. xs) = f x :. (f <$> xs)++-- INSTANCE FOLDABLE++instance Foldable (RangeL 0 0) where foldr _ z NilL = z++instance {-# OVERLAPPABLE #-}+	Foldable (RangeL 0 (m - 1)) => Foldable (RangeL 0 m) where+	foldr (-<) z = \case NilL -> z; x :.. xs -> x -< foldr (-<) z xs++instance {-# OVERLAPPABLE #-} (1 <= n, Foldable (RangeL (n - 1) (m - 1))) =>+	Foldable (RangeL n m) where+	foldr (-<) z (x :. xs) = x -< foldr (-<) z xs++instance Applicative (LengthL 0) where pure _ = NilL; _ <*> _ = NilL++instance {-# OVERLAPPABLE #-} (Functor (RangeL 0 m), Applicative (RangeL 0 (m - 1)), Unfoldr 0 0 m) => Applicative (RangeL 0 m) where+	pure = unfoldrRange (const True) (\x -> (x, x))+	NilL <*> _ = NilL+	_ <*> NilL = NilL+	f :.. fs <*> x :.. xs = f x :.. (fs <*> xs)++instance {-# OVERLAPPABLE #-} (1 <= n, Functor (RangeL n m), Applicative (RangeL (n - 1) (m - 1)), Unfoldr 0 n m) => Applicative (RangeL n m) where+	pure = unfoldrRange (const True) (\x -> (x, x))+	f :. fs <*> x :. xs = f x :. (fs <*> xs)++instance Applicative (LengthL 0) => Monad (LengthL 0) where+	NilL >>= _ = NilL++instance {-# OVERLAPPABLE #-} (1 <= n, Applicative (LengthL n), Monad (LengthL (n - 1))) => Monad (LengthL n) where+	x :. xs >>= f = y :. (xs >>= \z -> case f z of _ :. zs -> zs)+		where y :. _ = f x++-- INSTANCE ISSTRING++instance Unfoldr 0 n m => IsString (RangeL n m Char) where+	fromString s = fromMaybe (error $ "The string " ++ show s ++ " is not within range.")+		$ unfoldrRangeMaybe (\case "" -> Nothing; c : cs -> Just (c, cs)) s++instance (Foldable (RangeL n m), Unfoldr 0 n m) => IsList (RangeL n m a) where+	type Item (RangeL n m a) = a+	fromList lst = fromMaybe (error $ "The list is not within range.")+		$ unfoldrRangeMaybe (\case [] -> Nothing; x : xs -> Just (x, xs)) lst+	toList = Data.Foldable.toList++---------------------------------------------------------------------------+-- PUSH+---------------------------------------------------------------------------++infixr 5 .:..++class PushL n m where+	(.:..) :: a -> RangeL n m a -> RangeL n (m + 1) a++	{-^++	To push an optional element.++	>>> :set -XDataKinds+	>>> samplePushL = 'e' :. 'l' :. 'l' :. 'o' :.. NilL :: RangeL 3 7 Char+	>>> 'h' .:.. samplePushL+	'h' :. ('e' :. ('l' :. ('l' :.. ('o' :.. NilL))))+	>>> :type 'h' .:.. samplePushL+	'h' .:.. samplePushL :: RangeL 3 8 Char++	-}++instance PushL 0 m where+	(.:..) x = \case NilL -> x :.. NilL; xs@(_ :.. _) -> x :.. xs++instance {-# OVERLAPPABLE #-} (1 <= n, PushL (n - 1) (m - 1)) => PushL n m where+	x .:.. y :. ys = x :. (y .:.. ys)++---------------------------------------------------------------------------+-- ADD+---------------------------------------------------------------------------++infixr 5 ++.++class AddL n m v w where+	(++.) :: RangeL n m a -> RangeL v w a -> RangeL (n + v) (m + w) a++	{-^++	To concatenate two lists+	whose types are @RangeL n m a@ and @RangeL v w a@.++	>>> :set -XDataKinds+	>>> sampleAddL1 = 'f' :. 'o' :. 'o' :.. NilL :: RangeL 2 5 Char+	>>> sampleAddL2 = 'b' :. 'a' :.. 'r' :.. NilL :: RangeL 1 6 Char+	>>> sampleAddL1 ++. sampleAddL2+	'f' :. ('o' :. ('o' :. ('b' :.. ('a' :.. ('r' :.. NilL)))))+	>>> :type sampleAddL1 ++. sampleAddL2+	sampleAddL1 ++. sampleAddL2 :: RangeL 3 11 Char++	-}++instance AddL 0 0 v w where NilL ++. ys = ys++instance {-# OVERLAPPABLE #-}+	(PushL v (m + w - 1), AddL 0 (m - 1) v w, LoosenLMax v w (m + w)) =>+	AddL 0 m v w where+	(++.) :: forall a .  RangeL 0 m a -> RangeL v w a -> RangeL v (m + w) a+	NilL ++. ys = loosenLMax ys+	x :.. xs ++. ys = x .:.. (xs ++. ys :: RangeL v (m + w - 1) a)++instance {-# OVERLAPPABLE #-}+	(1 <= n, AddL (n - 1) (m - 1) v w) => AddL n m v w where+	x :. xs ++. ys = x :. (xs ++. ys)++---------------------------------------------------------------------------+-- LOOSEN+---------------------------------------------------------------------------++-- LOOSEN LEFT++loosenL :: (LoosenLMin n m v, LoosenLMax v m w) => RangeL n m a -> RangeL v w a+loosenL = loosenLMax . loosenLMin++{-^++To loosen a range of an element number.++>>> :set -XDataKinds+>>> sampleLoosenL = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :.. NilL :: RangeL 4 6 Char+>>> loosenL sampleLoosenL :: RangeL 2 8 Char+'h' :. ('e' :. ('l' :.. ('l' :.. ('o' :.. NilL))))++-}++-- LOOSEN LEFT MIN++class LoosenLMin n m v where+	loosenLMin :: RangeL n m a -> RangeL v m a++	{-^++	To loosen a lower bound of an element number.++	>>> :set -XDataKinds -fno-warn-tabs+	>>> :{+		sampleLoosenLMin :: RangeL 4 6 Char+		sampleLoosenLMin = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :.. NilL+	:}++	>>> loosenLMin sampleLoosenLMin :: RangeL 2 6 Char+	'h' :. ('e' :. ('l' :.. ('l' :.. ('o' :.. NilL))))++	-}++instance LoosenLMin 0 m 0 where+	loosenLMin = \case NilL -> NilL; xs@(_ :.. _) -> xs++instance {-# OVERLAPPABLE #-}+	(1 <= n, LoosenLMin (n - 1) (m - 1) 0) => LoosenLMin n m 0 where+	loosenLMin (x :. xs) = x :.. loosenLMin xs+	+instance {-# OVERLAPPABLE #-}+	(1 <= n, LoosenLMin (n - 1) (m - 1) (v - 1)) => LoosenLMin n m v where+	loosenLMin (x :. xs) = x :. loosenLMin xs++-- LOOSEN LEFT MAX++class LoosenLMax n m w where+	loosenLMax :: RangeL n m a -> RangeL n w a++	{-^++	To loosen an upper bound of an element number.++	>>> :set -XDataKinds -fno-warn-tabs+	>>> :{+		sampleLoosenLMax :: RangeL 4 6 Char+		sampleLoosenLMax = 'h' :. 'e' :. 'l' :. 'l' :. 'o' :.. NilL+	:}++	>>> loosenLMax sampleLoosenLMax :: RangeL 4 8 Char+	'h' :. ('e' :. ('l' :. ('l' :. ('o' :.. NilL))))++	-}++instance LoosenLMax 0 0 w where loosenLMax NilL = NilL++instance {-# OVERLAPPABLE #-}+	LoosenLMax 0 (m - 1) (w - 1) => LoosenLMax 0 m w where+	loosenLMax = \case NilL -> NilL; (x :.. xs) -> x :.. loosenLMax xs++instance {-# OVERLAPPABLE #-}+	(1 <= n, LoosenLMax (n - 1) (m - 1) (w - 1)) => LoosenLMax n m w where+	loosenLMax (x :. xs) = x :. loosenLMax xs++---------------------------------------------------------------------------+-- UNFOLDR+---------------------------------------------------------------------------++-- CLASS++class Unfoldr n v w where+	unfoldrMRangeWithBase :: Monad m =>+		RangeL n w a -> m Bool -> m a -> m (RangeL v w a)++	{-^+	+	It is like @unfoldrMRange@. But it has already prepared values.++	>>> :set -XDataKinds+	>>> :module + Data.IORef+	>>> r <- newIORef 1+	>>> check = (< 3) <$> readIORef r+	>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+	>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer+	>>> unfoldrMRangeWithBase xs check count :: IO (RangeL 3 5 Integer)+	123 :. (456 :. (3 :. (6 :.. NilL)))+	+	-}++	unfoldrMRangeMaybeWithBase :: Monad m =>+		RangeL n w a -> m Bool -> m a -> m (Maybe (RangeL v w a))++	{-^+	+	It is like @unfoldrMRangeMaybe@.+	But it has already prepared values.++	>>> :set -XDataKinds -fno-warn-tabs+	>>> :module + Data.IORef+	>>> r <- newIORef 1+	>>> check = (< 3) <$> readIORef r+	>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+	>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer+	>>> :{+		unfoldrMRangeMaybeWithBase xs check count+			:: IO (Maybe (RangeL 3 5 Integer))+	:}+	Just (123 :. (456 :. (3 :. (6 :.. NilL))))+	+	-}++-- INSTANCE++instance Unfoldr 0 0 0 where+	unfoldrMRangeWithBase NilL _ _ = pure NilL+	unfoldrMRangeMaybeWithBase NilL p _ = bool (Just NilL) Nothing <$> p++instance {-# OVERLAPPABLE #-} Unfoldr 0 0 (w - 1) => Unfoldr 0 0 w where+	unfoldrMRangeWithBase NilL p f =+		(p >>=) . bool (pure NilL) $ f >>= \x ->+			(x :..) <$> unfoldrMRangeWithBase NilL p f+	unfoldrMRangeWithBase (x :.. xs) p f =+		(x :..) <$> unfoldrMRangeWithBase xs p f++	unfoldrMRangeMaybeWithBase NilL p f =+		(p >>=) . bool (pure $ Just NilL) $ f >>= \x ->+			((x :..) <$>) <$> unfoldrMRangeMaybeWithBase NilL p f+	unfoldrMRangeMaybeWithBase (x :.. xs) p f =+		((x :..) <$>) <$> unfoldrMRangeMaybeWithBase xs p f++instance {-# OVERLAPPABLE #-}+	Unfoldr 0 (v - 1) (w - 1) => Unfoldr 0 v w where+	unfoldrMRangeWithBase NilL p f =+		f >>= \x -> (x :.) <$> unfoldrMRangeWithBase NilL p f+	unfoldrMRangeWithBase (x :.. xs) p f =+		(x :.) <$> unfoldrMRangeWithBase xs p f++	unfoldrMRangeMaybeWithBase NilL p f =+		(p >>=) . bool (pure Nothing) $ f >>= \x ->+			((x :.) <$>) <$> unfoldrMRangeMaybeWithBase NilL p f+	unfoldrMRangeMaybeWithBase (x :.. xs) p f =+		((x :.) <$>) <$> unfoldrMRangeMaybeWithBase xs p f++instance {-# OVERLAPPABLE #-}+	(1 <= n, Unfoldr (n - 1) (v - 1) (w - 1)) => Unfoldr n v w where+	unfoldrMRangeWithBase (x :. xs) p f =+		(x :.) <$> unfoldrMRangeWithBase xs p f++	unfoldrMRangeMaybeWithBase (x :. xs) p f =+		((x :.) <$>) <$> unfoldrMRangeMaybeWithBase xs p f++-- UNFOLDR RANGE++unfoldrRange :: Unfoldr 0 v w =>+	(s -> Bool) -> (s -> (a, s)) -> s -> RangeL v w a+unfoldrRange = unfoldrRangeWithBase NilL++{-^++To evaluate a function to construct a list.+The function recieve a state and return an element and a new state.+First argument is a predication which is evaluated+when an element number is greater than a minimum and not greater than a maximum.++>>> :set -XDataKinds+>>> next n = (n * 3, n + 1)+>>> unfoldrRange (< 2) next 1 :: RangeL 3 5 Int+3 :. (6 :. (9 :. NilL))++>>> unfoldrRange (< 5) next 1 :: RangeL 3 5 Int+3 :. (6 :. (9 :. (12 :.. NilL)))++>>> unfoldrRange (< 10) next 1 :: RangeL 3 5 Int+3 :. (6 :. (9 :. (12 :.. (15 :.. NilL))))++-}++unfoldrRangeWithBase :: Unfoldr n v w =>+	RangeL n w a -> (s -> Bool) -> (s -> (a, s)) -> s -> RangeL v w a+unfoldrRangeWithBase xs p f = fst . unfoldrRangeWithBaseWithS xs p f++{-^++It is like @unfoldrRange@. But it has already prepared values.++>>> :set -XDataKinds+>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer+>>> unfoldrRangeWithBase xs (< 3) (\n -> (n * 3, n + 1)) 1 :: RangeL 3 5 Integer+123 :. (456 :. (3 :. (6 :.. NilL)))++-}++unfoldrRangeWithBaseWithS :: Unfoldr n v w =>+	RangeL n w a -> (s -> Bool) -> (s -> (a, s)) -> s -> (RangeL v w a, s)+unfoldrRangeWithBaseWithS xs p f =+	runStateL $ unfoldrMRangeWithBase xs (StateL $ p &&& id) (StateL f)++{-^++It is like @unfoldrRangeWithBase@.+But it return not only a list but also a state value.++>>> :set -XDataKinds+>>> next n = (n * 3, n + 1)+>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Integer+>>> unfoldrRangeWithBaseWithS xs (< 3) next 1 :: (RangeL 3 5 Integer, Integer)+(123 :. (456 :. (3 :. (6 :.. NilL))),3)++-}++unfoldrMRange :: (Unfoldr 0 v w, Monad m) => m Bool -> m a -> m (RangeL v w a)+unfoldrMRange = unfoldrMRangeWithBase NilL++{-^++It is like @unfoldrRange@. But it use a monad instead of a function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldrMRange ((< 5) <$> readIORef r) count :: IO (RangeL 3 5 Integer)+3 :. (6 :. (9 :. (12 :.. NilL)))++-}++-- UNFOLDR RANGE MAYBE++unfoldrRangeMaybe :: Unfoldr 0 v w =>+	(s -> Maybe (a, s)) -> s -> Maybe (RangeL v w a)+unfoldrRangeMaybe = unfoldrRangeMaybeWithBase NilL++{-^++To eveluate a function to construct a list.+The function recieve a state and+return a nothing value or an element and a new state.+If number of created elements is less than a minimum number of list elements or+greater than a maximum number, then return Nothing.++>>> :set -XDataKinds+>>> next n0 n = if n < n0 then Just (n * 3, n + 1) else Nothing+>>> unfoldrRangeMaybe (next 2) 1 :: Maybe (RangeL 3 5 Int)+Nothing++>>> unfoldrRangeMaybe (next 5) 1 :: Maybe (RangeL 3 5 Int)+Just (3 :. (6 :. (9 :. (12 :.. NilL))))++>>> unfoldrRangeMaybe (next 10) 1 :: Maybe (RangeL 3 5 Int)+Nothing++-}++unfoldrRangeMaybeWithBase :: Unfoldr n v w =>+	RangeL n w a -> (s -> Maybe (a, s)) -> s -> Maybe (RangeL v w a)+unfoldrRangeMaybeWithBase xs f =+	fst . unfoldrRangeMaybeWithBaseGen xs (isJust &&& id)+		(maybe (error "never occur") (f `second`)) . f++{-^++It is like @unfoldrRangeMaybe@. But it has already prepared values.++>>> :set -XDataKinds+>>> xs = 123 :. 456 :.. NilL :: RangeL 1 5 Int+>>> next n = if n < 3 then Just (n * 3, n + 1) else Nothing+>>> unfoldrRangeMaybeWithBase xs next 1 :: Maybe (RangeL 3 5 Int)+Just (123 :. (456 :. (3 :. (6 :.. NilL))))++-}++type St a s r = Maybe (a, s) -> (r, Maybe (a, s))++unfoldrRangeMaybeWithBaseGen :: Unfoldr n v w =>+	RangeL n w a -> St a s Bool -> St a s a -> St a s (Maybe (RangeL v w a))+unfoldrRangeMaybeWithBaseGen xs p f =+	runStateL $ unfoldrMRangeMaybeWithBase xs (StateL p) (StateL f)++unfoldrMRangeMaybe :: (Unfoldr 0 v w, Monad m) =>+	m Bool -> m a -> m (Maybe (RangeL v w a))+unfoldrMRangeMaybe = unfoldrMRangeMaybeWithBase NilL++{-^++It is like @unfoldrRangeMaybe@.+But it use a monad instead of a function.+The first argument monad return boolean value.+It create values while this boolean value is True.+If this boolean value is False before to create enough values or+True after to create full values, then @unfoldrMRangeMaybe@ return Nothing.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> check n0 = (< n0) <$> readIORef r+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldrMRangeMaybe (check 2) count :: IO (Maybe (RangeL 3 5 Integer))+Nothing++>>> writeIORef r 1+>>> unfoldrMRangeMaybe (check 5) count :: IO (Maybe (RangeL 3 5 Integer))+Just (3 :. (6 :. (9 :. (12 :.. NilL))))++>>> writeIORef r 1+>>> unfoldrMRangeMaybe (check 10) count :: IO (Maybe (RangeL 3 5 Integer))+Nothing++-}++---------------------------------------------------------------------------+-- ZIP+---------------------------------------------------------------------------++-- CLASS++class ZipL n m v w where+	zipWithML :: Monad q =>+		(a -> b -> q c) -> RangeL n m a -> RangeL v w b ->+		q (RangeL n m c, RangeL (v - m) (w - n) b)++	{-^++	It is like @zipWithL@.+	But it use a function which return a monad instead of a simple value.++	>>> :set -XDataKinds -fno-warn-tabs+	>>> ns = 1 :. 2 :. 3 :.. NilL :: RangeL 2 4 Int+	>>> :{+		cs :: RangeL 5 7 Char+		cs = 'a' :. 'b' :. 'c' :. 'd' :. 'e' :. 'f' :.. NilL+	:}++	>>> zipWithML (\n -> putStrLn . replicate n) ns cs+	a+	bb+	ccc+	(() :. (() :. (() :.. NilL)),'d' :. ('e' :.. ('f' :.. NilL)))++	-}++instance ZipL 0 0 v w where zipWithML _ NilL = pure . (NilL ,)++instance {-# OVERLAPPABLE #-} (+	1 <= v, LoosenLMin v w (v - m), LoosenLMax (v - m) (w - 1) w,+	ZipL 0 (m - 1) (v - 1) (w - 1) ) => ZipL 0 m v w where+	zipWithML _ NilL ys = pure (NilL, loosenLMin ys)+	zipWithML (%) (x :.. xs) (y :. ys) =+		x % y >>= \z -> ((z :..) *** loosenLMax) <$> zipWithML (%) xs ys++instance {-# OVERLAPPABLE #-} (+	1 <= n, 1 <= v, n <= w, m <= v,+	ZipL (n - 1) (m - 1) (v - 1) (w - 1) ) => ZipL n m v w where+	zipWithML (%) (x :. xs) (y :. ys) =+		x % y >>= \z -> ((z :.) `first`) <$> zipWithML (%) xs ys++-- FUNCTION++zipL :: ZipL n m v w => RangeL n m a -> RangeL v w b ->+	(RangeL n m (a, b), RangeL (v - m) (w - n) b)+zipL = zipWithL (,)++{-^++To recieve two lists and return a tuple list and rest of the second list.+The first list must be shorter or equal than the second list.++>>> :set -XDataKinds+>>> sampleZipL1 = 1 :. 2 :. 3 :.. NilL :: RangeL 2 4 Integer+>>> sampleZipL2 = 7 :. 6 :. 5 :. 4 :. 3 :. 2 :.. NilL :: RangeL 5 7 Integer+>>> zipL sampleZipL1 sampleZipL2+((1,7) :. ((2,6) :. ((3,5) :.. NilL)),4 :. (3 :.. (2 :.. NilL)))+>>> :type zipL sampleZipL1 sampleZipL2+zipL sampleZipL1 sampleZipL2+  :: (RangeL 2 4 (Integer, Integer), RangeL 1 5 Integer)++-}++zipWithL :: ZipL n m v w => (a -> b -> c) -> RangeL n m a -> RangeL v w b ->+	(RangeL n m c, RangeL (v - m) (w - n) b)+zipWithL op = (runIdentity .) . zipWithML ((Identity .) . op)++{-^++It is like @zipL@.+But it evaluate a function to make values instead of put together in tuples.++>>> :set -XDataKinds+>>> sampleZipWithL1 = 1 :. 2 :. 3 :.. NilL :: RangeL 2 4 Integer+>>> sampleZipWithL2 = 7 :. 6 :. 5 :. 4 :. 3 :. 2 :.. NilL :: RangeL 5 7 Integer+>>> zipWithL (+) sampleZipWithL1 sampleZipWithL2+(8 :. (8 :. (8 :.. NilL)),4 :. (3 :.. (2 :.. NilL)))+>>> :type zipWithL (+) sampleZipWithL1 sampleZipWithL2+zipWithL (+) sampleZipWithL1 sampleZipWithL2+  :: (RangeL 2 4 Integer, RangeL 1 5 Integer)++-}
+ src/Data/List/Range/RangeR.hs view
@@ -0,0 +1,627 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}+{-# LANGUAGE DataKinds, KindSignatures, TypeOperators #-}+{-# LANGUAGE GADTs, TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances,+	UndecidableInstances #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs -fplugin=Plugin.TypeCheck.Nat.Simple #-}++module Data.List.Range.RangeR (+	-- ** Type+	RangeR(..),+	-- ** PushR+	PushR, (.:++),+	-- ** AddR+	AddR, (+++),+	-- ** LoosenRMin and LoosenRMax+	-- *** loosenR+	loosenR,+	-- *** loosenRMin+	LoosenRMin, loosenRMin,+	-- *** loosenRMax+	LoosenRMax, loosenRMax,+	-- ** Unfoldl+	-- *** class+	Unfoldl,+	-- *** unfoldlRange+	-- **** without monad+	unfoldlRange, unfoldlRangeWithBase, unfoldlRangeWithBaseWithS,+	-- **** with monad+	unfoldlMRange, unfoldlMRangeWithBase,+	-- *** unfoldlRangeMaybe+	-- **** without monad+	unfoldlRangeMaybe, unfoldlRangeMaybeWithBase,+	-- **** with monad+	unfoldlMRangeMaybe, unfoldlMRangeMaybeWithBase,+	-- ** ZipR+	ZipR, zipR, zipWithR, zipWithMR ) where++import GHC.TypeNats (Nat, type (+), type (-), type (<=))+import GHC.Exts+import Control.Arrow (first, second, (***), (&&&))+import Control.Monad.Identity (Identity(..))+import Control.Monad.State (StateR(..))+import Data.Foldable+import Data.Bool (bool)+import Data.Maybe (isJust, fromMaybe)+-- import Data.String++---------------------------------------------------------------------------++-- * TYPE+--	+ RANGE RIGHT+--	+ INSTANCE FUNCTOR+--	+ INSTANCE FOLDABLE+-- * PUSH+-- * ADD+-- * LOOSEN+--	+ LOOSEN RIGHT+--	+ LOOSEN RIGHT MIN+--	+ LOOSEN RIGHT MAX+-- * UNFOLDL+--	+ CLASS+--	+ INSTANCE+--	+ UNFOLDL RANGE+--	+ UNFOLDL RANGE MAYBE+-- * ZIP+--	+ CLASS AND INSTANCE+--	+ FUNCTION++---------------------------------------------------------------------------+-- TYPE+---------------------------------------------------------------------------++-- RANGE RIGHT++data RangeR :: Nat -> Nat -> * -> * where+	NilR :: 0 <= m => RangeR 0 m a+	(:++) :: 1 <= m => RangeR 0 (m - 1) a -> a -> RangeR 0 m a+	(:+) :: (1 <= n, 1 <= m) =>+		RangeR (n - 1) (m - 1) a -> a -> RangeR n m a++{-^++@RangeR n m a@ is a list of type @a@ values whose element number is+at minimum @n@, and at maximum @m@.+You can push and pop an element from right.++>>> :set -XDataKinds+>>> sampleRangeR = NilR :++ 'h' :++ 'e' :+ 'l' :+ 'l' :+ 'o' :: RangeR 3 8 Char++-}++infixl 6 :+, :++++deriving instance Show a => Show (RangeR n m a)++-- INSTANCE FUNCTOR++instance Functor (RangeR 0 0) where _ `fmap` NilR = NilR++instance {-# OVERLAPPABLE #-}+	Functor (RangeR 0 (m - 1)) => Functor (RangeR 0 m) where+	fmap f = \case NilR -> NilR; xs :++ x -> (f <$> xs) :++ f x++instance {-# OVERLAPPABLE #-}+	(1 <= n, Functor (RangeR (n - 1) (m - 1))) => Functor (RangeR n m) where+	f `fmap` (xs :+ x) = (f <$> xs) :+ f x++-- INSTANCE FOLDABLE++instance Foldable (RangeR 0 0) where foldr _ z NilR = z++instance {-# OVERLAPPABLE #-}+	Foldable (RangeR 0 (m - 1)) => Foldable (RangeR 0 m) where+	foldr (-<) z = \case NilR -> z; xs :++ x -> foldr (-<) (x -< z) xs++instance {-# OVERLAPPABLE #-} (1 <= n, Foldable (RangeR (n - 1) (m - 1))) =>+	Foldable (RangeR n m) where+	foldr (-<) z (xs :+ x) = foldr (-<) (x -< z) xs++instance Applicative (RangeR 0 0) where pure _ = NilR; _ <*> _ = NilR++instance {-# OVERLAPPABLE #-} (1 <= n, Functor (RangeR n n), Applicative (RangeR (n - 1) (n - 1)), Unfoldl 0 n n) => Applicative (RangeR n n) where+	pure = unfoldlRange (const True) (\x -> (x, x))+	fs :+ f <*> xs :+ x = (fs <*> xs) :+ f x++instance {-# OVERLAPPABLE #-} (Functor (RangeR 0 m), Applicative (RangeR 0 (m - 1)), Unfoldl 0 0 m) => Applicative (RangeR 0 m) where+	pure = unfoldlRange (const True) (\x -> (x, x))+	NilR <*> _ = NilR+	_ <*> NilR = NilR+	fs :++ f <*> xs :++ x = (fs <*> xs) :++ f x++instance {-# OVERLAPPABLE #-} (1 <= n, Functor (RangeR n m), Applicative (RangeR (n - 1) (m - 1)), Unfoldl 0 n m) => Applicative (RangeR n m) where+	pure = unfoldlRange (const True) (\x -> (x, x))+	fs :+ f <*> xs :+ x = (fs <*> xs) :+ f x++instance Applicative (RangeR 0 0) => Monad (RangeR 0 0) where NilR >>= _ = NilR+++instance {-# OVERLAPPABLE #-} (1 <= n, Applicative (RangeR n n), Monad (RangeR (n - 1) (n - 1))) => Monad (RangeR n n) where+	xs :+ x >>= f = (xs >>= \z -> case f z of zs :+ _ -> zs) :+ y+		where _ :+ y = f x++-- INSTANCE ISSTRING++instance Unfoldl 0 n m => IsString (RangeR n m Char) where+	fromString s = fromMaybe (error $ "The string " ++ show s ++ " is not within range.")+		. unfoldlRangeMaybe (\case "" -> Nothing; c : cs -> Just (cs, c)) $ reverse s++instance (Foldable (RangeR n m), Unfoldl 0 n m) => IsList (RangeR n m a) where+	type Item (RangeR n m a) = a+	fromList lst = fromMaybe (error $ "The list is not within range.")+		. unfoldlRangeMaybe (\case [] -> Nothing; x : xs -> Just (xs, x)) $ reverse lst+	toList = Data.Foldable.toList++---------------------------------------------------------------------------+-- PUSH+---------------------------------------------------------------------------++infixl 5 .:++++class PushR n m where+	(.:++) :: RangeR n m a -> a -> RangeR n (m + 1) a++	{-^++	To push an optional element.++	>>> :set -XDataKinds+	>>> samplePushR = NilR :++ 'h' :+ 'e' :+ 'l' :+ 'l' :: RangeR 3 7 Char+	>>> samplePushR .:++ 'o'+	((((NilR :++ 'h') :++ 'e') :+ 'l') :+ 'l') :+ 'o'+	>>> :type samplePushR .:++ 'o'+	samplePushR .:++ 'o' :: RangeR 3 8 Char++	-}++instance PushR 0 m where+	(.:++) = \case NilR -> (NilR :++); xs@(_ :++ _) -> (xs :++)++instance {-# OVERLAPPABLE #-} (1 <= n, PushR (n - 1) (m - 1)) => PushR n m where+	xs :+ x .:++ y = (xs .:++ x) :+ y++---------------------------------------------------------------------------+-- ADD+---------------------------------------------------------------------------++infixl 5 +++++class AddR n m v w where+	(+++) :: RangeR n m a -> RangeR v w a -> RangeR (n + v) (m + w) a++	{-^++	To concatenate two lists whose types are @RangeR n m a@ and @RangeR v w a@.++	>>> :set -XDataKinds+	>>> sampleRangeR1 = NilR :++ 'f' :+ 'o' :+ 'o' :: RangeR 2 5 Char+	>>> sampleRangeR2 = NilR :++ 'b' :++ 'a' :+ 'r' :: RangeR 1 6 Char+	>>> sampleRangeR1 +++ sampleRangeR2+	(((((NilR :++ 'f') :++ 'o') :++ 'o') :+ 'b') :+ 'a') :+ 'r'+	>>> :type sampleRangeR1 +++ sampleRangeR2+	sampleRangeR1 +++ sampleRangeR2 :: RangeR 3 11 Char++	-}++instance AddR n m 0 0 where xs +++ NilR = xs++instance {-# OVERLAPPABLE #-}+	(PushR n (m + w - 1), AddR n m 0 (w - 1), LoosenRMax n m (m + w)) =>+	AddR n m 0 w where+	(+++) :: forall a . RangeR n m a -> RangeR 0 w a -> RangeR n (m + w) a+	(+++) xs = \case+		NilR -> loosenRMax xs+		ys :++ y -> (xs +++ ys :: RangeR n (m + w - 1) a) .:++ y++instance {-# OVERLAPPABLE #-}+	(1 <= v, AddR n m (v - 1) (w - 1)) => AddR n m v w where+	xs +++ ys :+ y = (xs +++ ys) :+ y++---------------------------------------------------------------------------+-- LOOSEN+---------------------------------------------------------------------------++-- LOOSEN RIGHT++loosenR :: (LoosenRMin n m v, LoosenRMax v m w) => RangeR n m a -> RangeR v w a+loosenR = loosenRMax . loosenRMin++{-^++To loosen a range of element number.++>>> :set -XDataKinds+>>> sampleLoosenR = NilR :++ 'h' :+ 'e' :+ 'l' :+ 'l' :+ 'o' :: RangeR 4 6 Char+>>> loosenR sampleLoosenR :: RangeR 2 8 Char+((((NilR :++ 'h') :++ 'e') :++ 'l') :+ 'l') :+ 'o'++-}++-- LOOSEN RIGHT MIN++class LoosenRMin n m v where+	loosenRMin :: RangeR n m a -> RangeR v m a++	{-^++	To loosen a lower bound of element number.++	>>> :set -XDataKinds -fno-warn-tabs+	>>> :{+		sampleLoosenRMin :: RangeR 4 6 Char+		sampleLoosenRMin = NilR :++ 'h' :+ 'e' :+ 'l' :+ 'l' :+ 'o'+	:}++	>>> loosenRMin sampleLoosenRMin :: RangeR 2 6 Char+	((((NilR :++ 'h') :++ 'e') :++ 'l') :+ 'l') :+ 'o'++	-}++instance LoosenRMin 0 m 0 where+	loosenRMin = \case NilR -> NilR; xs@(_ :++ _) -> xs++instance {-# OVERLAPPABLE #-}+	(1 <= n, LoosenRMin (n - 1) (m - 1) 0) => LoosenRMin n m 0 where+	loosenRMin (xs :+ x) = loosenRMin xs :++ x++instance {-# OVERLAPPABLE #-}+	(1 <= n, LoosenRMin (n - 1) (m - 1) (v - 1)) => LoosenRMin n m v where+	loosenRMin (xs :+ x) = loosenRMin xs :+ x++-- LOOSEN RIGHT MAX++class LoosenRMax n m w where+	loosenRMax :: RangeR n m a -> RangeR n w a++	{-^++	To loosen an upper bound of element number.++	>>> :set -XDataKinds -fno-warn-tabs+	>>> :{+		sampleLoosenRMax :: RangeR 4 6 Char+		sampleLoosenRMax = NilR :++ 'h' :+ 'e' :+ 'l' :+ 'l' :+ 'o'+	:}++	>>> loosenRMax sampleLoosenRMax :: RangeR 4 8 Char+	((((NilR :++ 'h') :+ 'e') :+ 'l') :+ 'l') :+ 'o'++	-}++instance LoosenRMax 0 0 m where loosenRMax NilR = NilR++instance {-# OVERLAPPABLE #-}+	LoosenRMax 0 (m - 1) (w - 1) => LoosenRMax 0 m w where+	loosenRMax = \case NilR -> NilR; xs :++ x -> loosenRMax xs :++ x++instance {-# OVERLAPPABLE #-}+	(1 <= n, LoosenRMax (n - 1) (m - 1) (w - 1)) => LoosenRMax n m w where+	loosenRMax (xs :+ x) = loosenRMax xs :+ x++---------------------------------------------------------------------------+-- UNFOLDL+---------------------------------------------------------------------------++-- CLASS++class Unfoldl n v w where+	unfoldlMRangeWithBase :: Monad m =>+		m Bool -> m a -> RangeR n w a -> m (RangeR v w a)++	{-^++	It is like @unfoldlMRange@. But it has already prepared values.++	>>> :set -XDataKinds+	>>> :module + Data.IORef+	>>> r <- newIORef 1+	>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+	>>> xs = NilR :++ 123 :+ 456 :: RangeR 1 5 Integer+	>>> :{+		unfoldlMRangeWithBase ((< 3) <$> readIORef r) count xs+			:: IO (RangeR 3 5 Integer)+	:}+	(((NilR :++ 6) :+ 3) :+ 123) :+ 456++	-}++	unfoldlMRangeMaybeWithBase :: Monad m =>+		m Bool -> m a -> RangeR n w a -> m (Maybe (RangeR v w a))++	{-^++	It is like @unfoldrMRangeMaybe@. But it has already prepared values.++	>>> :set -XDataKinds+	>>> :module + Data.IORef+	>>> r <- newIORef 1+	>>> check = (< 3) <$> readIORef r+	>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+	>>> xs = NilR :++ 123 :+ 456 :: RangeR 1 5 Integer+	>>> :{+		unfoldlMRangeMaybeWithBase check count xs+			:: IO (Maybe (RangeR 3 5 Integer))+	:}+	Just ((((NilR :++ 6) :+ 3) :+ 123) :+ 456)++	-}++-- INSTANCE++instance Unfoldl 0 0 0 where+	unfoldlMRangeWithBase _ _ NilR = pure NilR+	unfoldlMRangeMaybeWithBase p _ NilR = bool (Just NilR) Nothing <$> p++instance {-# OVERLAPPABLE #-} Unfoldl 0 0 (w - 1) => Unfoldl 0 0 w where+	unfoldlMRangeWithBase p f = \case+		NilR -> (p >>=) . bool (pure NilR) $ f >>= \x ->+			(:++ x) <$> unfoldlMRangeWithBase p f NilR+		xs :++ x -> (:++ x) <$> unfoldlMRangeWithBase p f xs++	unfoldlMRangeMaybeWithBase p f = \case+		NilR -> (p >>=) . bool (pure $ Just NilR) $ f >>= \x ->+			((:++ x) <$>) <$> unfoldlMRangeMaybeWithBase p f NilR+		xs :++ x -> ((:++ x) <$>) <$> unfoldlMRangeMaybeWithBase p f xs++instance {-# OVERLAPPABLE #-} Unfoldl 0 (v - 1) (w - 1) => Unfoldl 0 v w where+	unfoldlMRangeWithBase p f = \case+		NilR -> f >>= \x -> (:+ x) <$> unfoldlMRangeWithBase p f NilR+		xs :++ x -> (:+ x) <$> unfoldlMRangeWithBase p f xs++	unfoldlMRangeMaybeWithBase p f = \case+		NilR -> (p >>=) . bool (pure Nothing) $ f >>= \x ->+			((:+ x) <$>) <$> unfoldlMRangeMaybeWithBase p f NilR+		xs :++ x -> ((:+ x) <$>) <$> unfoldlMRangeMaybeWithBase p f xs++instance {-# OVERLAPPABLE #-}+	(1 <= n, Unfoldl (n - 1) (v - 1) (w - 1)) => Unfoldl n v w where+	unfoldlMRangeWithBase p f (xs :+ x) =+		(:+ x) <$> unfoldlMRangeWithBase p f xs++	unfoldlMRangeMaybeWithBase p f (xs :+ x) =+		((:+ x) <$>) <$> unfoldlMRangeMaybeWithBase p f xs++-- UNFOLDL RANGE++unfoldlRange :: Unfoldl 0 v w =>+	(s -> Bool) -> (s -> (s, a)) -> s -> RangeR v w a+unfoldlRange p f s = unfoldlRangeWithBase p f s NilR++{-^++To eveluate a function to construct a list.+The function recieve a state and return an element and a new state.+The first argument is a predication which is evaluated when an element number is+greater than a minimum and not greater than a maximum.++>>> :set -XDataKinds+>>> unfoldlRange (< 2) (\n -> (n + 1, n * 3)) 1 :: RangeR 3 5 Int+((NilR :+ 9) :+ 6) :+ 3++>>> unfoldlRange (< 5) (\n -> (n + 1, n * 3)) 1 :: RangeR 3 5 Int+(((NilR :++ 12) :+ 9) :+ 6) :+ 3++>>> unfoldlRange (< 10) (\n -> (n + 1, n * 3)) 1 :: RangeR 3 5 Int+((((NilR :++ 15) :++ 12) :+ 9) :+ 6) :+ 3++-}++unfoldlRangeWithBase :: Unfoldl n v w =>+	(s -> Bool) -> (s -> (s, a)) -> s -> RangeR n w a -> RangeR v w a+unfoldlRangeWithBase p f = (snd .) . unfoldlRangeWithBaseWithS p f++{-^++It is like @unfoldlRange@. But it has already prepared values.++>>> :set -XDataKinds+>>> xs = NilR :++ 123 :+ 456 :: RangeR 1 5 Integer+>>> unfoldlRangeWithBase (< 3) (\n -> (n + 1, n * 3)) 1 xs :: RangeR 3 5 Integer+(((NilR :++ 6) :+ 3) :+ 123) :+ 456++-}++unfoldlRangeWithBaseWithS :: Unfoldl n v w =>+	(s -> Bool) -> (s -> (s, a)) -> s -> RangeR n w a -> (s, RangeR v w a)+unfoldlRangeWithBaseWithS p f =+	flip $ runStateR . unfoldlMRangeWithBase (StateR $ id &&& p) (StateR f)++{-^++It is like @unfoldlRangeWithBase@.+But it return not only a list but also a state value.++>>> :set -XDataKinds -fno-warn-tabs+>>> xs = NilR :++ 123 :+ 456 :: RangeR 1 5 Integer+>>> :{+	unfoldlRangeWithBaseWithS (< 3) (\n -> (n + 1, n * 3)) 1 xs+		:: (Integer, RangeR 3 5 Integer)+:}+(3,(((NilR :++ 6) :+ 3) :+ 123) :+ 456)++-}++unfoldlMRange :: (Unfoldl 0 v w, Monad m) => m Bool -> m a -> m (RangeR v w a)+unfoldlMRange p f = unfoldlMRangeWithBase p f NilR++{-^++It is like @unfoldlRange@. But it use a monad instead of a function.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldlMRange ((< 5) <$> readIORef r) count :: IO (RangeR 3 5 Integer)+(((NilR :++ 12) :+ 9) :+ 6) :+ 3++-}++-- UNFOLDL RANGE MAYBE++unfoldlRangeMaybe ::+	Unfoldl 0 v w => (s -> Maybe (s, a)) -> s -> Maybe (RangeR v w a)+unfoldlRangeMaybe f s = unfoldlRangeMaybeWithBase f s NilR++{-^++To evaluate a function to construct a list.+The function recieves a state and+return a nothing value or an element and a new state.+If the number of created elements is+less than a minimum number of list elements or+greater than a maximum number, then return @Nothing@.++>>> :set -XDataKinds+>>> count n0 n = if n < n0 then Just (n + 1, n * 3) else Nothing+>>> unfoldlRangeMaybe (count 2) 1 :: Maybe (RangeR 3 5 Int)+Nothing++>>> unfoldlRangeMaybe (count 5) 1 :: Maybe (RangeR 3 5 Int)+Just ((((NilR :++ 12) :+ 9) :+ 6) :+ 3)++>>> unfoldlRangeMaybe (count 10) 1 :: Maybe (RangeR 3 5 Int)+Nothing++-}++unfoldlRangeMaybeWithBase :: Unfoldl n v w =>+	(s -> Maybe (s, a)) -> s -> RangeR n w a -> Maybe (RangeR v w a)+unfoldlRangeMaybeWithBase f s xs =+	snd $ unfoldlRangeMaybeWithBaseGen (id &&& isJust)+		(maybe (error "never occur") (f `first`)) xs (f s)++{-^++It is like @unfoldlRangeMaybe@. But it has already prepared values.++>>> :set -XDataKinds+>>> count n = if n < 3 then Just (n + 1, n * 3) else Nothing+>>> xs = NilR :++ 123 :+ 456 :: RangeR 1 5 Int+>>> unfoldlRangeMaybeWithBase count 1 xs :: Maybe (RangeR 3 5 Int)+Just ((((NilR :++ 6) :+ 3) :+ 123) :+ 456)++-}++type St s a r = Maybe (s, a) -> (Maybe (s, a), r)++unfoldlRangeMaybeWithBaseGen :: Unfoldl n v w =>+	St s a Bool -> St s a a -> RangeR n w a -> St s a (Maybe (RangeR v w a))+unfoldlRangeMaybeWithBaseGen p f =+	runStateR . unfoldlMRangeMaybeWithBase (StateR p) (StateR f)++unfoldlMRangeMaybe :: (Unfoldl 0 v w, Monad m) =>+	m Bool -> m a -> m (Maybe (RangeR v w a))+unfoldlMRangeMaybe p f = unfoldlMRangeMaybeWithBase p f NilR++{-^++It is like @unfoldlRangeMaybe@. But it use a monad instead of a function.+The first argument monad returns a boolean value.+It creates values while this boolean value is @True@.+If this boolean value is @False@ before to create enough values or+@True@ after to create full values, then @unfoldlMRangeMaybe@ returns Nothing.++>>> :set -XDataKinds+>>> :module + Data.IORef+>>> r <- newIORef 1+>>> check n0 = (< n0) <$> readIORef r+>>> count = readIORef r >>= \n -> n * 3 <$ writeIORef r (n + 1)+>>> unfoldlMRangeMaybe (check 2) count :: IO (Maybe (RangeR 3 5 Integer))+Nothing++>>> writeIORef r 1+>>> unfoldlMRangeMaybe (check 5) count :: IO (Maybe (RangeR 3 5 Integer))+Just ((((NilR :++ 12) :+ 9) :+ 6) :+ 3)++>>> writeIORef r 1+>>> unfoldlMRangeMaybe (check 10) count :: IO (Maybe (RangeR 3 5 Integer))+Nothing++-}++---------------------------------------------------------------------------+-- ZIP+---------------------------------------------------------------------------++-- CLASS AND INSTANCE++class ZipR n m v w where+	zipWithMR :: Monad q =>+		(a -> b -> q c) -> RangeR n m a -> RangeR v w b ->+		q (RangeR (n - w) (m - v) a, RangeR v w c)++	{-^++	It is like @zipWithR@.+	But it uses a function which returns a monad instead of a simple value.++	>>> :set -XDataKinds+	>>> ns = NilR :++ 1 :+ 2 :+ 3 :+ 4 :+ 5 :+ 6 :: RangeR 5 7 Int+	>>> cs = NilR :++ 'a' :+ 'b' :+ 'c' :: RangeR 2 4 Char+	>>> zipWithMR (\n -> putStrLn . replicate n) ns cs+	cccccc+	bbbbb+	aaaa+	(((NilR :++ 1) :++ 2) :+ 3,((NilR :++ ()) :+ ()) :+ ())++	-}++instance ZipR n m 0 0 where zipWithMR _ xs NilR = pure (xs, NilR)++instance {-# OVERLAPPABLE #-} (+	1 <= n, LoosenRMin n m (n - w), LoosenRMax (n - w) (m - 1) m,+	ZipR (n - 1) (m - 1) 0 (w - 1) ) => ZipR n m 0 w where+	zipWithMR _ xs NilR = pure (loosenRMin xs, NilR)+	zipWithMR (%) (xs :+ x) (ys :++ y) =+		x % y >>= \z -> (loosenRMax *** (:++ z)) <$> zipWithMR (%) xs ys++instance {-# OVERLAPPABLE #-} (+	1 <= n, 1 <= v, v <= m, w <= n,+	ZipR (n - 1) (m - 1) (v - 1) (w - 1) ) => ZipR n m v w where+	zipWithMR (%) (xs :+ x) (ys :+ y) =+		x % y >>= \z -> ((:+ z) `second`) <$> zipWithMR (%) xs ys++-- FUNCTION++zipR :: ZipR n m v w => RangeR n m a -> RangeR v w b ->+	(RangeR (n - w) (m - v) a, RangeR v w (a, b))+zipR = zipWithR (,)++{-^++To recieve two lists and return a tuple list and rest of the first list.+The second list must be shorter or equal than the first list.++>>> :set -XDataKinds+>>> sampleZipR1 = NilR :++ 1 :+ 2 :+ 3 :+ 4 :+ 5 :+ 6 :: RangeR 5 7 Integer+>>> sampleZipR2 = NilR :++ 3 :+ 2 :+ 1 :: RangeR 2 4 Integer+>>> zipR sampleZipR1 sampleZipR2+(((NilR :++ 1) :++ 2) :+ 3,((NilR :++ (4,3)) :+ (5,2)) :+ (6,1))+>>> :type zipR sampleZipR1 sampleZipR2+zipR sampleZipR1 sampleZipR2+  :: (RangeR 1 5 Integer, RangeR 2 4 (Integer, Integer))++-}++zipWithR :: ZipR n m v w => (a -> b -> c) -> RangeR n m a -> RangeR v w b ->+	(RangeR (n - w) (m - v) a, RangeR v w c)+zipWithR op = (runIdentity .) . zipWithMR ((Identity .) . op)++{-^++It is like @zipR@.+But it evaluates a function to make values instead of puts together in tuples.++>>> :set -XDataKinds+>>> sampleZipWithR1 = NilR :++ 1 :+ 2 :+ 3 :+ 4 :+ 5 :+ 6 :: RangeR 5 7 Integer+>>> sampleZipWithR2 = NilR :++ 7 :+ 6 :+ 5 :: RangeR 2 4 Integer+>>> zipWithR (+) sampleZipWithR1 sampleZipWithR2+(((NilR :++ 1) :++ 2) :+ 3,((NilR :++ 11) :+ 11) :+ 11)+>>> :type zipWithR (+) sampleZipWithR1 sampleZipWithR2+zipWithR (+) sampleZipWithR1 sampleZipWithR2+  :: (RangeR 1 5 Integer, RangeR 2 4 Integer)++-}
+ test/doctests.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++module Main (main) where++import Test.DocTest++main :: IO ()+main = doctest [+	"-isrc",+	"src/Data/List/Length.hs",+	"src/Data/List/Range.hs",+	"src/Data/List/Range/Nat.hs" ]
+ test/spec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DataKinds #-}+{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}++import Data.Bits+import Data.Word++import Data.List.Length+import Data.List.Range++main :: IO ()+main = do+	print $ foo 123; putStrLn ""+	print $ bar 123; putStrLn ""+	print baz; putStrLn ""+	print hoge; putStrLn ""++foo :: Word32 -> LengthL 32 Bool+foo = unfoldr \w -> (w `testBit` 0, w `shiftR` 1)++bar :: Word32 -> LengthR 32 Bool+bar = unfoldl \w -> (w `shiftR` 1, w `testBit` 0)++baz :: (RangeL 2 3 (Integer, Integer), RangeL 1 6 Integer)+baz = zipWithL (,)+	(1 :. 2 :. 3 :.. NilL :: RangeL 2 3 Integer)+	(1 :. 2 :. 3 :. 4 :. 5 :.. NilL :: RangeL 4 8 Integer)++hoge :: (RangeR 1 6 Integer, RangeR 2 3 (Integer, Integer))+hoge = zipWithR (,)+	(NilR :++ 1 :+ 2 :+ 3 :+ 4 :+ 5 :: RangeR 4 8 Integer)+	(NilR :++ 1 :+ 2 :+ 3 :: RangeR 2 3 Integer)