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

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"

Related

How to throw a specific Exception in Julia

I am doing test driven development in Julia.
The test expects a certain exception to be thrown.
How do I throw the expected exception?
I'm looping through a string and counting the occurrence of specific letters.
Any letter than 'A','C','G',or'T' should result in an exception
Running Julia version 1.2.0.
I have tried these alternatives:
throw(DomainError())
throw(DomainError)
throw("DomainError")
I expected those to work based on this resource:
https://scls.gitbooks.io/ljthw/content/_chapters/11-ex8.html
Here is a link to the problem I am trying to solve:
https://exercism.io/my/solutions/781af1c1f9e2448cac57c0707aced90f
(Heads up: That link may be unique to my login)
My code:
function count_nucleotides(strand::AbstractString)
Counts = Dict()
Counts['A'] = 0
Counts['C'] = 0
Counts['G'] = 0
Counts['T'] = 0
for ch in strand
# println(ch)
if ch=='A'
Counts['A'] += 1
# Counts['A'] = Counts['A'] + 1
elseif ch=='C'
Counts['C'] += 1
elseif ch=='G'
Counts['G'] += 1
elseif ch=='T'
Counts['T'] += 1
else
throw(DomainError())
end
end
return Counts
end
The test:
#testset "strand with invalid nucleotides" begin
#test_throws DomainError count_nucleotides("AGXXACT")
end
My error report, see the lines with: Expected and Thrown.
strand with invalid nucleotides: Test Failed at /Users/username/Exercism/julia/nucleotide-count/runtests.jl:18
Expression: count_nucleotides("AGXXACT")
Expected: DomainError
Thrown: MethodError
Stacktrace:
[1] top-level scope at /Users/shane/Exercism/julia/nucleotide-count/runtests.jl:18
[2] top-level scope at /Users/juliainstall/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.2/Test/src/Test.jl:1113
[3] top-level scope at /Users/username/Exercism/julia/nucleotide-count/runtests.jl:18
Test Summary: | Fail Total
strand with invalid nucleotides | 1 1
ERROR: LoadError: Some tests did not pass: 0 passed, 1 failed, 0 errored, 0 broken.
The MethodError comes from the call to DomainError -- there are no zero-argument constructor for this exception type. From the docs:
help?> DomainError
DomainError(val)
DomainError(val, msg)
The argument val to a function or constructor is outside the valid domain.
So there are one constructor which takes the value that was out of the domain, and one that, in addition, takes an extra message string. You could e.g. do
throw(DomainError(ch))
or
throw(DomainError(ch, "this character is bad"))

Haskell getLine in a function's otherwise

I'm really new to Haskell and am trying to learn some simple functions.
I made some option choices through functions like so:
displayOptions :: Int -> String
displayOptions option
| option == 0 = "1 - Shop\n2 - Fight Monsters\n3 - Inn\n4 - Monk"
| otherwise = "invalid"
I then get the user input with getLine
choice <- getLine
And then I display a second option box for example,
playerChoice :: String -> String
playerChoice option
| option == "1" = "Sword - 50gp\nShield - 100gp"
| option == "2" = "You go fight some monsters outside town."
| option == "3" = "You go to the town Inn."
| option == "4" = "You go see the holy monk."
| otherwise = "You entered invalid information...\n" ++ displayOptions(0)
What I'm confused about is how I can get the user's choice again within a function. I want my otherwise = to say invalid information, display the options, get the input again and then display the choice they made.
So my main program would look something like this:
main = do
putStrLn "The king has sent you on the journey to become a master."
putStrLn $ "What would you like to do?"
putStrLn $ displayOptions(0)
choice <- getLine
putStrLn $ playerChoice(choice)
You would have to change the return type to be IO String instead of String.
However, probably you want to return Either String String so the function indicates that it's returned the game progression text Right "You do something" or a failure with an explanation of the failure Left "Not an option".
Then in the caller you loop until you get a Right value and each time you get a Left value you print the text and ask again.
I'm sure there's a slightly better way but here's some quickly fixed up code:
module Main where
playerChoice :: String -> Either String String
playerChoice option
| option == "1" = Right "Sword - 50gp\nShield - 100gp"
| option == "2" = Right "You go fight some monsters outside town."
| option == "3" = Right "You go to the town Inn."
| option == "4" = Right "You go see the holy monk."
| otherwise = Left "You entered invalid information..."
displayOptions :: Int -> String
displayOptions option
| option == 0 = "1 - Shop\n2 - Fight Monsters\n3 - Inn\n4 - Monk\n"
| otherwise = "invalid"
main = do
let progress whathappens = do
putStrLn whathappens
let tryAsk prompt = do
putStrLn prompt
choice <- getLine
either tryAsk progress $ playerChoice(choice)
tryAsk $ displayOptions(0) ++ "What would you like to do?"
progress "The king has sent you on the journey to become a master."
if you import Data.Function then you can also write it like the following - which in this case probably isn't better but it's a nice shallow step into a fascinating part of haskell:
fix (\moreProgress whathappens -> do
putStrLn whathappens
fix (\askAgain prompt -> do
putStrLn prompt
choice <- getLine
either askAgain moreProgress $ playerChoice(choice))
$ displayOptions(0) ++ "What would you like to do?")
$ "The king has sent you on the journey to become a master."
You should change the return type to Either String String in order to provide an error message. For more details, look at the docs for the Either type.
In Haskell, we don't have traditional looping structures like for or while instead we use recursive calls. See While loop in Haskell with a condition for an example.

Creating a Caesar Cipher Program in Python 3.4, but function doesn't work

Currently, I am creating a Caesar Cipher but it is not working correctly, can anyone help at all? The code will be below. At the moment, if the program is run first time (as in, no functions have to be re run) it works perfectly, but when the getKey() function is re run, it returns an error. After the code, the error is shown:
def runProgram():
def choice():
userChoice = input("Do you wish to Encrypt of Decrypt? Enter E or D: ").lower()
if userChoice == "e":
return userChoice
elif userChoice == "d":
return userChoice
else:
print("Invalid Response. Please try again.")
choice()
def getMessage():
userMessage = input("Enter your message: ")
return userMessage
def getKey():
try:
userKey = int(input("Enter a key number (1-26): "))
except:
print("Invalid Option. Please try again.")
getKey()
else:
if userKey < 1 or userKey > 26:
print("Invalid Option. Please try again.")
getKey()
else:
return userKey
def getTranslated(userChoice, message, key):
translated = ""
if userChoice == "e":
for character in message:
num = ord(character)
num += key
translated += chr(num)
savedFile = open('Encrypted.txt', 'w')
savedFile.write(translated)
savedFile.close()
return translated
else:
for character in message:
num = ord(character)
num -= key
translated += chr(num)
return translated
userChoice = choice() #Runs function for encrypt/decrypt selection. Saves choice made.
message = getMessage() #Run function for user to enter message. Saves message.
key = getKey() #Runs function for user to select key. Saves key choice.
translatedMessage = getTranslated(userChoice, message, key) #Runs function to translate message, using the choice, message and key variables)
print("\nTranslation complete: " + translatedMessage)
runProgram()
I have tried to create it error proof during the getKey() function with the try, except and else commands. It will 'Try' to see that the input is an int or not, if it is, it goes to else, but if it isn't an int, then it will rerun the function. If the function is rerun, and an int is entered, this error is given:
This is an example of it working:
Do you wish to Encrypt of Decrypt? Enter E or D: E
Enter your message: Hello
Enter a key number (1-26): 5
Translation complete: Mjqqt
This is an example when the getKey() function must be re run due to an int not being entered:
Do you wish to Encrypt of Decrypt? Enter E or D: E
Enter your message: Hello
Enter a key number (1-26): H
Invalid Option. Please try again.
Enter a key number (1-26): 5
Traceback (most recent call last):
File "C:\Python34\Encryptor2.py", line 54, in
runProgram()
File "C:\Python34\Encryptor2.py", line 52, in runProgram
translatedMessage = getTranslated(userChoice, message, key) #Runs function to translate message, using the choice, message and key variables)
File "C:\Python34\Encryptor2.py", line 35, in getTranslated
num += key
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'
As you can see, it re runs the function as I want it too, but the error occurs when adding the key to the ord of character.
The first call to getKey(), with your comment:
key = getKey() #Runs function for user to select key. Saves key choice.
Another place you call it:
if userKey < 1 or userKey > 26:
print("Invalid Option. Please try again.")
getKey()
If you were to write that with the same kind of comment, it would be:
getKey() #Runs function for user to select key. Doesn't save key choice.
What the user types in, comes out of getKey() ... and you aren't keeping track of it, so it vanishes. You then do.
return userKey
userKey is still the H you tried to convert to int, the one that failed. You didn't get rid of it, so it's still there.
The better solution is to rework the shape of your code, so getKey() never calls getKey() inside itself. Do the error checking outside, perhaps, like this kind of shape:
def getKey():
prompt user for key
try to convert to int and return the int
if it fails, return None as an indication that getting the key went wrong.
key = None #set some wrong placeholder
while (key is None) or (key < 1) or (key > 26):
key = getKey()
change your input to raw_input
just use the maketrans and translate functions that basically encrypt or decrypt the message for you.they make for a very short and efficient solution to the problem
message = input('enter message').lower()
offset = int(input('enter offset (enter a negative number to decrypt)'))
alphabet = 'abcdefghijklmnopqrstuvwxyz'
enc_alphabet = (alphabet[alphabet.index(alphabet[offset]):len(alphabet)])+ alphabet[0:offset]
data = str.maketrans(alphabet,enc_alphabet)
final_message = str.translate(message, data)
print(final_message)
This code really doesn't need to be this complicated at all, if you just use regex the code will be much shorter but (in my opinion) way better.
Here's a code I created for Caesar cipher encrypting, decrypting and using a shift of the user's choice using regex.
import re
def caesar(plain_text, shift):
cipherText = ''
for ch in plain_text:
stayInAlphabet = ord(ch) + shift
if ch.islower():
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
elif stayInAlphabet < ord('a'):
stayInAlphabet += 26
elif ch.isupper():
if stayInAlphabet > ord('Z'):
stayInAlphabet -= 26
elif stayInAlphabet < ord('A'):
stayInAlphabet += 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
print(cipherText)
return cipherText
selection = input ("encrypt/decrypt ")
if selection == 'encrypt':
plainText = input("What is your plaintext? ")
shift = (int(input("What is your shift? ")))%26
caesar(plainText, shift)
else:
plainText = input("What is your plaintext? ")
shift = ((int(input("What is your shift? ")))%26)*-1
caesar(plainText, shift)

F# Lazy and Exceptions

Given this example:
let value = try (lazy raise(Exception())).Value with | _ -> false
Why is the exception not captured in the try block. Keep in mind that I raise the exception like this to prove the example. The point is that if I have a lazy code that throws and exception, it seems to be unable to capture in the try block. Do I have to be specific in my match of the exception or do I have to capture the exception inside the lazy expression itself?
The following prints both the exception and the value which is false.
let value =
try
(lazy raise(System.Exception())).Value
with
| exn -> printfn "%A" exn
false
printfn "%A" value
I'm not able to rep your results. What are you seeing?
let value =
try
(lazy raise(Exception())).Value
true
with
| ex ->
printfn "got exception";
false
Gives me
got exception
val value : bool = false
Edit:
Adding debugging image

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

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.