Can anything be done to define a Show instance for an undefined value? Maybe some GHC extensions exist? I want something like this:
> print (1,undefined)
(1,"undefined")
According to the Haskell 2010 report, chapter 9, evaluating undefined should always cause an error:
-- It is expected that compilers will recognize this and insert error
-- messages that are more appropriate to the context in which undefined
-- appears.
undefined :: a
undefined = error "Prelude.undefined"
Since printing a value includes evaluating it, this will always give an error.
The bottom value (of which undefined is one flavor) is a value that is never constructed and hence can't be observed. This implies that you can't print it either. This value can't be compared to null from other languages, which usually can be observed and even checked against.
It is useful to think of undefined as well as error "blah" and all other bottoms as equivalent to results of infinite loops. The result of an infinite loop is never constructed and hence can't be observed.
More conceptually: The "undefined" is not a value like 'X'. The 'X' value has type Char. What type does "undefined" have? The symbol "undefined" is polymorphic, it can have any type (any type of kind *).
Type classes like "Show t" dispatch on the type t. So different type can and do have different show functions that display them. Which function gets your "undefined" depends on the type.
In GHCI most polymorphic types are defaulted to () so it can run the command. One can make a show function for a new type that does not look at the value:
Prelude> data Test = Test
Prelude> instance Show Test where show x = "I did not look at x"
Prelude> show Test
"I did not look at x"
Prelude> show (undefined :: Test)
"I did not look at x"
But as you can see this avoids the error with undefined by never examining the value at all. So this is a bit useless.
You could make your own type class and printing machinery that runs in IO and catches errors and does sort of what you want:
import Control.Exception
perr s = do x <- try (evaluate (show s)) :: IO (Either SomeException String)
return (either show id x))
The above translates errors into the error's string form:
Prelude Control.Exception> perr True
"True"
Prelude Control.Exception> perr (undefined :: Bool)
"Prelude.undefined"
Note: A better 'perr' needs to force the whole String instead of just the WHNF.
Even though (as the others already pointed out) you can't specify a Show instance for undefined, you may be able to put together a workaround by using catch as in the following code:
import qualified Control.Exception as C
import System.IO.Unsafe (unsafePerformIO)
showCatch :: (Show a) => a -> IO String
showCatch = showCatch' "undefined"
showCatch' :: (Show a) => String -> a -> IO String
showCatch' undef x = C.catch (C.evaluate (show x)) showUndefined
where
showUndefined :: C.ErrorCall -> IO String
showUndefined _ = return undef
unsafeShowCatch :: (Show a) => a -> String
unsafeShowCatch x = unsafePerformIO (showCatch x)
But this example will only work for simple expressions:
*Main> let v1 = showCatch 1
v1 :: IO String
*Main> let v2 = showCatch $ if True then undefined else 0
v2 :: IO String
*Main> v1
"1"
*Main> v2
"undefined"
*Main> let v3 = unsafeShowCatch 1
v3 :: String
*Main> let v4 = unsafeShowCatch $ undefined
v4 :: String
*Main> v3
"1"
*Main> v4
"undefined"
It won't work for calls like
showCatch (1,undefined)
Related
I'm puzzled by a seemingly buggy behavior of GHC happening with rather simple Haskell programs.
Consider the following code:
import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList
main :: IO ()
s = show
main = output [
s 42,
s True
]
In GHC 8.4.3 produces the following output:
$ runghc parameterize.hs
.hs:9:7: error:
• No instance for (Num Bool) arising from the literal ‘42’
• In the first argument of ‘s’, namely ‘42’
In the expression: s 42
In the first argument of ‘output’, namely ‘[s 42, s True]’
|
9 | s 42,
|
GHC 8.0.2 produces the same error.
This also happens with the following variations:
Using where
main :: IO ()
main = output [
s 42,
s True
]
where s = show
Using let ... in
main :: IO ()
main = let s = show in output [
s 42,
s True
]
But in the three cases, replacing s = show by s x = show x solves the problem:
main :: IO ()
s x = show x
main = output [
s 42,
s True
]
$ runghc u.hs
42
True
This is not specific to show. Here is one which fails with the succ function operating on Enum elements:
main :: IO ()
main = let s = succ in putStrLn $ showList [
show $ s 41,
show $ s False
] ""
Replacing s = succ by s x = succ x still fixes the thing.
I haven't been able to find an explanation for this unexpected behavior. Is it a bug ? If it isn't, please explain what is happening.
You are bitten by the monomorphism restriction and its not a bug. The first two paragraphs of that page:
The "monomorphism restriction" is a counter-intuitive rule in Haskell
type inference. If you forget to provide a type signature, sometimes
this rule will fill the free type variables with specific types using
"type defaulting" rules. The resulting type signature is always less
polymorphic than you'd expect, so often this results in the compiler
throwing type errors at you in situations where you expected it to
infer a perfectly sane type for a polymorphic expression.
A simple example is plus = (+). Without an explicit signature for
plus, the compiler will not infer the type (+) :: (Num a) => a -> a ->
a for plus, but will apply defaulting rules to specify plus ::
Integer -> Integer -> Integer. When applied to plus 3.5 2.7, GHCi will
then produce the somewhat-misleading-looking error, No instance for
(Fractional Integer) arising from the literal ‘3.5’.
Simply replace (+) here with show and it is your example.
With this code for example:
import System.IO
output :: [String] -> IO()
output stringList = sequence_ $ map putStrLn stringList
main :: IO ()
s = show
s2 x = show x
main = do
output [
s False,
s True
]
output [
s2 42,
s2 True
]
You get this result in ghci after loading the file containing this:
Prelude> :l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
Ok, one module loaded.
*Main> :t s
s :: Bool -> String
*Main> :t s2
s2 :: Show a => a -> String
*Main>
So in your first example the type deduced for s doesn't allow you to use it with a number.
The exact rules, when the monomorphism restriction applies are defined here Section 4.5.5 of Haskell Report 2010, but are fairly technical.
Also pay attention that the monomorphism restriction is deactivated at the ghci prompt and only applies to compiled modules.
I have a little toy semantics for natural language, with words like:
ran :: String -> Bool
ran = (`elem` ["Bart", "Homer", "Marge"])
and:
bart :: String
bart = "Bart"
So for example, I can have (ran bart) :: Bool, and so on.
I want to write a parser which, for example takes the string "Bart ran" and returns True. I'd probably use Parsec for this.
However, the problem is being able to call functions via strings. E.g. getting from "ran" to the function ran. For this, I thought Language.Haskell.Interpreter's interpret function might be appropriate.
So my questions are:
Is this a sensible way to do what I want to do?
If so, why doesn't the following work, entered into GHCi, given a module called Grammar.hs in the same directory with ran defined as above:
let a = runInterpreter $ do
loadModules ["Grammar"]
setImports ["Prelude"]
interpret "ran" (as :: String -> Bool)
let b = do
x <- a
return $ x <*> pure "John"
b
I get the error:
"Left (WontCompile [GhcError {errMsg = "<interactive>:2:1:\n Not in scope: \8216ran\8217\n Perhaps you meant \8216tan\8217 (imported from Prelude)"}])"
which suggests that the import isn't working, and indeed, if I try something similar with a Prelude function, everything works.
Why do I get the following type error (among many others) if I try to compile the same code as in Q2, (minus the let):
No instance for MonadIO m0 arising from a use of runInterpreter
As for #2, you need to add "Grammar" to the setImports list as well:
runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
As for #3, it is because runInterpreter is monomorphic in the choice of monad to run it in:
runInterpreter :: (MonadIO m, MonadMask m)
=> InterpreterT m a
-> m (Either InterpreterError a)
So you'll need to choose a particular m by running it in e.g. IO:
main :: IO ()
main = do
ran <- runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
print $ ran <*> pure "John"
Now, as for #1, I am not convinced you need something as stupidly powerful as HInt here. You could just maintain a dictionary of String -> Bool functions keyed by a String key, something simple like a Map String (String -> Bool), and then use that to look up ran etc.
I have a function
import System.Exit
exit_and_report_type_mismatch :: String -> IO ExitCode
exit_and_report_type_mismatch error_message = do
putStrLn error_message
exitFailure
and a section of another like so
interpret_expr :: Vars -> Expr -> Val
interpret_expr vars (Plus (ConsE _ _) (NumE _)) = exit_and_report_type_mismatch "Type Error: Can only concatenate list (not int) to list"
Haskell complains to me that it is expecting type Val (another data type I have defined) but it actually receives type IO Exitcode. Fair enough - exit_and_report_mismatch is returning IO ExitCode which is not a Val.
How do I completely abort the Haskell program from within "exit_and_report_type_mismatch"? I have read a bit about Haskell exceptions but the explanations either do not make sense or mention having to call ExitWith from the main function, which is not an option.
This is what error is for. From the documentation:
error :: [Char] -> a
error stops execution and displays an error message.
For instance:
zsh% runhaskell <<<'main = putStrLn (error "Message") >> print "Not reached."'
runghcXXXX7729.hs: Message
The effect of putStrLn is ignored, and the program terminates as soon as the value produced by error is demanded (lazy evaluation means that just putting error somewhere doesn't immediately cause an error; as you might or might not expect, let x = error "Message" in putStrLn "Printed" causes no errors). It is possible to catch these exceptions with the functions from Control.Exception.Base, such as catch, but I've never done this nor have I seen this done.
Also, as a final note, consider avoiding the use of error. Partial functions (functions that aren't defined over their entire input domain) are best avoided when possible, as it's much easier to reason about your code with the stronger guarantees total functions provide. It's nice when, as for total functions, f :: A -> B really means "the function f returns something of type B"; for partial functions, f :: A -> B means only "if the function f returns, then what it returns is of type B". In your case, this might mean having a type like interpretExpr :: Vars -> Expr -> Either RuntimeError Val, or something suitably isomorphic (in the simplest case, perhaps data Result = Error String | Value Val, and interpretExpr :: Vars -> Expr -> Result).
This will do it:
import System.IO.Unsafe
exit_and_report_type_mismatch :: String -> a
exit_and_report_type_mismatch error_message = unsafePerformIO $ do
putStrLn error_message
exitFailure
The function error might work the same though.
I have a data type which contains an IORef as an important element. This means there is not a clean way to make it a member of the show type class. This is not too bad as I have a print function in the IO monad for this type. But it is annoying in GHCi in that every time I return one of these thing as a result I get an error stating that it cannot be shown.
Is there a way to get GHCi, which operates in the IO monad anyway, to use an IO action to show a result? If not, would there be any negative consequences to writing show a = unsafePerformIO $ print a?
Have you considered adding to your .ghci file something like:
instance (Show a) => Show (IORef a) where
show a = show (unsafePerformIO (readIORef a))
It isn't safe at all, but if this is just for your personal use perhaps that is OK.
For more general use the previously given answers look good to me. That is, either define a static "I can't show this" message:
instance Show (IORef a) where
show _ = "<ioref>"
This would give something like:
> runFunc
MyStruct <ioref> 4 "string val"
Or use a custom function. I suggest making a class and lifting all the Show instances:
class ShowIO a where
showIO :: a -> IO String
instance Show a => ShowIO a where
showIO = return . show
instance ShowIO a => ShowIO (IORef a) where
showIO a = readIORef a >>= showIO
Giving the output (untested, this is just hand-written):
> myFunc >>= showIO
MyStruct "My String in an IORef" 4 "string val"
ghci has three cases for return values:
Show a => a: Just run show and print it
Show a => IO a: Execute the action, run show and print
IO (): print nothing
So usually, if you type an IO action, it get's executed and the result gets printed if it's not (). Let's try it:
ghci>15
15
ghci>'a' : 'b' : 'c' : []
"abc"
ghci>putStrLn "Hello, world!"
Hello, world!
ghci>putStrLn "Hello, world!" >> return 42
Hello, world!
42
ghci>
If you want to print something different, the best way is probably to write a custom function and stick it in front of each line you want to see:
myShowFun :: ... -> IO String
ghci> myShowFun $ ...
foobar
Actually I have some formula like "x + y", which is a String.
I managed to replace the x/y variable with specific values like "1.2", which is still String type.
Now I have expression like "1 + 2".
So the problem is how to evaluate a expression of a string type and get the result.
ps: I wanna sth like read, that can directly convert the whole string expression instead of handling the operator (+/-,etc) case by case. Is that possible?
Your question leaves a lot of room for interpretation. I'm taking a guess you aren't accustom to building a whole pipeline of lexing, parsing, maybe type checking, and evaluating. The long answer would involve you defining what language you wish to evaluate (Just integers with '+', perhaps all rationals with '+', '-' '*', '/', or even a larger language?) and perform each of the above steps for that language.
The short answer is: to evaluate Haskell expressions, which includes the basic math operators you're probably talking about, just use the "hint" package:
$ cabal install hint
...
$ ghci
> import Language.Haskell.Interpreter
> runInterpreter $ setImports ["Prelude"] >> eval "3 + 5"
Right "8"
Yay!
Might be worth reading the Parsec section of Real World Haskell. You could parse it into an expression tree and then substitute the values in. As you use Parsec you'd build up an expression tree using types (very roughly, I'm sure I've made some mistakes which I'll edit in fixes for as and when people point them out!) like that below.
data Op = Plus | Minus
data Term = Variable String
| Value Int
data Expression = Expr Expression Op Expression
| Term
Then 1 + 2 would be (Expr (Variable "x") Plus (Variable "y")) and you could apply the appropriate substitutions.
To get the result, I guess you could right a simple function evaluate :: Map String Int -> Expression -> Either ErrorMessage Int which would apply the bindings in the map and then calculate the result if possible.
Well I've been banging my head against hint but I give up for now. I know hint can do this but I'm not sure how. [edit] See TomMD's answer for how to set imports up for hint. [/edit]
import Language.Haskell.Interpreter (eval, runInterpreter, Interpreter, InterpreterError)
main = do let resIO = eval "3" :: Interpreter String
res <- runInterpreter resIO
print res
This uninterestingly produces Right "3" as the result. I tried the following variants, only to run into baffling errors:
... eval "3 + 3" ....
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: `+'"])
The + operator isn't in scope??? wtf...
import Language.Haskell.Interpreter (interpret, as, runInterpreter, Interpreter)
main = do let resIO = interpret "3" (as :: Int) :: Interpreter Int
res <- runInterpreter resIO
print res
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: type constructor or class 'Int'")])
The Int class isn't in scope??? ugh...
I invite those more knowledgeable than me to expound on the finer details of hint.
The accepted answer shows a minimal example of using the hint, but it lacks couple of things:
How to evaluate using bindings like let x = 1 in x + 1.
How to handle exceptions, specifically divide by zero.
Here is a more complete example:
import qualified Control.DeepSeq as DS
import Control.Exception (ArithException (..))
import qualified Control.Exception as Ex
import qualified Control.Monad as M
import qualified Data.Either as E
import qualified Language.Haskell.Interpreter as I
evalExpr :: String -> [(String, Integer)] -> IO (Maybe Integer)
evalExpr expr a = Ex.handle handler $ do
i <- I.runInterpreter $ do
I.setImports ["Prelude"]
-- let var = value works too
let stmts = map (\(var, val) -> var ++ " <- return " ++ show val) a
M.forM_ stmts $ \s -> do
I.runStmt s
I.interpret expr (I.as :: Integer)
-- without force, exception is not caught
(Ex.evaluate . DS.force) (E.either (const Nothing) Just i)
where
handler :: ArithException -> IO (Maybe Integer)
handler DivideByZero = return Nothing
handler ex = error $ show ex