I am trying to serialize a Contacts type but I am stuck at defining put and get?
import Control.Monad
import Data.Binary
type Name = String
type Address = String
data Contacts = Contacts [(Name, Address)] deriving (Show)
instance Binary Contacts where
put (Contacts [(n,a)]) = do ...
get = do ...
main :: IO ()
main = do
let c = Contacts [("gert","home")]
let e = encode c
let d = decode e
print d
Yes, you are stuck defining put and get. Does that answer your question?
type Name = String
type Address = String
data Contacts = Contacts [(Name, Address)] deriving (Show)
instance Binary Contacts
put (Contacts [(n,a)]) = do ...
get = do ...
Since there are already instances:
instance (Binary a) => Binary [a]
instance (Binary a, Binary b) => Binary (a,b)
instance Binary Char
You should just be able to trivially lift the underlying put and get routines:
instance Binary Contacts where
put (Contacts set) = put set
get = fmap Contacts get
So when you put contacts you just tell it to put the list of pairs of strings. When you want to deserialize the contacts you just get the underlying list and use the Contacts constructor.
Adding more simple examples to prevent other noobs from suffering like me :)
{-# LANGUAGE RecordWildCards #-}
import Data.Binary
type Name = String
type Address = String
type Phone = String
data Contacts = Contacts [(Name, Address)] deriving (Show)
instance Binary Contacts where
put (Contacts set) = put set
get = fmap Contacts get
data Contact = Contact { name :: Name, address :: Address, phone :: Phone } deriving (Show)
instance Binary Contact where
put Contact{..} = do put name; put address; put phone
get = do name <- get; address <- get; phone <- get; return Contact{..}
main :: IO ()
main = do
let c = Contacts [("gert","home"),("gert2","home2")]
let e = encode c
print e
let d = decode e
print (d:: Contacts)
let c' = Contact{name="gert",address="home",phone="test"}
let e' = encode c'
print e'
let d' = decode e'
print (d':: Contact)
Related
Can I force the use of keywords only when initializing a record in Haskell?
data Person
= Person
{
name :: String,
idnum :: String
}
deriving( Show )
main = putStrLn $ show $ Person "oren" "9200"
-- I want to only allow such initializations:
-- main = putStrLn $ show $ Person { name = "moish", idnum = "7400" }
(This is especially useful when two fields have the same type)
As far as I know, no.
Consider maybe the following solution?
newtype Name = Name String
newtype Idnum = Idnum String
data Person = Person { name :: Name, idnum :: Idnum }
Another possibility, worse in my opinion, is this:
module A (Person, name, idnum) where
data Person = Person
{ _name :: String
, _idnum :: String
}
name :: String -> (Person -> Person)
name n p = p { _name = n }
idnum :: String -> (Person -> Person)
idnum n p = p { _idnum = n }
emptyPerson :: Person
emptyPerson = Person "" ""
# in another module
module B
import A (Person, name, idnum)
myPerson = name "myname" . idnum "myidnum" $ emptyPerson
In this case there's no guarantee that both name and idnum get a value.
The fact that Person can always be used as a 'plain function' may turn out to be very useful. If you have, for instance, getName :: IO String and getIdnum :: IO String, then combining these to form a getPerson :: IO Person is concise: getPerson = Person <$> getName <*> getIdnum. This is only possible because we don't use record syntax here!
I am a Haskell newbie, and I am thinking about how I can modularize my Rest application, which essentially passes around a ReaderT everywhere. I have devised a primitive working example of how to do that (below) using ExistentialQuantification. In a comment to a relevant answer, user MathematicalOrchid claimed something similar to be an anti-pattern. Is this an anti-pattern? In newbie terms, can you explain why if so and show a better alternative?
{-# LANGUAGE ExistentialQuantification #-}
import Control.Monad.Reader
import Control.Monad.Trans
import Data.List (intersect)
data Config = Config Int Bool
data User = Jane | John | Robot deriving (Show)
listUsers = [Jane, John, Robot]
class Database d where
search :: d -> String -> IO [User]
fetch :: d -> Int -> IO (Maybe User)
data LiveDb = LiveDb
instance Database LiveDb where
search d q = return $ filter ((q==) . intersect q . show) listUsers
fetch d i = return $ if i<3 then Just $ listUsers!!i else Nothing
data TestDb = TestDb
instance Database TestDb where
search _ _ = return [Robot]
fetch _ _ = return $ Just Robot
data Context = forall d. (Database d) => Context {
db :: d
, config :: Config
}
liveContext = Context { db = LiveDb, config = Config 123 True }
testContext = Context { db = TestDb, config = Config 123 True }
runApi :: String -> ReaderT Context IO String
runApi query = do
Context { db = db } <- ask
liftIO . fmap show $ search db query
main = do
let q = "Jn"
putStrLn $ "searching users for " ++ q
liveResult <- runReaderT (runApi q) liveContext
putStrLn $ "live result " ++ liveResult
testResult <- runReaderT (runApi q) testContext
putStrLn $ "test result " ++ testResult
Edit: a working example based on the accepted answer
import Control.Monad.Reader
import Control.Monad.Trans
import Data.List (intersect)
data Config = Config Int Bool
data User = Jane | John | Robot deriving (Show)
listUsers = [Jane, John, Robot]
data Database = Database {
search :: String -> IO [User]
, fetch :: Int -> IO (Maybe User)
}
liveDb :: Database
liveDb = Database search fetch where
search q = return $ filter ((q==) . intersect q . show) listUsers
fetch i = return $ if i<3 then Just $ listUsers!!i else Nothing
testDb :: Database
testDb = Database search fetch where
search _ = return [Robot]
fetch _ = return $ Just Robot
data Context = Context {
db :: Database
, config :: Config
}
liveContext = Context { db = liveDb, config = Config 123 True }
testContext = Context { db = testDb, config = Config 123 True }
runApi :: String -> ReaderT Context IO String
runApi query = do
d <- fmap db $ ask
liftIO . fmap show $ search d $ query
main = do
let q = "Jn"
putStrLn $ "searching users for " ++ q
liveResult <- runReaderT (runApi q) liveContext
putStrLn $ "live result " ++ liveResult
testResult <- runReaderT (runApi q) testContext
putStrLn $ "test result " ++ testResult
When you pattern-match on a Context, you get in the db field a value of a type that you can never know precisely; all you're allowed to know about it is that it's a Database instance, and thus you can use that class' methods with it. But that means that, from the point of view of the Context type, the existential d type affords it no more capabilities than this type does:
-- The "record of methods" pattern
data Database =
Database { search :: String -> IO [User]
, fetch :: Int -> IO (Maybe User)
}
liveDb :: Database
liveDb = Database search fetch
where search d q = return $ filter ((q==) . intersect q . show) listUsers
fetch d i = return $ if i<3 then Just $ listUsers!!i else Nothing
testDb :: Database
testDb = Database search fetch
where search _ _ = return [Robot]
fetch _ _ = return (Just Robot)
data Context =
Context { db :: Database
, config :: Config
}
That's the core argument against using existential types in the manner that you've done—there is a completely equivalent alternative that doesn't require existential types.
The argument against existential types is quite simple (and strong): often, you can avoid both the existential type and type class machinery, and use plain functions instead.
This is clearly the case where your class has the form
class D a where
method1 :: a -> T1
method2 :: a -> T2
-- ...
as in the posted Database example, since its instances can be replaced by values in a plain record type
data D = {
method1 :: T1
, method2 :: T2
-- ...
}
This is, essentially, the solution by #LuisCasillas .
However, note that the above translation relies on types T1,T2 not to depend on a. What if this is not the case? E.g. what if we had
class Database d where
search :: d -> String -> [User]
fetch :: d -> Int -> Maybe User
insert :: d -> User -> d
The above is a "pure" (no-IO) interface to a database, also allowing updates through insert. An instance could then be
data LiveDb = LiveDb [User]
instance Database LiveDb where
search (LiveDb d) q = filter ((q==) . intersect q . show) d
fetch (LiveDb d) i = case drop i d of [] -> Nothing ; (x:_) -> Just x
insert (LiveDb d) u = LiveDb (u:d)
Note that here we do use the parameter d, unlike in the original case where it was a placeholder.
Can we do without classes and existentials here?
data Database =
Database { search :: String -> [User]
, fetch :: Int -> Maybe User
, insert :: User -> Database
}
Notice that above we are returning an abstract Database in insert. This interface is more general than the existential-classy one, since it allows insert to change the underlying representation for the database. I.e., insert could move from a list-based representation to a tree-based one. This is like having insert acting from the existentially-quantified Database to itself, instead of from a concrete instance to itself.
Anyway, let's write LiveDb in the record-style way:
liveDb :: Database
liveDb = Database (search' listUsers) (fetch' listUsers) (insert' listUsers)
where search' d q = filter ((q==) . intersect q . show) d
fetch' d i = case drop i d of [] -> Nothing ; (x:_) -> Just x
insert' d u = Database (search' d') (fetch' d') (insert' d')
where d' = u:d
listUsers = [Jane, John, Robot]
Above I had to pass the underlying state d to each function, and in insert I had to update such state.
Overall, I find the above more involved than the instance Database LiveDb methods, which require no state-passing. Surely, we can apply a little refactoring and clarify the code:
makeLiveDb :: [User] -> Database
makeLiveDb d = Database search fetch insert
where search q = filter ((q==) . intersect q . show) d
fetch i = case drop i d of [] -> Nothing ; (x:_) -> Just x
insert u = makeLiveDb (u:d)
liveDb :: Database
liveDb = makeLiveDb [Jane, John, Robot]
This is a bit better, yet not as simple than the plain instance. There is no straightforward winner in this case, and which style to use is a matter of personal preference.
Personally, I stay away from existentially-quantified classes as much as possible, since in many, many cases they lose to much simpler approaches. However, I'm not dogmatic about them, and allow myself to use the "anti-pattern" when the alternative starts becoming too clumsy.
As an alternative, one could use an external function working at the abstract level, only:
data Database =
Database { search :: String -> [User]
-- let's neglect other methods for simplicity's sake
}
insert :: Database -> User -> Database
insert (Database s) u = Database s'
where s' str = s str ++ [ u | show u == str ] -- or something similar
The advantage of doing this is that insert works on the abstract Database, whatever its underlying data structure is. The disadvantage is that, in this way, insert can only access the database through its "methods", and can only work by building closures upon closures. If we also implemented a remove method, applying insert and delete many times will cause a larger and larger memory footprint, since remove can not remove the element from the underlying data structure, but can only build yet another closure which skips over the removed element. More pragmatically, it would be as if insert and remove simply appended to a log, and search scanned the log to see if the most recent action on an element was an insertion or a removal. This will not have a great performance.
(src http://hackage.haskell.org/packages/archive/safecopy/0.6.1/doc/html/Data-SafeCopy.html)
If you rename Contacts data type into data Contacts_v0
type Name = String
type Address = String
data Contacts = Contacts [(Name, Address)]
instance SafeCopy Contacts where
putCopy (Contacts list) = contain $ safePut list
getCopy = contain $ Contacts <$> safeGet
How is Contacts_v0 suppose to be assigned to old existing data?
type Name = String
type Address = String
type Phone = String
data Contacts_v0 = Contacts_v0 [(Name, Address)]
instance SafeCopy Contacts_v0 where
putCopy (Contacts_v0 list) = contain $ safePut list
getCopy = contain $ Contacts_v0 <$> safeGet
data Contact = Contact { name :: Name
, address :: Address
, phone :: Phone }
instance SafeCopy Contact where
putCopy Contact{..} = contain $ do safePut name; safePut address; safePut phone
getCopy = contain $ Contact <$> safeGet <*> safeGet <*> safeGet
data Contacts = Contacts [Contact]
instance SafeCopy Contacts where
version = 2
kind = extension
putCopy (Contacts contacts) = contain $ safePut contacts
getCopy = contain $ Contacts <$> safeGet
instance Migrate Contacts where
type MigrateFrom Contacts = Contacts_v0
migrate (Contacts_v0 contacts) = Contacts [ Contact{ name = name
, address = address
, phone = "" }
| (name, address) <- contacts ]
From the above library documentation I am trying to do this.
{-# LANGUAGE RecordWildCards, TypeFamilies #-}
import Control.Applicative
import Data.SafeCopy
type Name = String
type Address = String
type Phone = String
data Contacts = Contacts [(Name, Address)] deriving (Show)
instance SafeCopy Contacts where
putCopy (Contacts list) = contain $ safePut list
getCopy = contain $ Contacts <$> safeGet
data Contacts_v0 = Contacts_v0 [(Name, Address)] deriving (Show)
instance SafeCopy Contacts_v0 where
putCopy (Contacts_v0 list) = contain $ safePut list
getCopy = contain $ Contacts_v0 <$> safeGet
data Contact = Contact { name :: Name, address :: Address, phone :: Phone } deriving (Show)
instance SafeCopy Contact where
putCopy Contact{..} = contain $ do safePut name; safePut address; safePut phone
getCopy = contain $ Contact <$> safeGet <*> safeGet <*> safeGet
{-
data Contacts = Contacts [Contact]
instance SafeCopy Contacts where
version = 2
kind = extension
putCopy (Contacts contacts) = contain $ safePut contacts
getCopy = contain $ Contacts <$> safeGet
instance Migrate Contacts where
type MigrateFrom Contacts = Contacts_v0
migrate (Contacts_v0 contacts) = Contacts [ Contact{ name = name, address = address, phone = "" }
| (name, address) <- contacts ]
-}
main :: IO ()
main = do
let test = Contacts [("gert","home")]
print test
--let testNew = how do you migrate test using migrate?
--print testNew
Note that it would make more sense to me if they renamed the new one to Contacts_v2 instead of renaming the old one.
Maybe I should rephrase the question, when is safecopy useful?
{-# LANGUAGE RecordWildCards, TypeFamilies#-}
import Control.Applicative
import Data.SafeCopy
import Data.Binary
import Data.Serialize.Get
import Data.Serialize.Put
type Name = String
type Address = String
type Phone = String
data Contact = Contact { name :: Name, address :: Address, phone :: Phone } deriving (Show)
instance Binary Contact where
put Contact{..} = do put name; put address; put phone
get = do name <- get; address <- get; phone <- get; return Contact{..}
instance SafeCopy Contact where
putCopy Contact{..} = contain $ do safePut name; safePut address; safePut phone
getCopy = contain $ Contact <$> safeGet <*> safeGet <*> safeGet
data Contacts = Contacts [Contact] deriving (Show)
instance Binary Contacts where
put (Contacts set) = put set
get = fmap Contacts get
instance SafeCopy Contacts where
version = 2
kind = extension
putCopy (Contacts contacts) = contain $ safePut contacts
getCopy = contain $ Contacts <$> safeGet
instance Migrate Contacts where
type MigrateFrom Contacts = Contacts_v0
migrate (Contacts_v0 contacts) = Contacts[Contact{name=name,address=address,phone=""}|(name,address)<-contacts]
data Contacts_v0 = Contacts_v0 [(Name, Address)] deriving (Show)
instance Binary Contacts_v0 where
put (Contacts_v0 set) = put set
get = fmap Contacts_v0 get
instance SafeCopy Contacts_v0 where
putCopy (Contacts_v0 list) = contain $ safePut list
getCopy = contain $ Contacts_v0 <$> safeGet
main :: IO ()
main = do
--
-- instance Binary
--
let c' = Contacts[Contact{name="gert",address="home",phone="test"},Contact{name="gert2",address="home2",phone="test2"}]
let e' = encode c'
print e'
let d' = decode e'
print (d':: Contacts)
let c = Contacts_v0 [("gert_v0","home_v0"),("gert2_v0","home2_v0")]
let e = encode c
print e
let d = decode e
print (d:: Contacts_v0)
--can not do print (d:: Contacts) meaning you are screwed
--
-- instance SafeCopy
--
let c'' = Contacts_v0 [("gert_v0","home_v0"),("gert2_v0","home2_v0")]
let e'' = runPut (safePut c'')
print e''
let d'' = runGet safeGet e''
case d'' of
Left _ -> print "error"
Right d'' -> print (d'':: Contacts)
--can do print (d:: Contacts) or print (d:: Contacts_v0) meaning you are safed
I'm reading values from in from a console using readLn.
I'd like to write a function:
requestValue :: String -> IO a
requestValue s = do
putStrLn $ "Please enter a new value for " ++ s
readLn
I'd then be able to do, for example,
changeAge :: Person -> IO Person
changeAge p = do
age' <- requestValue "age"
return $ p { age = age'}
changeName :: Person -> IO Person
changeName p = do
name' <- requestValue "name"
return $ p { name = name'}
The problem I have is that the read instance of String seems to require the string to be in quotes. I don't want to have to enter "Fred" in the console to change name when I really only want to type in Fred.
Is there an easy way to do this that keeps requestValue polymorphic?
Since you want to add your own custom read behavior for user names, the way to do that is to actually write a new instance for readings names. To do that we can create a new type for names:
import Control.Arrow (first)
newtype Name = Name { unName :: String }
deriving (Eq, Ord, Show)
and write a custom read for it:
instance Read Name where
readsPrec n = map (first Name) . readsPrec n . quote
where quote s = '"' : s ++ ['"']
this is the same as the read instance for strings, but we first quote the string, after reading it in.
Now you can modify your Person type to use Name instead of String:
data Person = Person { age :: Int
, name :: Name } deriving Show
and we're in business:
*Main> changeName (Person 31 (Name "dons"))
Please enter a new value for name
Don
Person {age = 31, name = Name {unName = "Don"}}
You want getLine, not readLn.
Is there a possibility to construct data in runtime ? I mean something like "read" function, but which applies [(field name, value)]. Let's say I have
data Street = Street String
data City = City String
data ZipCode = ZipCode String
data Address = Address {
street :: Street,
city :: City,
zipCode :: ZipCode
}
I want to have a function like:
genericConstructor :: (DataConstructable a) => String -> [(String, a)] -> a
So I can use it like this:
genericConstructor "Address" [("street", Street "Baker"),
("city", City "London"),
("zipCode", ZipCode "12345")] :: Address
I don't want any boilerplate code, looking for anything similar to Reflection API for Java.
Currently looking at Data.Data and Data.Typeable modules though don't see how I can achieve it.
The purpose of all of this is to create a binding between some data format and haskell data structures.
Here's something close to what you're asking for.
import Data.Data
import Data.Dynamic
import Data.Maybe
data City = City String deriving (Data, Typeable, Show, Eq)
data Street = Street String deriving (Data, Typeable, Show, Eq)
data Addr = Addr {
city :: City
,street :: Street} deriving (Show, Eq, Data, Typeable)
class Foo a where
genericConstr :: [(String,Dynamic)] -> a
instance Foo Addr where
genericConstr = buildAddr
lf ls nm = fromMaybe (error $ nm ++ " not found") (lookup nm ls >>= fromDynamic)
buildAddr ls = Addr {city = lf ls "city", street = lf ls "street"}
Load this, and in ghci:
*Foo> genericConstr [("street", toDyn (Street "Baker")), ("city", toDyn (City "London"))] :: Addr
Addr {city = City "London", street = Street "Baker"}
This seems like a lot of work to me, though. This is tricky because Haskell requires all types to be resolved at compile time; in this case you're trying to create types with run-time information (e.g. the string "Address"). This is possible, but you'll be fighting the type system at every step. I agree with Jason that using a parser is probably a better approach.
I think one problem with your sceme is that with
genericConstructor :: (DataConstructable a) => String -> [(String, a)] -> a
all the 'arguments' would have to be of the same constructable type. Therefore, you would need something along the lines of
genericConstructor :: (DataConstructable a) => String -> [forall b. DataConstructable b => (String, b)] -> a
which I'm not entirely sure how to do, I must admit.
Would it not be easier just to parse everything from the data format string?