oeis2 (empty) → 0.1.0
raw patch · 9 files changed
+660/−0 lines, 9 filesdep +QuickCheckdep +aesondep +basesetup-changed
Dependencies added: QuickCheck, aeson, base, containers, hspec, http-conduit, lens, lens-aeson, oeis2, text, vector
Files
- ChangeLog.md +3/−0
- LICENSE +30/−0
- README.md +65/−0
- Setup.hs +2/−0
- oeis2.cabal +69/−0
- src/Math/OEIS.hs +118/−0
- src/Math/OEIS/Internal.hs +220/−0
- src/Math/OEIS/Types.hs +78/−0
- test/Spec.hs +75/−0
+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for oeis++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Okkey (c) 2018++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 Okkey 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,65 @@+# oeis2++Haskell interface for [Online Encyclopedia of Integer Sequences](https://oeis.org/); homage to [oeis](http://hackage.haskell.org/package/oeis).++## Difference from [oeis](http://hackage.haskell.org/package/oeis)++- Source data of OEIS. + : [oeis](http://hackage.haskell.org/package/oeis) use `fmt=text`, but this library use `fmt=json`.+- Possible to get all search results.+- Search functions from ID or sub-sequence are merged.+- Possibele to search from **other** than ID or sub-sequence.+- Support for HTTPS.++## Usage++Add import statement.++```haskell+import Math.OEIS+```++- Get all search results from sub-sequence++ - If `n == 0`, you get all search results.++ ```haskell+ ghci>searchSeq (SubSeq [1,2,3,4]) 0+ [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...+ ghci>length it+ 53+ ```++ - Otherwise, you get first `n` search results.++ ```haskell+ ghci>searchSeq (SubSeq [1,2,3,4]) 17+ [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,8,9,+ ghci>length it+ 17+ ```++- Get first few terms from sub-sequence++ ```haskell+ ghci>getSeqData (SubSeq [1,2,2,3,3,3,4,4,4,4])+ Just [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,7,...+ ```++- Get Mathematica function from sub-sequence++ ```haskell+ ghci>mathematica <$> lookupSeq (SubSeq [1,2,2,3,3,3,4,4,4,4])+ Just ["a[1] = 1; a[n_] := a[n] = a[n - a[n - 1]] + 1 (* _Branko Curgus_, May 12 2009 *)","Table[n, {n, 13}, {n}] // Flatten (* _Robert G. Wilson v_, May 11 2010 *)"]+ ```++- If no search result++ ```haskell+ ghci>lookupSeq (ID "1145141919893")+ Nothing+ ```++## ToDo++- Could use other functions of the searching system written in [here](https://oeis.org/hints.html).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ oeis2.cabal view
@@ -0,0 +1,69 @@+-- This file has been generated from package.yaml by hpack version 0.28.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: dfea261a0cd8b7a597f5717df1093a6c7c1acf8250c469966c4c360b62652f15++name: oeis2+version: 0.1.0+synopsis: Interface for Online Encyclopedia of Integer Sequences (OEIS).+description: Please see the README on GitHub at <https://github.com/23_prime/oeis2#readme>+category: Math+homepage: https://github.com/23_prime/oeis2#readme+bug-reports: https://github.com/23_prime/oeis2/issues+author: okkey+maintainer: a23b23c23d23e@gmail.com+copyright: 2018 okkey+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10+extra-source-files:+ ChangeLog.md+ README.md++source-repository head+ type: git+ location: https://github.com/23_prime/oeis2++library+ exposed-modules:+ Math.OEIS+ Math.OEIS.Internal+ Math.OEIS.Types+ other-modules:+ Paths_oeis2+ hs-source-dirs:+ src+ build-depends:+ aeson >=1.3 && <1.5+ , base >=4.7 && <5+ , containers >=0.5 && <0.7+ , http-conduit >=2.3 && <2.4+ , lens >=4.16 && <4.18+ , lens-aeson >=1.0 && <1.1+ , text >=1.2 && <1.3+ , vector >=0.12 && <0.13+ default-language: Haskell2010++test-suite oeis2-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_oeis2+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ QuickCheck+ , aeson >=1.3 && <1.5+ , base >=4.7 && <5+ , containers >=0.5 && <0.7+ , hspec+ , http-conduit >=2.3 && <2.4+ , lens >=4.16 && <4.18+ , lens-aeson >=1.0 && <1.1+ , oeis2+ , text >=1.2 && <1.3+ , vector >=0.12 && <0.13+ default-language: Haskell2010
+ src/Math/OEIS.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE OverloadedLists #-}++module Math.OEIS (+ -- * Types+ SeqData,+ SearchStatus(..),+-- Language(..),+ Keyword(..),+ OEISSeq(..),++ -- * Functions+ searchSeq', searchSeq,+ lookupSeq', lookupSeq,+ getSeqData', getSeqData,+ extendSeq', extendSeq+ ) where++import Data.List+import Data.Maybe (fromMaybe, listToMaybe)+import qualified Data.Vector as V+import System.IO.Unsafe (unsafePerformIO)++import Math.OEIS.Internal+import Math.OEIS.Types+++-- | Get all search results on OEIS+--+-- e.g.+--+-- > ghci>searchSeq (ID "A000027") 0+-- > [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...+--+-- > ghci>searchSeq (SubSeq [1,2,3,4]) 0+-- > [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...+-- > ghci>length it+-- > 53+-- > ghci>searchSeq (SubSeq [1,2,3,4]) 17+-- > [OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,8,9,+-- > ghci>length it+-- > 17+--+-- > ghci>searchSeq (SubSeq [1,1,4,5,1,4,1,9,1,9,8,9,3]) 0+-- > []+searchSeq' :: SearchStatus -> Int -> IO (V.Vector OEISSeq)+searchSeq' ss bound = do+ results' <- getResults ss 0 bound []+ let seqs+ | V.null results' = []+ | otherwise = parseOEIS <$> results'+ return seqs++searchSeq :: SearchStatus -> Int -> V.Vector OEISSeq+searchSeq ss = unsafePerformIO . searchSeq' ss+++-- | Look up a sequence on OEIS.+--+-- e.g.+--+-- > ghci>lookupSeq (ID "A000027")+-- > Just (OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...+--+-- > ghci>lookupSeq (SubSeq [1,2,3,4])+-- > Just (OEIS {number = "A000027", ids = ["M0472","N0173"], seqData = [1,2,3,4,5,6,7,...+lookupSeq :: SearchStatus -> Maybe OEISSeq+lookupSeq = unsafePerformIO . lookupSeq'++-- | lookupSeq in IO+lookupSeq' :: SearchStatus -> IO (Maybe OEISSeq)+lookupSeq' ss = do+ result <- getResult ss 0+ return $ case result of+ Just result' -> Just $ parseOEIS result'+ _ -> Nothing+++-- | Get sub-sequence on OEIS.+--+-- e.g.+--+-- > ghci>getSeqData (ID "A000027")+-- > Just [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]+--+-- > ghci>getSeqData (SubSeq [1,2,3,4])+-- > Just [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]+--+getSeqData :: SearchStatus -> Maybe SeqData+getSeqData = unsafePerformIO . getSeqData'++-- | getSeqData in IO+getSeqData' :: SearchStatus -> IO (Maybe SeqData)+getSeqData' = ((seqData <$>) <$>) . lookupSeq'+++-- | Extend from sub-sequence.+--+-- e.g.+--+-- > ghci>extendSeq [1,2,3,4]+-- > [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]+--+-- > ghci> extendSeq [1,3,2,5,6,1,6]+-- > [1,3,2,5,6,1,6]+extendSeq :: SeqData -> SeqData+extendSeq = unsafePerformIO . extendSeq'++-- | extendSeq in IO+extendSeq' :: [Integer] -> IO [Integer]+extendSeq' [] = return []+extendSeq' sd = do+ oeis <- lookupSeq' (SubSeq sd)+ return $ case oeis of+ Just s -> extend sd (seqData s)+ _ -> sd+ where+ extend :: SeqData -> SeqData -> SeqData+ extend sd ext = fromMaybe sd . listToMaybe . filter (sd `isPrefixOf`) $ tails ext
+ src/Math/OEIS/Internal.hs view
@@ -0,0 +1,220 @@+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE OverloadedStrings #-}++module Math.OEIS.Internal where++import Control.Lens ((^?), (^?!))+import Control.Monad (when)+import Data.Aeson.Lens+import Data.Aeson.Types+import Data.Char+import Data.List+import Data.Maybe (fromJust, fromMaybe, isNothing)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO as T+import qualified Data.Vector as V+import Network.HTTP.Simple (getResponseBody, httpBS, parseRequest)+import System.IO.Unsafe (unsafePerformIO)++import Math.OEIS.Types+++---------------+-- JSON Keys --+---------------+intKeys = [+ "number", "offset", "references", "revision"+ ]+textKeys = [+ "id", "data", "name", "keyword", "author", "time", "created"+ ]+textsKeys = [+ "comment", "reference", "link", "formula", "example", "maple", "mathematica",+ "program", "xref", "ext"+ ]+keys = intKeys ++ textKeys ++ textsKeys :: Texts+++----------------+-- Text utils --+----------------+(+.+) = T.append+(.+) = T.cons+(+.) = T.snoc+++----------------------+-- Get JSON of OEIS --+----------------------+showSeqData :: SeqData -> T.Text+showSeqData = T.pack . tail . init . show++readSeqData :: String -> SeqData+readSeqData str = case reads ("[" ++ str ++ "]") of+ [(sd, "")] -> sd+ _ -> []++baseSearchURI :: T.Text+baseSearchURI = "https://oeis.org/search?fmt=json&q="++addPrefix :: SearchStatus -> T.Text+addPrefix (SubSeq ints) = "seq:" +.+ showSeqData ints+addPrefix ss = let (cst, txt) = T.breakOn " " $ T.pack $ show ss+ pref = T.toLower cst +.+ ":"+ txt' = T.init $ T.tail $ T.strip txt+ in pref +.+ txt'++searchURI :: SearchStatus -> T.Text+searchURI ss = baseSearchURI +.+ addPrefix ss++openURL :: T.Text -> IO T.Text+openURL x = T.decodeUtf8 . getResponseBody <$> (httpBS =<< parseRequest (T.unpack x))++getJSON :: SearchStatus -> Int -> IO T.Text+getJSON (Others txt) _ = return txt -- for test+getJSON ss n = openURL $ searchURI ss +.+ "&start=" +.+ T.pack (show n)+++----------------+-- Parse JSON --+----------------+-- Get all search results --+getResults :: SearchStatus -> Int -> Int -> V.Vector Value -> IO (V.Vector Value)+getResults ss start bound vs = do+ when (bound < 0) $ fail "Upper-bound number of search results mast be non-negative."+ jsn <- getJSON ss start+ let results' = jsn ^? key "results" . _Array+ results = case results' of+ Nothing -> return []+ Just vs' ->+ let len = length vs'+ start' = start + 10+ diff = case bound of+ 0 -> len+ _ -> bound - start+ in case ss of+ ID _ -> return vs'+ Others _ -> return vs'+ _ ->+ if bound /= 0 && diff <= 10 || len /= 10 then+ return $ vs V.++ V.take diff vs'+ else+ getResults ss start' bound $ vs V.++ vs'+ results++-- Get nth search result --+getResult :: SearchStatus -> Int -> IO (Maybe Value)+getResult ss n = do+ results <- getResults ss 0 (n + 1) []+ let result = results V.!? n+ return result++-- Get each data in result --+getData :: Value -> T.Text -> (T.Text, Maybe OEISData)+getData result k+ | k `elem` intKeys+ = let d = result ^? key k ._Integer+ in case d of+ Nothing -> (k, Nothing)+ _ ->+ case k of+ "number" -> let d' = T.pack $ show $ fromJust d+ len = T.length d'+ in (k, Just $ TXT $ 'A' .+ T.replicate (6 - len) "0" +.+ d')+ _ -> (k, INT <$> d)+ | k `elem` textKeys+ = let d = result ^? key k ._String+ in case d of+ Nothing -> (k, Nothing)+ _ ->+ case k of+ "keyword" -> (k, KEYS . map readKeyword . T.splitOn "," <$> d)+ "data" -> let d' = T.unpack $ '[' .+ fromJust d +. ']'+ in (k, Just $ SEQ (read d' :: SeqData))+ "id" -> (k, TXTS . T.splitOn " " <$> d)+ _ -> (k, TXT <$> d)+ | k `elem` textsKeys+ = let ds = result ^? key k . _Array+ in case ds of+ Nothing -> (k, Nothing)+ _ -> let ts = (\i -> result ^?! key k . nth i . _String) <$> [0..(len - 1)]+ len = fromJust $ length <$> ds+ in case k of+ "program" -> let prgs = parsePrograms emptyProgram [] ts+ in (k, Just $ PRGS prgs)+ _ -> (k, Just $ TXTS ts)+ | otherwise = (k, Nothing)++resultLen :: SearchStatus -> IO (Maybe Int)+resultLen ss = do+ jsn <- getJSON ss 0+ return $ fromInteger <$> jsn ^? key "count" . _Integer++emptyOEIS :: OEISSeq+emptyOEIS = OEIS "" [] [] "" [] [] [] [] [] [] [] [] [] [] 0 "" [] 0 0 "" ""++addElement :: OEISSeq -> (T.Text, Maybe OEISData) -> OEISSeq+addElement seq (k, Just (TXT t))+ = case k of+ "number" -> seq {number = t}+ "name" -> seq {name = t}+ "author" -> seq {author = t}+ "time" -> seq {time = t}+ "created" -> seq {created = t}+ _ -> seq+addElement seq (k, Just (TXTS ts))+ = case k of+ "id" -> seq {ids = ts}+ "comment" -> seq {comment = ts}+ "reference" -> seq {reference = ts}+ "link" -> seq {link = ts}+ "formula" -> seq {formula = ts}+ "example" -> seq {example = ts}+ "maple" -> seq {maple = ts}+ "mathematica" -> seq {mathematica = ts}+ "xref" -> seq {xref = ts}+ "ext" -> seq {ext = ts}+ _ -> seq+addElement seq (k, Just (INT n))+ = case k of+ "offset" -> seq {offset = n}+ "references" -> seq {references = n}+ "revision" -> seq {revision = n}+ _ -> seq+addElement seq ("data" , Just (SEQ s)) = seq {seqData = s}+addElement seq ("keyword", Just (KEYS ks)) = seq {keyword = ks}+addElement seq ("program", Just (PRGS ps)) = seq {program = ps}+addElement seq (_, _) = seq++parseOEIS :: Value -> OEISSeq+parseOEIS result = foldl' addElement emptyOEIS $ map (getData result) keys+++-- Parse Keyword --+readKeyword :: T.Text -> Keyword+readKeyword txt =+ let str = T.unpack $ capitalize txt+ in case reads str of+ [(kw, "")] -> kw+ _ -> Other++capitalize :: T.Text -> T.Text+capitalize "" = ""+capitalize cs = toUpper (T.head cs) .+ T.map toLower (T.tail cs)+++-- Parse Program --+emptyProgram = ("", []) :: Program++parsePrograms :: Program -> [Program] -> [T.Text] -> [Program]+parsePrograms _ prgs [] = prgs+parsePrograms (lang0, funcs) prgs (t : ts)+ | T.head t == '(' = let prgs' = prgs ++ [(lang, [func])]+ in parsePrograms (lang, [func]) prgs' ts+ | otherwise = let prgs' = init prgs ++ [(lang0, funcs ++ [t])]+ in parsePrograms (lang0, funcs ++ [t]) prgs' ts+ where+ (lang', func') = T.breakOn ")" t+ lang = T.tail lang'+ func = T.strip $ T.tail func'
+ src/Math/OEIS/Types.hs view
@@ -0,0 +1,78 @@+module Math.OEIS.Types where++import qualified Data.Text as T++type SeqData = [Integer]+type Texts = [T.Text]++-- Prefixes+{-+id: ref: program:+seq: link: xref:+signed: formula: keyword:+name: example: author:+offset: maple: extension:+comment: mathematica:+-}+data SearchStatus = ID T.Text+ | SubSeq SeqData+ | Signed T.Text+ | Name T.Text+ | Comment T.Text+ | Ref T.Text+ | Link T.Text+ | Formla T.Text+ | Example T.Text+ | Maple T.Text+ | Mathematica T.Text+ | Offset T.Text+ | Program T.Text+ | XRef T.Text+ | KeyWord T.Text+ | Author T.Text+ | Extension T.Text+ | Others T.Text+ deriving (Show, Eq)++--data Language = Haskell | PARI | L T.Text deriving (Show, Eq)+type Language = T.Text+type Program = (Language, [T.Text])++data Keyword = Base | Bref | Changed | Cofr | Cons | Core | Dead | Dumb | Dupe |+ Easy | Eigen | Fini | Frac | Full | Hard | More | Mult |+ New | Nice | Nonn | Obsc | Sign | Tabf | Tabl | Uned |+ Unkn | Walk | Word | Look | Other+ deriving (Eq, Show, Read)++data OEISData = INT Integer+ | SEQ SeqData+ | TXT T.Text+ | TXTS Texts+ | KEYS [Keyword]+ | PRGS [Program]+ deriving (Show)++data OEISSeq+ = OEIS { number :: T.Text,+ ids :: Texts,+ seqData :: SeqData,+ name :: T.Text,+ comment :: Texts,+ reference :: Texts,+ link :: Texts,+ formula :: Texts,+ example :: Texts,+ maple :: Texts,+ mathematica :: Texts,+ program :: [Program],+ xref :: Texts,+ keyword :: [Keyword],+ offset :: Integer,+ author :: T.Text,+ ext :: Texts,+ references :: Integer,+ revision :: Integer,+ time :: T.Text,+ created :: T.Text+ }+ deriving (Show, Eq, Read)
+ test/Spec.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE OverloadedStrings #-}++import Data.Aeson.Lens+import Data.Aeson.Types+import Data.List+import Data.Maybe (fromJust)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified Data.Vector as V+import System.IO+import System.IO.Unsafe (unsafePerformIO)+import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck.Gen++import Math.OEIS+import Math.OEIS.Internal+++main :: IO ()+main = do+ withFile "./test/docs/test.json" ReadMode $ \handle1 ->+ withFile "./test/docs/result.txt" ReadMode $ \handle2 -> do+ testJSON <- T.hGetContents handle1+ testResult' <- hGetContents handle2+ let testResult = read testResult' :: V.Vector OEISSeq+ hspec $ specSearchSeq testJSON testResult+ hspec specLookupSeq+ hspec specGetSeqData+ hspec specExtendSeq++specSearchSeq :: T.Text -> V.Vector OEISSeq -> Spec+specSearchSeq jsn seq = describe "Test for searchSeq" $ do+ it "Number of all search results" $+ length (searchSeq (SubSeq [1,2,2,3,3,3,4,4,4,4]) 0) `shouldBe`+ fromJust (unsafePerformIO $ resultLen (SubSeq [1,2,2,3,3,3,4,4,4,4]))+ it "Get some of search results" $+ searchSeq (Others jsn) 10 `shouldBe` seq+ it "No search results" $+ searchSeq (SubSeq [1, 2, 3, 6, 11, 23, 47, 106, 237]) 0 `shouldBe` V.empty++specLookupSeq :: Spec+specLookupSeq = describe "Test for lookupSeq" $ do+ it "Compare lookup by ID with by SubSeq" $+ lookupSeq (ID "A000027") `shouldBe` lookupSeq (SubSeq [1, 2, 3, 4, 5, 6, 7])+ prop "Compare lookup by ID with by SubSeq -2" $+ \x ->+ let rs = unsafePerformIO $ generate $ resize 5 $ vectorOf x $ choose (1, 10)+ seq1 = lookupSeq (SubSeq rs)+ num = maybe "" number seq1+ seq2 = lookupSeq (ID num)+ in seq2 `shouldBe` seq1+ it "Get Maple function" $+ maple <$> lookupSeq (ID "A000027") `shouldBe`+ Just ["A000027 := n->n; seq(A000027(n), n=1..100);"]+ it "No search results" $+ lookupSeq (SubSeq [1,3,4,5,4,3,6]) `shouldBe` Nothing++specGetSeqData :: Spec+specGetSeqData = describe "Test for getSeqData" $ do+ it "Get SeqData" $+ getSeqData (ID "A000027")`shouldBe` Just [1..77]+ it "No SeqData" $+ getSeqData (SubSeq [1,3,4,5,4,3,6]) `shouldBe` Nothing++specExtendSeq :: Spec+specExtendSeq = describe "Test for extendSeq" $ do+ prop "Extend Seq" $+ \x ->+ let rs = unsafePerformIO $ generate $ resize 5 $ vectorOf x $ choose (1, 10)+ seq = extendSeq rs+ in rs `isInfixOf` seq+ it "No extension" $+ extendSeq [1,3,4,5,4,3,6] `shouldBe` [1,3,4,5,4,3,6]+