public
Last active

type class Indexable

  • Download Gist
Indexable.hs
Haskell
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
 
module Indexable where
import qualified Data.Aeson as A
import qualified Data.HashMap.Strict as HM
import qualified Data.Map as M
import qualified Data.Vector as V
import Data.Text (Text, unpack)
import Data.Map (Map)
-- START this part only used to run test
import qualified Data.Attoparsec.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as L
import Data.Aeson (json')
import Str
-- END this part only used to run test
 
class Indexable a where
type Key a
type Value a
(!?) :: a -> Key a -> Maybe (Value a)
(!) :: a -> Key a -> Value a
x ! k = case x !? k of
Just v -> v
Nothing -> error "key not found"
-- Useful for recursive data types, Valu a = a
-- To chain lookup actions together
(?!?) :: Maybe a -> Key a -> Maybe (Value a)
Nothing ?!? _ = Nothing
Just x ?!? k = x !? k
 
instance Indexable [a] where
type Key [a] = Int
type Value [a] = a
(!) = (!!)
xs !? i | i < 0 = Nothing
[] !? _ = Nothing
(x:_) !? 0 = Just x
(_:xs) !? n = xs !? (n-1)
 
instance (Ord k) => Indexable (Map k v) where
type Key (Map k v) = k
type Value (Map k v) = v
(!) = (M.!)
(!?) = flip M.lookup
 
instance Indexable A.Value where
type Key (A.Value) = Text
type Value (A.Value) = A.Value
x !? k = case x of
A.Object o -> HM.lookup k o
A.Array a
| [(i, "")] <- reads (unpack k) -> a V.!? i
| otherwise -> Nothing
otherwise -> Nothing
 
main :: IO ()
main = do
let strMap = M.fromList [("one","1"),("two","2"),("three","3")]
let strList = ["1","2","3"]
let maybeJohn = toMaybeJson jsonStr
print $ maybeJohn ?!? "phoneNumber" ?!? "1" -- Just (Object (fromList [("number",String "646 555-4567"),("type",String "fax")]))
print $ strMap !? "two" -- Just "2"
print $ strMap ! "two" -- "2"
print $ strList !? 0 -- Just "1"
print $ strList ! 0 -- "1"
print $ strMap !? "no-exist" -- Nothing
print $ strList !? 100 -- Nothing
print $ strMap ! "no-exist" -- error
print $ strList ! 100 -- error
where
toMaybeJson :: L.ByteString -> Maybe A.Value
toMaybeJson = result2Maybe . L.parse json'
result2Maybe :: L.Result a -> Maybe a
result2Maybe (L.Done _ r) = Just r
result2Maybe _ = Nothing
jsonStr = [str|
{
"firstName": "John",
"lastName": "Smith",
"male": true,
"age": 25,
"address":
{
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber":
[
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
|]
 
-- Str.hs copies from http://www.haskell.org/haskellwiki/Poor_man's_here_document

TODO: make maybeJohn $! "phoneNumber" $! 1 possible

for $! :: Maybe Value -> Text -> Maybe Value, so maybeJohn $! "phoneNumber" $! "1"

"1" cannot be type checked, need to be improved.

What is Dependent Type?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.