module Math.OEIS.Internal where
import Control.Arrow (second, (***))
import Data.Char (isSpace, toUpper, toLower)
import Data.List (intercalate, isPrefixOf, foldl')
import Network.HTTP (simpleHTTP, rspBody, rspCode, rqBody, rqHeaders, rqMethod, rqURI, Request(..), RequestMethod(GET))
import Network.URI (parseURI, URI)
import Math.OEIS.Types
baseSearchURI :: String
baseSearchURI :: String
baseSearchURI = String
"http://oeis.org/search?fmt=text&q="
idSearchURI :: String -> String
idSearchURI :: String -> String
idSearchURI String
n = String
baseSearchURI String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"id:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
n
seqSearchURI :: SequenceData -> String
seqSearchURI :: SequenceData -> String
seqSearchURI SequenceData
xs = String
baseSearchURI String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ((Integer -> String) -> SequenceData -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Integer -> String
forall a. Show a => a -> String
show SequenceData
xs)
getOEIS :: (a -> String) -> a -> IO [OEISSequence]
getOEIS :: (a -> String) -> a -> IO [OEISSequence]
getOEIS a -> String
toURI a
key =
case String -> Maybe URI
parseURI (a -> String
toURI a
key) of
Maybe URI
Nothing -> [OEISSequence] -> IO [OEISSequence]
forall (m :: * -> *) a. Monad m => a -> m a
return []
Just URI
uri -> do
Maybe String
mbody <- URI -> IO (Maybe String)
get URI
uri
[OEISSequence] -> IO [OEISSequence]
forall (m :: * -> *) a. Monad m => a -> m a
return ([OEISSequence] -> IO [OEISSequence])
-> [OEISSequence] -> IO [OEISSequence]
forall a b. (a -> b) -> a -> b
$ [OEISSequence]
-> (String -> [OEISSequence]) -> Maybe String -> [OEISSequence]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] String -> [OEISSequence]
parseOEIS Maybe String
mbody
get :: URI -> IO (Maybe String)
get :: URI -> IO (Maybe String)
get URI
uri = do
Result (Response String)
ersp <- Request String -> IO (Result (Response String))
forall ty. HStream ty => Request ty -> IO (Result (Response ty))
simpleHTTP (URI -> Request String
request URI
uri)
Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe String -> IO (Maybe String))
-> Maybe String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ case Result (Response String)
ersp of
Left ConnError
_ -> Maybe String
forall a. Maybe a
Nothing
Right Response String
rsp
| Response String -> ResponseCode
forall a. Response a -> ResponseCode
rspCode Response String
rsp ResponseCode -> ResponseCode -> Bool
forall a. Eq a => a -> a -> Bool
== (Int
2,Int
0,Int
0) -> String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ Response String -> String
forall a. Response a -> a
rspBody Response String
rsp
| Bool
otherwise -> Maybe String
forall a. Maybe a
Nothing
request :: URI -> Request String
request :: URI -> Request String
request URI
uri = Request :: forall a. URI -> RequestMethod -> [Header] -> a -> Request a
Request
{ rqURI :: URI
rqURI = URI
uri
, rqMethod :: RequestMethod
rqMethod = RequestMethod
GET
, rqHeaders :: [Header]
rqHeaders = []
, rqBody :: String
rqBody = String
""
}
readKeyword :: String -> Keyword
readKeyword :: String -> Keyword
readKeyword = String -> Keyword
forall a. Read a => String -> a
read (String -> Keyword) -> (String -> String) -> String -> Keyword
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
capitalize
capitalize :: String -> String
capitalize :: String -> String
capitalize String
"" = String
""
capitalize (Char
c:String
cs) = Char -> Char
toUpper Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower String
cs
emptyOEIS :: OEISSequence
emptyOEIS :: OEISSequence
emptyOEIS = [String]
-> SequenceData
-> SequenceData
-> String
-> [String]
-> [String]
-> [String]
-> [String]
-> String
-> Int
-> Int
-> [(Language, String)]
-> [String]
-> [String]
-> [Keyword]
-> [String]
-> OEISSequence
OEIS [] [] [] String
"" [] [] [] [] String
"" Int
0 Int
0 [] [] [] [] []
addElement :: (Char, String) -> OEISSequence -> OEISSequence
addElement :: (Char, String) -> OEISSequence -> OEISSequence
addElement (Char
'I', String
x) OEISSequence
c = OEISSequence
c { catalogNums :: [String]
catalogNums = String -> [String]
words String
x }
addElement (Char
t, String
x) OEISSequence
c | Char
t Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"STU" = OEISSequence
c { sequenceData :: SequenceData
sequenceData = SequenceData
nums SequenceData -> SequenceData -> SequenceData
forall a. [a] -> [a] -> [a]
++ OEISSequence -> SequenceData
sequenceData OEISSequence
c }
where nums :: SequenceData
nums = (String -> Integer) -> [String] -> SequenceData
forall a b. (a -> b) -> [a] -> [b]
map String -> Integer
forall a. Read a => String -> a
read ([String] -> SequenceData) -> [String] -> SequenceData
forall a b. (a -> b) -> a -> b
$ String -> [String]
csvItems String
x
addElement (Char
t, String
x) OEISSequence
c | Char
t Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
"VWX" = OEISSequence
c { signedData :: SequenceData
signedData = SequenceData
nums SequenceData -> SequenceData -> SequenceData
forall a. [a] -> [a] -> [a]
++ OEISSequence -> SequenceData
signedData OEISSequence
c }
where nums :: SequenceData
nums = (String -> Integer) -> [String] -> SequenceData
forall a b. (a -> b) -> [a] -> [b]
map String -> Integer
forall a. Read a => String -> a
read ([String] -> SequenceData) -> [String] -> SequenceData
forall a b. (a -> b) -> a -> b
$ String -> [String]
csvItems String
x
addElement (Char
'N', String
x) OEISSequence
c = OEISSequence
c { description :: String
description = String
x }
addElement (Char
'D', String
x) OEISSequence
c = OEISSequence
c { references :: [String]
references = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
references OEISSequence
c }
addElement (Char
'H', String
x) OEISSequence
c = OEISSequence
c { links :: [String]
links = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
links OEISSequence
c }
addElement (Char
'F', String
x) OEISSequence
c = OEISSequence
c { formulas :: [String]
formulas = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
formulas OEISSequence
c }
addElement (Char
'Y', String
x) OEISSequence
c = OEISSequence
c { xrefs :: [String]
xrefs = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
xrefs OEISSequence
c }
addElement (Char
'A', String
x) OEISSequence
c = OEISSequence
c { author :: String
author = String
x }
addElement (Char
'O', String
x) OEISSequence
c = OEISSequence
c { offset :: Int
offset = String -> Int
forall a. Read a => String -> a
read String
o
, firstGT1 :: Int
firstGT1 = String -> Int
forall a. Read a => String -> a
read String
f }
where (String
o,String
f) = (String -> String) -> (String, String) -> (String, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second String -> String
forall a. [a] -> [a]
tail ((String, String) -> (String, String))
-> (String -> (String, String)) -> String -> (String, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
',') (String -> (String, String)) -> String -> (String, String)
forall a b. (a -> b) -> a -> b
$ String
x
addElement (Char
'p', String
x) OEISSequence
c = OEISSequence
c { programs :: [(Language, String)]
programs = (Language
Maple, String
x) (Language, String) -> [(Language, String)] -> [(Language, String)]
forall a. a -> [a] -> [a]
:
OEISSequence -> [(Language, String)]
programs OEISSequence
c }
addElement (Char
't', String
x) OEISSequence
c = OEISSequence
c { programs :: [(Language, String)]
programs = (Language
Mathematica, String
x) (Language, String) -> [(Language, String)] -> [(Language, String)]
forall a. a -> [a] -> [a]
:
OEISSequence -> [(Language, String)]
programs OEISSequence
c }
addElement (Char
'o', String
x) OEISSequence
c = OEISSequence
c { programs :: [(Language, String)]
programs = (Language
Other, String
x) (Language, String) -> [(Language, String)] -> [(Language, String)]
forall a. a -> [a] -> [a]
:
OEISSequence -> [(Language, String)]
programs OEISSequence
c }
addElement (Char
'E', String
x) OEISSequence
c = OEISSequence
c { extensions :: [String]
extensions = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
extensions OEISSequence
c }
addElement (Char
'e', String
x) OEISSequence
c = OEISSequence
c { examples :: [String]
examples = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
examples OEISSequence
c }
addElement (Char
'K', String
x) OEISSequence
c = OEISSequence
c { keywords :: [Keyword]
keywords = String -> [Keyword]
parseKeywords String
x }
addElement (Char
'C', String
x) OEISSequence
c = OEISSequence
c { comments :: [String]
comments = String
x String -> [String] -> [String]
forall a. a -> [a] -> [a]
: OEISSequence -> [String]
comments OEISSequence
c }
addElement (Char, String)
_ OEISSequence
c = OEISSequence
c
parseOEIS :: String -> [OEISSequence]
parseOEIS :: String -> [OEISSequence]
parseOEIS String
x = if String
"No results." String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` ([String]
ls[String] -> Int -> String
forall a. [a] -> Int -> a
!!Int
3)
then []
else [(Char, String)] -> [OEISSequence]
go ([(Char, String)] -> [OEISSequence])
-> ([String] -> [(Char, String)]) -> [String] -> [OEISSequence]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Char, String) -> Bool) -> [(Char, String)] -> [(Char, String)]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile ((Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'I') (Char -> Bool)
-> ((Char, String) -> Char) -> (Char, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char, String) -> Char
forall a b. (a, b) -> a
fst) ([(Char, String)] -> [(Char, String)])
-> ([String] -> [(Char, String)]) -> [String] -> [(Char, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [(Char, String)]
parseRawOEIS ([String] -> [OEISSequence]) -> [String] -> [OEISSequence]
forall a b. (a -> b) -> a -> b
$ [String]
ls'
where ls :: [String]
ls = String -> [String]
lines String
x
ls' :: [String]
ls' = [String] -> [String]
forall a. [a] -> [a]
init ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
drop Int
5 ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
ls
go :: [(Char, String)] -> [OEISSequence]
go [] = []
go ((Char, String)
i:[(Char, String)]
xs) = (OEISSequence -> (Char, String) -> OEISSequence)
-> OEISSequence -> [(Char, String)] -> OEISSequence
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (((Char, String) -> OEISSequence -> OEISSequence)
-> OEISSequence -> (Char, String) -> OEISSequence
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Char, String) -> OEISSequence -> OEISSequence
addElement) OEISSequence
emptyOEIS ([(Char, String)] -> [(Char, String)]
forall a. [a] -> [a]
reverse ((Char, String)
i(Char, String) -> [(Char, String)] -> [(Char, String)]
forall a. a -> [a] -> [a]
:[(Char, String)]
ys)) OEISSequence -> [OEISSequence] -> [OEISSequence]
forall a. a -> [a] -> [a]
: [(Char, String)] -> [OEISSequence]
go [(Char, String)]
zs
where ([(Char, String)]
ys, [(Char, String)]
zs) = ((Char, String) -> Bool)
-> [(Char, String)] -> ([(Char, String)], [(Char, String)])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break ((Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'I') (Char -> Bool)
-> ((Char, String) -> Char) -> (Char, String) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char, String) -> Char
forall a b. (a, b) -> a
fst) [(Char, String)]
xs
parseRawOEIS :: [String] -> [(Char, String)]
parseRawOEIS :: [String] -> [(Char, String)]
parseRawOEIS = (String -> (Char, String)) -> [String] -> [(Char, String)]
forall a b. (a -> b) -> [a] -> [b]
map String -> (Char, String)
parseItem ([String] -> [(Char, String)])
-> ([String] -> [String]) -> [String] -> [(Char, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> [String]
combineConts
parseKeywords :: String -> [Keyword]
parseKeywords :: String -> [Keyword]
parseKeywords = (String -> Keyword) -> [String] -> [Keyword]
forall a b. (a -> b) -> [a] -> [b]
map String -> Keyword
readKeyword ([String] -> [Keyword])
-> (String -> [String]) -> String -> [Keyword]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
csvItems
csvItems :: String -> [String]
csvItems :: String -> [String]
csvItems String
"" = []
csvItems String
x = String
item String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
others
where (String
item, String
rest) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
',') String
x
others :: [String]
others = String -> [String]
csvItems (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ Char -> String -> String
del Char
',' String
rest
del :: Char -> String -> String
del :: Char -> String -> String
del Char
_ String
"" = String
""
del Char
c (Char
x:String
xs) | Char
cChar -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
x = String
xs
| Bool
otherwise = Char
xChar -> String -> String
forall a. a -> [a] -> [a]
:String
xs
parseItem :: String -> (Char, String)
parseItem :: String -> (Char, String)
parseItem String
s = (Char
c, String
str)
where ( Char
'%':Char
c:String
_ , String
rest) = String -> (String, String)
splitWord String
s
(String
_, String
str ) = if Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'I' then (String
"", String
rest)
else String -> (String, String)
splitWord String
rest
combineConts :: [String] -> [String]
combineConts :: [String] -> [String]
combineConts (s :: String
s@(Char
'%':Char
_:String
_) : [String]
ss) =
(String -> [String] -> [String]) -> (String, [String]) -> [String]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (:) ((String, [String]) -> [String])
-> ([String] -> (String, [String])) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> [String] -> String
joinConts String
s ([String] -> String)
-> ([String] -> [String])
-> ([String], [String])
-> (String, [String])
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** [String] -> [String]
combineConts) (([String], [String]) -> (String, [String]))
-> ([String] -> ([String], [String]))
-> [String]
-> (String, [String])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break String -> Bool
isItem ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
ss
combineConts [String]
ss = [String]
ss
splitWord :: String -> (String, String)
splitWord :: String -> (String, String)
splitWord = (String -> String) -> (String, String) -> (String, String)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second String -> String
trimLeft ((String, String) -> (String, String))
-> (String -> (String, String)) -> String -> (String, String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isSpace
isItem :: String -> Bool
isItem :: String -> Bool
isItem String
x = Bool -> Bool
not (String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
x) Bool -> Bool -> Bool
&& Char
'%' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Char
forall a. [a] -> a
head String
x
joinConts :: String -> [String] -> String
joinConts :: String -> [String] -> String
joinConts String
s [String]
conts = String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> String
trimLeft [String]
conts
trimLeft :: String -> String
trimLeft :: String -> String
trimLeft = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace