Haskell use of getters instead of pattern match - haskell

I have a simple nested data structure I can pattern match:
Prelude> data Token = Token String Int deriving ( Show )
Prelude> data Person = Person Token deriving ( Show )
Prelude> person = Person (Token "moish" 74)
Prelude> foo (Person (Token name _)) = "hello " ++ name
Is there an easy way to extract the name (moish) from p without pattern-match ?
foo :: Person -> String
foo p = -- ???

Nope. Pattern match is the one and only way to consume data. Everything else is built on top of that.

Related

Template Haskell on Aeson

I have a data type like this:
module My.Module
data A = A { aFoo :: Integer } deriving (Generic, Show)
And I have generic option for Aeson
import Data.Char ( toUpper, toLower )
genericOptions :: String -> Options
genericOptions prefix = defaultOptions
{ fieldLabelModifier = dropPrefix $ length prefix
, constructorTagModifier = addPrefix prefix
, omitNothingFields = True
}
where
dropPrefix l s = let remainder = drop l s
in (toLower . head) remainder : tail remainder
addPrefix p s = p ++ toUpper (head s) : tail s
So I can use it like this
instance A.FromJSON A where
parseJSON = A.genericParseJSON $ genericOptions "A"
instance A.ToJSON A where
toJSON = A.genericToJSON $ genericOptions "A"
But I realize I could use some template haskell
import Data.Aeson.TH ( deriveJSON )
import Language.Haskell.TH.Syntax ( Dec, Name, Q )
genericDeriveJSON :: Name -> Q [Dec]
genericDeriveJSON name =
deriveJSON (genericOptions (show name)) name
$(genericDeriveJSON ''A)
It throws an error:
Exception when trying to run
compile-time code:
Prelude.tail: empty list
Code: A.genericDeriveJSON ''A
It seems drop l s on dropPrefix returned an empty string meaning the value of show name is not string "A". Since I don't think I could inspect the value, anybody knows what is the value?
Try to use nameBase instead of show (which is meant for debugging and not core logic).
To see what show is doing you can look at the implementation of show which is defined as showName which is itself defined as showName' Alone, to see roughly that it constructs the fully qualified name of your type.

`show` record without deriving Show

Quite often I need to print something while debugging and unless the datatype I need to see derives Show I can't print it. For some datatypes I can't add deriving (Show) to the definition because it may be in a library or somewhere else I can't get to.
Is there anyway I can print these datatypes for debugging?
Standalone deriving
A deriving clause on the type definition isn't the only way to derive. You can also use the StandaloneDeriving GHC language extension.
λ> :set -XStandaloneDeriving
λ> data Person = Human { name :: String, age :: Int } | Dog { goodPupper :: Bool }
λ> deriving instance Show Person
λ> Human "Chris" 31
Human {name = "Chris", age = 31}
Generics
If the type has a Generic instance, you can stringify it with the gshowsPrecdefault function from the generic-deriving package.
λ> import GHC.Generics
λ> import Generics.Deriving.Show
λ> data Person = Human { name :: String, age :: Int } | Dog { goodPupper :: Bool } deriving Generic
λ> putStrLn $ gshowsPrecdefault 0 (Dog True) ""
Dog {goodPupper = True}
GHCi :force
You can use the :force command in GHCi to inspect a value.
λ> data Person = Human { name :: String, age :: Int } | Dog { goodPupper :: Bool }
λ> x = Human "Chris" 31
λ> x
<interactive>:17:1: error:
• No instance for (Show Person) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
λ> :force x
x = <Human> "Chris" 31
See Breakpoints and inspecting variables in the GHC manual.
You have to make your datatype an instance of Show if you want to print it in any way. If you don't want to derive Show you can always implement it yourself.
data Foo = Bar
instance Show Foo where
show Bar = "This is Bar"
main = print f where f = Bar
You can absolutely print things without Show instances.
data MyType a = MyType Int a
showMyType :: (a -> String) -> MyType a -> String
showMyType f (MyType n a) =
"MyType " ++ show n ++ " (" ++ f a ++ ")"

*** Exception: Prelude.read: no parse

I am new to Haskell, I wrote this small script but I am having this read: no parse Exception, anyone could help me?
thanks
import System.Environment
import Data.List
data ContactInfo = Contact { name :: String
, surname :: String
, mobile :: String
} deriving (Read, Show)
fromDt :: [String] -> ContactInfo
fromDt ds = read $ "Contact " ++ (Data.List.concat $ Data.List.intersperse " " $ Data.List.map show ds)
main = do
let val = fromDt ["John","Smith","223 455 2703"]
putStrLn ("Name: " ++ name val ++ ", " ++ surname val)
Using read is horrible for that task, simply use the constructor Contact.
fromDt :: [String] -> ContactInfo
fromDt [n,s,m] = Contact n s m
Note that you will still get an error if the list you pass to fromDt is not 3 cells long. I would simply avoid defining this fragile function and use the constructor Contact directly wherever you would call fromDt.
When you define a data type using record syntax, the derived read instance requires the full record syntax - i.e. you must pass a string like
ContactInfo { name = "...", surname = "...", mobile = "..." }
to read to obtain a ContactInfo value. A string like:
ContactInfo "..." "..." "..."
will result in a no parse exception. Here is a quick demo:
data ABC = ABC { a :: Int, b :: Int, c :: Int }
deriving (Show, Read)
test1 :: ABC -- throws no parse exception
test1 = read "ABC 1 2 3"
test2 :: ABC -- works
test2 = read "ABC { a = 1, b = 2, c = 3 }"

Can I reflect messages out of a Haskell program at runtime?

I’m writing a program that validates a complex data structure according to a number of complex rules. It inputs the data and outputs a list of messages indicating problems with the data.
Think along these lines:
import Control.Monad (when)
import Control.Monad.Writer (Writer, tell)
data Name = FullName String String | NickName String
data Person = Person { name :: Name, age :: Maybe Int }
data Severity = E | W | C -- error/warning/comment
data Message = Message { severity :: Severity, code :: Int, title :: String }
type Validator = Writer [Message]
report :: Severity -> Int -> String -> Validator ()
report s c d = tell [Message s c d]
checkPerson :: Person -> Validator ()
checkPerson person = do
case age person of
Nothing -> return ()
Just years -> do
when (years < 0) $ report E 1001 "negative age"
when (years > 200) $ report W 1002 "age too large"
case name person of
FullName firstName lastName -> do
when (null firstName) $ report E 1003 "empty first name"
NickName nick -> do
when (null nick) $ report E 1004 "empty nickname"
For documentation, I also want to compile a list of all messages this program can output. That is, I want to obtain the value:
[ Message E 1001 "negative age"
, Message W 1002 "age too large"
, Message E 1003 "empty first name"
, Message E 1004 "empty nickname"
]
I could move the messages out of checkPerson into some external data structure, but I like it when the messages are defined right at the spot where they are used.
I could (and probably should) extract the messages from the AST at compile time.
But the touted flexibility of Haskell made me thinking: can I achieve that at runtime? That is, can I write a function
allMessages :: (Person -> Validator ()) -> [Message]
such that allMessages checkPerson would give me the above list?
Of course, checkPerson and Validator need not stay the same.
I can almost (not quite) see how I could make a custom Validator monad with a “backdoor” that would run checkPerson in a sort of “reflection mode,” traversing all paths and returning all Messages encountered. I would have to write a custom when function that would know to ignore its first argument under some circumstances (which ones?). So, a kind of a DSL. Perhaps I could even emulate pattern matching?
So: can I do something like this, how, and what would I have to sacrifice?
Please feel free to suggest any solutions even if they do not exactly fit the above description.
This kind of half-static analysis is basically exactly what arrows were invented for. So let's make an arrow! Our arrow will basically be just a Writer action, but one that remembers what messages it might have spit out at any given moment. First, some boilerplate:
{-# LANGUAGE Arrows #-}
import Control.Arrow
import Control.Category
import Control.Monad.Writer
import Prelude hiding (id, (.))
Now, the type described above:
data Validator m a b = Validator
{ possibleMessages :: [m]
, action :: Kleisli (Writer m) a b
}
runValidator :: Validator m a b -> a -> Writer m b
runValidator = runKleisli . action
There are some straightforward instances to put in place. Of particular interest: the composition of two validators remembers messages from both the first action and the second action.
instance Monoid m => Category (Validator m) where
id = Validator [] id
Validator ms act . Validator ms' act' = Validator (ms ++ ms') (act . act')
instance Monoid m => Arrow (Validator m) where
arr f = Validator [] (arr f)
first (Validator ms act) = Validator ms (first act)
instance Monoid m => ArrowChoice (Validator m) where
left (Validator ms act) = Validator ms (left act)
All the magic is in the operation that actually lets you report something:
reportWhen :: Monoid m => m -> (a -> Bool) -> Validator m a ()
reportWhen m f = Validator [m] (Kleisli $ \a -> when (f a) (tell m))
This is the operation that notices when you're about to output a possible message, and makes a note of it. Let's copy your types and show how to code up checkPerson as an arrow. I've simplified your messages a little bit, but nothing important is different there -- just less syntactic overhead in the example.
type Message = String
data Name = FullName String String | NickName String -- http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/
data Person = Person { name :: Name, age :: Maybe Int }
checkPerson :: Validator Message Person ()
checkPerson = proc person -> do
case age person of
Nothing -> returnA -< ()
Just years -> do
"negative age" `reportWhen` (< 0) -< years
"age too large" `reportWhen` (>200) -< years
case name person of
FullName firstName lastName -> do
"empty first name" `reportWhen` null -< firstName
NickName nick -> do
"empty nickname" `reportWhen` null -< nick
I hope you'll agree that this syntax is not too far removed from what you originally wrote. Let's see it in action in ghci:
> runWriter (runValidator checkPerson (Person (NickName "") Nothing))
((),"empty nickname")
> possibleMessages checkPerson
["empty nickname","empty first name","age too large","negative age"]

How can I use read on a string that is not double quoted?

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.

Resources