How do I get an unhandled exception to be reported in SML/NJ? - exception

I have the following SML program in a file named testexc.sml:
structure TestExc : sig
val main : (string * string list -> int)
end =
struct
exception OhNoes;
fun main(prog_name, args) = (
raise OhNoes
)
end
I build it with smlnj-110.74 like this:
ml-build sources.cm TestExc.main testimg
Where sources.cm contains:
Group is
csx.sml
I invoke the program like so (on Mac OS 10.8):
sml #SMLload testimg.x86-darwin
I expect to see something when I invoke the program, but the only thing I get is a return code of 1:
$ sml #SMLload testimg.x86-darwin
$ echo $?
1
What gives? Why would SML fail silently on this unhandled exception? Is this behavior normal? Is there some generic handler I can put on main that will print the error that occurred? I realize I can match exception OhNoes, but what about larger programs with exceptions I might not know about?

The answer is to handle the exception, call it e, and print the data using a couple functions available in the system:
$ sml
Standard ML of New Jersey v110.74 [built: Tue Jan 31 16:23:10 2012]
- exnName;
val it = fn : exn -> string
- exnMessage;
val it = fn : exn -> string
-
Now, we have our modified program, were we have the generic handler tacked on to main():
structure TestExc : sig
val main : (string * string list -> int)
end =
struct
exception OhNoes;
open List;
fun exnToString(e) =
List.foldr (op ^) "" ["[",
exnName e,
" ",
exnMessage e,
"]"]
fun main(prog_name, args) = (
raise OhNoes
)
handle e => (
print("Grasshopper disassemble: " ^ exnToString(e));
42)
end
I used lists for generating the message, so to make this program build, you'll need a reference to the basis library in sources.cm:
Group is
$/basis.cm
sources.cm
And here's what it looks like when we run it:
$ sml #SMLload testimg.x86-darwin
Grasshopper disassemble: [OhNoes OhNoes (more info unavailable: ExnInfoHook not initialized)]
$ echo $?
42
I don't know what ExnInfoHook is, but I see OhNoes, at least. It's too bad the SML compiler didn't add a basic handler for us, so as to print something when there was an unhandled exception in the compiled program. I suspect ml-build would be responsible for that task.

Related

How to extract the name of a Party?

In a DAML contract, how do I extract the name of a party from a Party field?
Currently, toText p gives me Party(Alice). I'd like to only keep the name of the party.
That you care about the precise formatting of the resulting string suggests that you are implementing a codec in DAML. As a general principle DAML excels as a modelling/contract language, but consequently has limited features to support the sort of IO-oriented work this question implies. You are generally better off returning DAML values, and implementing codecs in Java/Scala/C#/Haskell/etc interfacing with the DAML via the Ledger API.
Still, once you have a Text value you also have access to the standard List manipulation functions via unpack, so converting "Party(Alice)" to "Alice" is not too difficult:
daml 1.0 module PartyExtract where
import Base.List
def pack (cs: List Char) : Text =
foldl (fun (acc: Text) (c: Char) -> acc <> singleton c) "" cs;
def partyToText (p: Party): Text =
pack $ reverse $ drop 2 $ reverse $ drop 7 $ unpack $ toText p
test foo : Scenario {} = scenario
let p = 'Alice'
assert $ "Alice" == partyToText p
In DAML 1.2 the standard library has been expanded, so the code above can be simplified:
daml 1.2
module PartyExtract2
where
import DA.Text
traceDebug : (Show a, Show b) => b -> a -> a
traceDebug b a = trace (show b <> show a) $ a
partyToText : Party -> Text
partyToText p = dropPrefix "'" $ dropSuffix "'" $ traceDebug "show party: " $ show p
foo : Scenario ()
foo = do
p <- getParty "Alice"
assert $ "Alice" == (traceDebug "partyToText party: " $ partyToText p)
NOTE: I have left the definition and calls to traceDebug so you can see the exact strings being generated in the scenario trace output.

failwith causes an error when used in a calculation expression - FParsec

I use a function:
let identifier kind =
(many1Satisfy2L isLetter
(fun c -> isLetter c || isDigit c) "identifier"
>>= fun s -> preturn s) >>= fun s -> identifierKind s kind
The kind argument is of this type:
type KindOfIdentifier =
| Data
| Type
| Module
And here is my function that analyzes the kind argument:
let private identifierKind (id: string) kind =
match kind with
| KindOfIdentifier.Data ->
if id.ToUpper() = id && id.Length > 1 then preturn id
elif System.Char.IsUpper id.[0] = false then preturn id
else failwith "Error 1"
| KindOfIdentifier.Module ->
if System.Char.IsUpper id.[0] then preturn id
else failwith "Error 2"
| KindOfIdentifier.Type ->
preturn id
I would therefore like to analyze an identifier to verify whether it meets the criteria of the identifier type. If identifying it does not meet the criterion, I return an error with failwith.
But, when I use this parser (identify) with a deliberate error in my text to be analyzed, to check if everything works, I get a long error:
(Sorry, I'm French, so there's a little french in the error message ^^.)
How to prevent all this, and only display the error message in the classic way with FParsec?
The failwith function throws a .NET exception - a catasprophic failure that is supposed to indicate that the program broke in an unexpected way. Or, in other words, in an exceptional way - hence the name "exception". This is not what you're trying to do.
What you're trying to do here is to indicate to FParsec that the current parsing attempt has failed, and possibly provide an explanation of what exactly happened.
To do this, you need to create an error-producing instance of Parser - the same type that is returned by preturn.
While preturn creates a successful instance of Parser, there is another function that creates an error-producing instance. This function is called fail. Just use it:
| KindOfIdentifier.Data ->
if id.ToUpper() = id && id.Length > 1 then preturn id
elif System.Char.IsUpper id.[0] = false then preturn id
else fail "Error 1"

Getting error when try to pattern match for Unix_error (Ocaml)?

I've been trying to pattern for the case where a user types in an invalid directory:
# let dir = Unix.opendir "adfalf";;
Exception: Unix.Unix_error (Unix.ENOENT, "opendir", "adfalf").
My function is as follows:
let files_of_dir d =
try
let dir = Unix.opendir d in
...
with
Unix_error (uerr, ucommand, dir) -> raise Not_found
Except I keep getting the compilation error:
Error: This variant pattern is expected to have type exn
The constructor Unix_error does not belong to type exn
I don't understand what I'm doing wrong w/ the pattern matching. If anyone could help me on this it would be greatly appreciated!
Some Other Notes:
I've been compiling my code using the following command on terminal:
ocamlbuild filename.byte
You need to say Unix.Unix_error, not just Unix_error. Note that this is what appears in your sample session.

How do exceptions work in Haskell (part two)?

I have the following code:
{-# LANGUAGE DeriveDataTypeable #-}
import Prelude hiding (catch)
import Control.Exception (throwIO, Exception)
import Control.Monad (when)
import Data.Maybe
import Data.Word (Word16)
import Data.Typeable (Typeable)
import System.Environment (getArgs)
data ArgumentParserException = WrongArgumentCount | InvalidPortNumber
deriving (Show, Typeable)
instance Exception ArgumentParserException
data Arguments = Arguments Word16 FilePath String
main = do
args <- return []
when (length args /= 3) (throwIO WrongArgumentCount)
let [portStr, cert, pw] = args
let portInt = readMaybe portStr :: Maybe Integer
when (portInt == Nothing) (throwIO InvalidPortNumber)
let portNum = fromJust portInt
when (portNum < 0 || portNum > 65535) (throwIO InvalidPortNumber)
return $ Arguments (fromInteger portNum) cert pw
-- Newer 'base' has Text.Read.readMaybe but alas, that doesn't come with
-- the latest Haskell platform, so let's not rely on it
readMaybe :: Read a => String -> Maybe a
readMaybe s = case reads s of
[(x, "")] -> Just x
_ -> Nothing
Its behavior differs when compiled with optimizations on and off:
crabgrass:~/tmp/signserv/src% ghc -fforce-recomp Main.hs && ./Main
Main: WrongArgumentCount
crabgrass:~/tmp/signserv/src% ghc -O -fforce-recomp Main.hs && ./Main
Main: Main.hs:20:9-34: Irrefutable pattern failed for pattern [portStr, cert, pw]
Why is this? I am aware that imprecise exceptions can be chosen from arbitrarily; but here we are choosing from one precise and one imprecise exception, so that caveat should not apply.
I would agree with hammar, this looks like a bug. And it seems fixed in HEAD since some time. With an older ghc-7.7.20130312 as well as with today's HEAD ghc-7.7.20130521, the WrongArgumentCount exception is raised and all the other code of main is removed (bully for the optimiser). Still broken in 7.6.3, however.
The behaviour changed with the 7.2 series, I get the expected WrongArgumentCount from 7.0.4, and the (optimised) core makes that clear:
Main.main1 =
\ (s_a11H :: GHC.Prim.State# GHC.Prim.RealWorld) ->
case GHC.List.$wlen
# GHC.Base.String (GHC.Types.[] # GHC.Base.String) 0
of _ {
__DEFAULT ->
case GHC.Prim.raiseIO#
# GHC.Exception.SomeException # () Main.main7 s_a11H
of _ { (# new_s_a11K, _ #) ->
Main.main2 new_s_a11K
};
3 -> Main.main2 s_a11H
}
when the length of the empty list is different from 3, raise WrongArgumentCount, otherwise try to do the rest.
With 7.2 and later, the evaluation of the length is moved behind the parsing of portStr:
Main.main1 =
\ (eta_Xw :: GHC.Prim.State# GHC.Prim.RealWorld) ->
case Main.main7 of _ {
[] -> case Data.Maybe.fromJust1 of wild1_00 { };
: ds_dTy ds1_dTz ->
case ds_dTy of _ { (x_aOz, ds2_dTA) ->
case ds2_dTA of _ {
[] ->
case ds1_dTz of _ {
[] ->
case GHC.List.$wlen
# [GHC.Types.Char] (GHC.Types.[] # [GHC.Types.Char]) 0
of _ {
__DEFAULT ->
case GHC.Prim.raiseIO#
# GHC.Exception.SomeException # () Main.main6 eta_Xw
of wild4_00 {
};
3 ->
where
Main.main7 =
Text.ParserCombinators.ReadP.run
# GHC.Integer.Type.Integer Main.main8 Main.main3
Main.main8 =
GHC.Read.$fReadInteger5
GHC.Read.$fReadInteger_$sconvertInt
Text.ParserCombinators.ReadPrec.minPrec
# GHC.Integer.Type.Integer
(Text.ParserCombinators.ReadP.$fMonadP_$creturn
# GHC.Integer.Type.Integer)
Main.main3 = case lvl_r1YS of wild_00 { }
lvl_r1YS =
Control.Exception.Base.irrefutPatError
# ([GHC.Types.Char], [GHC.Types.Char], [GHC.Types.Char])
"Except.hs:21:9-34|[portStr, cert, pw]"
Since throwIO is supposed to respect ordering of IO actions,
The throwIO variant should be used in preference to throw to raise an exception within the IO monad because it guarantees ordering with respect to other IO operations, whereas throw does not.
that should not happen.
You can force the correct ordering by using a NOINLINE variant of when, or by performing an effectful IO action before throwing, so it seems that when the inliner sees that the when does nothing except possibly throwing, it decides that order doesn't matter.
(Sorry, not a real answer, but try to fit that in a comment ;)

How do I get yason:encode-alist to return the encoded string instead of sending it to a stream?

I'm trying to encode a JSON string from an alist using YASON. The problem is, the return value I'm getting is the original alist I fed it. It's printing the JSON string, and according to the documentation, it goes to *STANDARD-OUTPUT*.
Simple example session:
(ql:quickload :yason)
To load "yason":
Load 1 ASDF system:
yason
; Loading "yason"
(:YASON)
* (defparameter starving-json-eater (yason:encode-alist '(("foo" . "bar") ("baz" . "qux"))))
{"foo":"bar","baz":"qux"}
STARVING-JSON-EATER
* starving-json-eater
(("foo" . "bar") ("baz" . "qux"))
I've tried passing 'starving-json-eater into the stream parameter, but I get an error:
* (setf starving-json-eater (yason:encode-alist '(("foo" . "bar") ("baz" . "qux")) 'starving-json-eater))
debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {1001E06783}>:
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-WRITE-CHAR (1)>
when called with arguments
(STARVING-JSON-EATER #\{).
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [RETRY] Retry calling the generic function.
1: [ABORT] Exit debugger, returning to top level.
((:METHOD NO-APPLICABLE-METHOD (T)) #<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-WRITE-CHAR (1)> STARVING-JSON-EATER #\{) [fast-method]
How can I get {"foo":"bar","baz":"qux"} into starving-json-eater?
You can use WITH-OUTPUT-TO-STRING to temporarily bind a variable to an open stream which writes into a string. You may even bind the special variable *standard-output* so that you only change the dynamic context of your code without providing explicitly a different stream argument (like when you redirect streams with processes).
(with-output-to-string (*standard-output*)
(yason:encode-alist '(("a" . "b"))))
Note that binding *standard-output* means that anything that writes to *standard-output* will end up being written in the string during the extent of with-output-to-string. In the above case, the scope is sufficiently limited to avoid unexpectedly capturing output from nested code. You could also use a lexical variable to control precisely who gets to write to the string:
(with-output-to-string (json)
(yason:encode-alist '(("a" . "b")) json))
The trick is to create a throwaway string output stream to catch the value, and then grab it from later:
* (ql:quickload :yason)
To load "yason":
Load 1 ASDF system:
yason
; Loading "yason"
(:YASON)
* (defparameter sated-json-eater (make-string-output-stream))
SATED-JSON-EATER
* (yason:encode-alist '(("foo" . "bar") ("baz" . "qux")) sated-json-eater)
(("foo" . "bar") ("baz" . "qux"))
* (defparameter json-string (get-output-stream-string sated-json-eater))
JSON-STRING
* json-string
"{\"foo\":\"bar\",\"baz\":\"qux\"}"
This can be hidden away in a function:
(defun json-string-encode-alist (alist-to-encode)
(let ((stream (make-string-output-stream)))
(yason:encode-alist alist-to-encode stream)
(get-output-stream-string stream)))