
Daniel Fischer wrote:
In a real library, the constructor Parse would not be exported, to allow later changing the implementation of the Parse type without breaking user code. So user code like parseByte cannot access the constructor and must use the exported API (getState, putState, identity, bail, ...).
thanks for the point, I get it. One other question. Later in the chapter they define peekByte as follows: -- file: ch10/Parse.hs peekByte :: Parse (Maybe Word8) peekByte = (fmap fst . L.uncons . string) <$> getState Here they are accessing the 'string' field of the state. So whomever writes this function needs to have the accessor functions. At this point I'm wondering how much state is really getting hidden. Or maybe peekByte would only be written inside the original library. I was just playing around and discovered you can choose to export the accessor functions or not. Let's say we have -------- module Mod where data What = What { acc :: Int64 } -------- now in a separate module we write: ------------------- -- All fine: import Mod x1 = What 3 x2 = What { acc = 3 } x3 = acc x1 --------------- Now we revisit the first module and write module Mod ( What(What) ) where Now, import Mod x1 = What 3 -- Fine x2 = What { acc = 3 } -- Error x3 = acc x1 -- Error So apparently this exports the constructor but not the accessor fields. The item can be constructed in the normal way, but not in record syntax way. Finally module Mod ( What(acc) ) where --> This exports the accessors which can be used to access, but not to construct module Mod (What(..)) where --> export everything So the lesson is, if we are going to allow users to write functions like peekByte, we have to export the accessor functions, but not necessarily any constructors.