Haskell getLine in a function's otherwise - function

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.

Related

Beginner in Elixir : parse CSV file

Hello I'm a beginner in Elixir and I want to parse and stock a CSV file in an Elixir object.
But it's display that:
** (FunctionClauseError) no function clause matching in anonymous fn/1 in Siren.parseCSV/0
The following arguments were given to anonymous fn/1 in Siren.parseCSV/0:
# 1
["41", "5", "59", "N", "80", "39", "0", "W", "Youngstown", "OH"]
anonymous fn/1 in Siren.parseCSV/0
(elixir 1.10.3) lib/stream.ex:482: anonymous fn/4 in Stream.filter/2
(elixir 1.10.3) lib/stream.ex:1449: Stream.do_element_resource/6
(elixir 1.10.3) lib/stream.ex:1609: Enumerable.Stream.do_each/4
(elixir 1.10.3) lib/enum.ex:959: Enum.find/3
(mix 1.10.3) lib/mix/task.ex:330: Mix.Task.run_task/3
(mix 1.10.3) lib/mix/cli.ex:82: Mix.CLI.run_task/2
Here my code:
defmodule Siren do
def parseCSV do
IO.puts("Let's parse CSV file...")
File.stream!("../name.csv")
|> Stream.map(&String.trim(&1))
|> Stream.map(&String.split(&1, ","))
|> Stream.filter(fn
["LatD" | _] -> false
end)
|> Enum.find(fn State -> String
[LatD, LatM, LatS, NS, LonD, LonM, LonS, EW, City, State] ->
IO.puts("find -> #{State}")
true
end)
end
end
And the csv file:
LatD,LatM,LatS,NS,LonD,LonM,LonS,EW,City,State
41,5,59,N,80,39,0,W,Youngstown,OH
42,52,48,N,97,23,23,W,Yankton,SD
46,35,59,N,120,30,36,W,Yakima,WA
42,16,12,N,71,48,0,W,Worcester,MA
43,37,48,N,89,46,11,W,WisconsinDells,WI
36,5,59,N,80,15,0,W,Winston-Salem,NC
49,52,48,N,97,9,0,W,Winnipeg,MB
39,11,23,N,78,9,36,W,Winchester,VA
34,14,24,N,77,55,11,W,Wilmington,NC
39,45,0,N,75,33,0,W,Wilmington,DE
48,9,0,N,103,37,12,W,Williston,ND
41,15,0,N,77,0,0,W,Williamsport,PA
37,40,48,N,82,16,47,W,Williamson,WV
33,54,0,N,98,29,23,W,WichitaFalls,TX
37,41,23,N,97,20,23,W,Wichita,KS
40,4,11,N,80,43,12,W,Wheeling,WV
26,43,11,N,80,3,0,W,WestPalmBeach,FL
47,25,11,N,120,19,11,W,Wenatchee,WA
41,25,11,N,122,23,23,W,Weed,CA
The first issue is here:
|> Stream.filter(fn
["LatD" | _] -> false
end)
all the lines should pass this and the only first one matches the given clauses. This would fix the issue
|> Stream.filter(fn
["LatD" | _] -> false
_ -> true
end)
or
|> Stream.reject(&match?(["LatD" | _], &1))
Enum.find(fn State -> String after looks unclear and would be surely the next issue. I failed to understand what have you tried to achieve here.
The general advice would be: don’t reinvent the wheel and use NimbleCSV written by José Valim to parse CSVs, because there are lot of corner cases (like commas inside quotes in any field etc,) handled properly in the aforementioned library.
Aleksei Matiushkin gave you the right answer but also you have this function:
fn
State ->
String
[LatD, LatM, LatS, NS, LonD, LonM, LonS, EW, City, State] ->
IO.puts("find -> #{State}")
true
end
It accepts two possible values, either State which is an atom, or a list of 10 specific atoms.
What you want to do is use variables, and variables in Elixir start with a lowercase letter or an underscore if it has to be ignored.
fn
state ->
String
[latd, latm, lats, ns, lond, lonm, lons, ew, city, state] ->
IO.puts("find -> #{state}")
true
end
But in this case, the first clause of the function will always match anything because it acts like a catch-all clause.
What you probably want is:
fn
[_latd, _latm, _lats, _ns, _lond, _lonm, _lons, _ew, _city, state] ->
IO.puts("find -> #{state}")
# here decide if you want to return true or false,
# for instance `state == NC`
true
end

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"

How to obtain a random word using function and dictionary? (Python 3)

The user has to select a category. And from there, the program has to generate a random word from the category list. If the user selected an invalid category, the program will prompt the user to choose a category again (loop the askCat function again).
import random
#Make word dictionary
wordDict = {'Animals':['Giraffe','Dog','Dolphin','Rabbit','Butterfly'], \
'Fruits': ['Apple','Pineapple','Durian','Orange','Rambutan'], \
'Colours': ['Red','Blue','Yellow','Green','Purple'], \
'Shapes': ['Heart','Circle','Rectangle','Square','Diamond']}
#Determine word category and random word
def askCat (wordDict):
category = str( input ("To start the game, please choose a category: \n Animals (a), Fruits (f), Colours (c), Shapes (s) "))
print()
if category == 'a':
print ("You chose the Animals category.")
cat = (wordDict['Animals'])
elif category == 'f':
print ("You chose the Fruits category.")
cat = (wordDict['Animals'])
elif category == 'c':
print ("You chose the Colours category.")
cat = (wordDict['Animals'])
elif category == 's':
print ("You chose the Shapes category.")
cat = (wordDict['Animals'])
else:
print ("You entered an invalid category. Try again!")
print()
askCat(wordDict)
return random.choice(cat)
#Print random word
randWord = askCat(wordDict)
print (randWord)
When on the first try, the user enter a valid category, the program works just fine. However, the problem I'm facing is that, when the user enter an invalid category the first time, and when he enter a valid category the second time, the program don't work anymore.
Please do help! Thanks (:
else:
print ("You entered an invalid category. Try again!")
print()
askCat(wordDict)
return random.choice(cat)
In the else branch, you are recursively calling the function again—which is okay—and then you discard its return value and return cat instead which, in this call of the function, was never set.
Instead, you should return the value from the recursive call:
else:
print ("You entered an invalid category. Try again!")
print()
return askCat(wordDict)
return random.choice(cat)
That way, when you call it recursively, the result from that call will be used, and not the one you tried to get from the current cat.
Furthermore, in each of your branches, you are doing cat = (wordDict['Animals']); you probably want to change that so you actually get fruits for f etc.
And finally, while using recursion is okay, it’s not the best way to handle this. Recursion always has a maximum depth it can into, so in the worst case, a user could keep answering the wrong thing increasing the recursion stack further, until the program errors out. If you want to avoid that, you should use a standard loop instead:
cat = None
while not cat:
# You don’t nee to use `str()` here; input always returns a string
category = input("To start the game, please choose a category: \n Animals (a), Fruits (f), Colours (c), Shapes (s) ")
print()
if category == 'a':
print("You chose the Animals category.")
cat = wordDict['Animals'] # no need to use parentheses here
elif category == 'f':
# ...
# and so on
else:
print("You entered an invalid category. Try again!")
# the loop will automatically repeat, as `cat` wasn’t set
# when we reach here, `cat` has been set
return random.choice(cat)
In your function askCat, if the user first enter a wrong category, you call again askCat. However, you don't return the value returned by that call.
Replace (in the function askCat):
askCat(wordDict)
to:
return askCat(wordDict)
However, I would strongly recommend you to use a while loop instead.

MySql Database connection with python

I've got an issue trying to connect to a database with python. It compiles without error but it doesn't seem to do anything. I'm not sure if I'm instantiating the class incorrectly or what the issue may be. Could someone point me in the right direction?
import _mysql
import MySQLdb
class Operations:
def open():
db=_mysql.connect("127.0.0.1","root","admin","test")
c=db.cursor()
#deletes the cursor
def close(self):
c.close()
#verifies the credentials and advances
def login(self):
print "Welcome to the online bookstore login!"
x = raw_input('Please enter your user id. ')
y = raw_input('Please enter your password. ')
c.execute("""SELECT userid,password FROM members WHERE userid = %s""", (x,))
z = c.password
if y == z:
member_menu()
else:
close()
def new_user(self):
print "Welcome to the Online book store new user registration page!"
print "To begin, please enter your first name: "
fName = raw_input('Please enter your first name: ')
lName = raw_input('Please enter your last name: ')
address = raw_input('Please enter your street address: ')
city = raw_input('Please enter your city: ')
state = raw_input('Please enter your state: ')
zip_code = raw_input('Please enter your zip code: ')
phone = raw_input('Please enter your phone number: ')
email = raw_input('Please enter your email: ')
user_ID = raw_input('Please enter your user id: ')
password = raw_input('Please enter your password: ')
c.executemany("""INSERT INTO members(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,) VALUES (fName, lName, address, city, state, zip_code, phone, email, user_id, password,)""")
print "Your account has been created. returning to the welcome menu. "
welcome()
def welcome(self):
choice = NONE;
print "**********************************************************************\n"
print "***\t\t\t\t\t\t\t\t ***\n"
print "***\t\tWelcome to the Online Book Store\t\t ***\n"
print "***\t\t\t\t\t\t\t\t ***\n"
print "**********************************************************************\n"
print "1. Member Login\n"
print "2. New Member Registration\n"
print "3. Quit\n"
choice = raw_input('Type in your option: ')
if choice == 1:
login()
elif x == 2:
new_user()
else:
close()
def member_menu(self):
x = NONE
print "**********************************************************************\n"
print "***\t\t\t\t\t\t\t\t ***\n"
print "***\t\t Welcome to the Online Book Store \t\t ***\n"
print "***\t\t\t Member Menu \t\t\t ***\n"
print "***\t\t\t\t\t\t\t\t ***\n"
print "**********************************************************************\n"
print "1. Search by Author/Title/Subject\n"
print "2. View/Edit Shopping Cart\n"
print "3. Check Order Status\n"
print "4. One Click Check Out\n"
print "5. Logout\n"
print "Type in your option: "
x = raw_input('Please enter your choice. ')
if x == 1:
close_conn(),
elif x == 2:
close_conn(),
elif x == 3:
close_conn(),
elif x == 4:
close_conn(),
else:
close_conn()
def main():
start = Operations()
print "Opening conenction to database"
start.welcome
if __name__ == '__main__':
main()
Well, there are so many problems with your code, that I'll probably miss some of them anyway.
Nothing happens, because your main() function and condition are both parts of the class definition, so all the interpreter sees are actually two imports and a class definition.
Let's say we unindented the main() definition and the condition. All that would happen then is creating an instance of Operations (with no special effects, as you have no custom constructor defined) and printing "Opening connection to database" to the screen, because all the last line in main() does is getting a reference to the welcome() method and ignoring it. You need to call it: start.welcome()
When you do call it, much more problems will appear. NameErrors will probably come first, as you are using identifiers that do not exist in given scopes. It seems you're new to Python's object model and probably coming from a language with a different approach, like C++. In Python all non-static and non-class instance methods take a reference to the object they're operating on as the first parameter, traditionally called 'self'. If you want to access any of the fields of the object, you need to do this through 'self', they are not visible to the interpreter otherwise. E.g.: you open a connection and keep the cursor as c, which you later reuse in other methods:
def open():
# ...
c=db.cursor()
# ...
def login(self):
# ...
c.execute("...")
That's incorrect for two reasons:
your open() method does not take self as a parameter
you're creating c as a local variable in scope of the open() method and then trying to access it in login(), which essentialy results in a "reference before assignment" error.
In order to be correct, it should be written like this:
def open(self):
# ...
self.c = db.cursor()
# ...
def login(self):
# ...
self.c.execute("...")
You're making the same mistake in many places. You need to call self.login(), self.new_user(), self.close(), etc.
You're using Python 2, at least according to the question's tags and there is one thing you need to remember when declaring classes in Python 2. There exist so called old- and new-style classes and what you want to do is use the new-style ones. Therefore your class must inherit from object:
class Operations(object):
# ...
They've finally decided to drop the old-style classes support in Python 3 and there's no need to explicitly inherit from object anymore, but while in Python 2, you need to cope with it.
While there are still some errors or potential errors (what is close_connection()?), I think it's enough for a good start ;). Good luck.