Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Totally new to haskell (learning it for a class in school)

It seems pretty cool so far, but I'm stumped on what I thought was a pretty basic operation:

I have defined a data type like so:

Data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun

and I need to create an instance of Show that will print out full names of the days like

>Show Mon
"Monday"

My textbook says that defining the Day data type this way is an enum type, so I thought "well this is easy! I can just make a list of the strings of day names and use a day value as the index!"

Haskell does not work that way, apparently.

I thought I was going to write sometihng like
code:
getDayName :: Day -> String
getDayName m = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]!!m

instance Show Day where
        show m = show (getDayName m)
but m needs to be converted to an int. Okay that makes sense. Googling how to convert an enum type into an int type makes it seem like this is a totally wrong thing to do and not the haskell way of doing things.

am I barking up the wrong tree here?

Adbot
ADBOT LOVES YOU

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

dirby posted:

Your approach would require building a mapping to ints and this list, neither of which you need. Just cut out the middleman: you want show Mon = "Monday", etc. so write those...

Wait really? I should just make a statement for each possible value of Day? I thought that sounded like poor solution that does not scale well...

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

dirby posted:

If your type has more than, say, ten constructors, then you're probably doing your type wrong. That said, it'seems possible to use enumerated type stuff to do this, so if you specifically want help doing that, say so, I guess.

nope, I just didn't want my professor to look at my code and say "well you hardcoded every value like an idiot freshman" instead of using all the map stuff we talked about in class. But since it sounds like map is more complicated and expensive here, the way you suggested, which I dismissed, is the better way.

edit:^ yes, because I thought there would be an easy way to get at the int value of a enum type, like there is in c.

edit2: But thanks, I got it working no problem now.

Snak fucked around with this message at 01:23 on Sep 17, 2015

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Wow. Thanks for all the feedback. It was a really simple, basic assignment to demonstrate we knew how to make basic Haskell functions. I was only confused because I don't have a feel for "the Haskell way" and I was bringing a bunch of C baggage along for the ride.

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
I'm back with more super-newbie questions about Haskell...


To use my previous example, let's say I have defined a type
code:
data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving (Eq, Enum, Show)
Is there a way for me to iterate through the possibly values of the Day type?

Like if I wanted to do a "for each day in (Mon, Tue, Wed, Thu, Fri, Sat, Sun)" type thing, is that possible to get just from the type itself, or do I need to hardcode a list?

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
awesome. That is so great. Thanks

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
I have another horribly noobly question:

I know that defining veriables inside the then clause of an if "statement" is a terrible and un-Haskell-y thing to do, but I don't know how else to accomplish what I'm trying to do. I have a great and effective Haskell expression that gets me a list of two elements. I need the different of those two elements. I want to assign the difference of the value at index 1 and the value at index 0 to the then clause. I cannot figure out how to do it.

So i thought "oh, I will make a variable" and it looks something like this
code:
foo :: ( a -> a ) -> Maybe Int
foo f = if <some basic condition>
		then
			Just (list!!1 - list!!0) where list =  <long expression that generates the list>
		else
			Nothing
And no matter what I do it says there's a missing else clause.

It would probably work if I just skipped the variable and put the whole expression that generates the list in both places I currently use the list variable, but that would be really ugly

edit: it does in fact work perfectly if I do that.
I was going to say that I can't generate the list outside of the then clause, because then it will search an infinitely iterated list for a term that may never appear,
but because of lazy evaluation, can I safely do that? Because it won't evaluate until it's returned in the then clause anyway? That sounds horrible though.

Snak fucked around with this message at 00:19 on Sep 29, 2015

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Thanks. That also makes sense. I really like Haskell and functional programming so far, it's just. so. different.

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
I am back with more last-minute homework-related questions.

In my class we have been using Haskell primarily to explore the grammar and syntax of languages. To than end, our homework uses a very simple "while language" we have defined in data types. This aspect of things is pretty intuitive to me, so I'm not having a lot of trouble there. The following is an excerpt from my homework, and is the subject of my current confusion:
(variables are declared with the "newint" statment)

quote:

Below is a code outline for this static check. (checkS s []) is True if s
contains no undeclared variables. (check (NewInt x c) ds) records in ds that x
is declared when it recursively checks c
. Complete the definitions of checkS,
checkE and checkB. Test your solution with check below. In particular, (check
"newfib.wh") should be True and (check "fib.wh") should be False.
Specifically the sentence that I bolded. As usual, it is late on the due date, so if you aren't able to help me I completely understand.

I believe that "check" in (check (NewInt x c) ds) supposed to be "checkS", because check only takes one parameter: fname. I assume that this must be the case. So checkS's second parameter is the location that the result of the check will stored. This is why it is initially empty. The c in "NewInt x c" is the code block in which x is defined. Which makes sense; c is a statment, which means it can be a sequence of statements. So we can recursively checkS on each of these statements. In order to determine... something.

I guess I'm having trouble understanding the fail condition here. Since a program that declares it's variables with NewInt will have newint statements at the beginning of it's program. These statements are "hit" first by checkS, hence the need for recursion from that point, as described in the example. But what are we looking for? Well we're looking for variables that aren't declared by a newint. So what does that look like? Well it's any variable that isn't currently inside the recursion started by it's newint statement.

So that's what I understand. But I still have no idea how to implement it. Sorry for rambling, I wanted to describe my understanding as accurately as possible.

If my understanding is sort of correct, is there some kind of hint that you could give me to help me understand what the failure scenario of this test looks like?

For reference, here is the skeleton provided so you can see structure of the implementation I am expected to use.
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of
                 (Skip _)       -> undefined
                 (Assign x e _) -> undefined
                 (Seq cs)       -> undefined
                 (If b _ s1 s2) -> undefined
                 (While b _ c)  -> undefined
                 (NewInt i c)   -> undefined
I am not asking for anyone to give me the answer or help me cheat.

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Whoops I guess I didn't provide enough information. When checkS is called, it is called like this
code:
check fname
  = do { input <- readFile fname
       ; putStr input
       ; case parse program fname input of
            Left err -> error (show err)
            Right x  -> return (checkS x [])
       }
So the list is initially empty. But now I think I've answered my own question. Any time a variable is encountered in a statement, add it to the list. Or something.

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

sarehu posted:

Well, they're saying "add it to the list," but that's speaking in functional programmer codetalk for "put it in the list you return/pass to some other function."

Okay but I'm still totally lost.

here is what I have so far, which is wrong and broken
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of -- this is obviously wrong,
                 (Skip _)       -> checkS (tail c) r --this statment does not contain any variables, but we still need to check the rest, so drop it from c and recurse
                 (Assign x e _) -> if (x `elem` r) then checkS (tail c) r else False --if the variable being assigned is in scope, continue, else return False
                 (Seq cs)       -> False
                 (If b _ s1 s2) -> False
                 (While b _ c)  -> False
                 (NewInt i c)   -> checkS c (i : r) --continue checking c, with i added to list of in scope variables
You can tell that it's wrong right away, because c is not a list. So the tail function obviously does not belong there. The recursion itself needs to be implemented in the Seq case, since that's the only place the code knows there's more than one statement.

man I love/hate this class. I spend hours and hours trying to understand that idea that the assignments are trying to communicate, because I simply don't understand what they're asking me. When I understand what they are ask, implementing those ideas becomes trivial. On the last assignment I spend an hour talking with the TA just to determine that that yes, translating the psuedo-code into the abstract language was what we were supposed to do. It's like pulling teeth to get these guys who consider all this stuff second nature to just explain what they want so I can start thinking about the problem.

edit: I am making progress, but I am still unsure how to handle the Seq case. Here is what I have now:
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of -- this is obviously wrong,
                 (Skip _)       -> True --this statement contains no variables, so it cannot contain any undeclaired ones
                 (Assign x e _) -> (if (x `elem` r) then True else False) && checkE e r--if the variable being assigned is in scope, continue, else return False
                 (Seq cs)       -> checkS (head cs) r && checkS (Seq (tail cs)) r
                 (If b _ s1 s2) -> checkB b r && checkS s1 r && checkS s2 r
                 (While b _ c)  -> checkB b r && checkS c r
                 (NewInt i c)   -> checkS c (i : r) --continue checking c, with i added to list of in scope variables

Snak fucked around with this message at 06:29 on Nov 14, 2015

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Well I think I did get it all figured out last night. Thanks for the help. When I am stuck on a programming problem, I find that simply trying to explain the problem to other people often causes me to understand it better and make a breakthrough.

Jabor posted:

What are the actual semantics of NewInt? It looks to me like you might be overthinking it a little bit.

Well NewInt isn't a function in Haskell, it's a statement in the abstract language that we have defined. Here is the language:
code:
type  Ident = String
type  Label = Int

data AExp --Arithmetic Expression
  = Var Ident
  | IntLit Int
  | AOp String AExp AExp
  deriving Eq

data BExp --Boolean Expression
  = BUnOp String BExp --I forget what this is, I think it's just for handling "not <bool>" as being a boolean expression
  | BoolLit Bool --Boolean literal, ie True or False
  | BOp String BExp BExp --boolean operation
  | RelOp String AExp AExp -- boolean relation, >, <, ==, etc. 
  deriving Eq

data Stat --Statement
  = Assign Ident AExp Label
  | Skip Label
  | Seq [Stat]
  | If BExp Label Stat Stat
  | While BExp Label Stat
-- The new statement for defining variables:
  | NewInt Ident Stat
  deriving Eq
So the syntax of NewInt is "Newint Ident Stat", where Ident is the string identifier (the name) of the variable being declared and Stat is almost certainly of type Sequences of statements, which is what the scope of the variable will be.

Here is the code that ended up working. I am not 100% sure that is correct, because I was down to the wire and figured it out with 15 minutes left on the deadline and it passed the obvious tests.
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of 
                 (Skip _)       -> True --this statement contains no variables, so it cannot contain any undeclaired ones
                 (Assign x e _) -> checkE (Var x) r && checkE e r--if the variable being assigned is in scope, continue, else return False
                 (Seq cs)       -> if length cs > 1 then (checkS (head cs) r && checkS (Seq (tail cs)) r) else checkS (head cs) r
                 (If b _ s1 s2) -> checkB b r && checkS s1 r && checkS s2 r
                 (While b _ c)  -> checkB b r && checkS c r
                 (NewInt i c)   -> checkS c (i : r) --continue checking c, with i added to list of in scope variables

checkE :: AExp -> [Ident] -> Bool
checkE e r = case e of
                  (Var x)        -> if (x `elem` r) then True else False --THIS IS THE FAILURE CASE I WAS LOOKING FOR. Took me long enough. 
                  (IntLit i)     -> True --not a variable, so not an undeclared variable
                  (AOp op e1 e2) -> checkE e1 r && checkE e2 r

checkB :: BExp -> [Ident] -> Bool
checkB b r = case b of
                  (BUnOp "not" b)    -> checkB b r
                  (BoolLit b)        -> True
                  (BOp "&" b1 b2)    -> checkB b1 r && checkB b2 r
                  (RelOp ">" e1 e2)  -> checkE e1 r && checkE e2 r
                  (RelOp "<=" e1 e2) -> checkE e1 r && checkE e2 r
Again, thanks for letting me post my bullshit here, it was actually really helpful.

Snak fucked around with this message at 19:40 on Nov 14, 2015

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
I got a B in my class, thanks for all the help everyone. I'm not sure I learned much from the class, because I got a 68 on the midterm, and a 69 on the final, but I got over 90% on all the assignment, and 100% and the extra credit on the last assignment.

There's lots of stuff I still don't understand though. What's a good resource for explaining the role of monads in language design? Like I get how they are used in Haskell, but in the hypothetical scenario where I was constructing a language, I wouldn't able to implement monads because I don't "get" them on a more basic level.

Adbot
ADBOT LOVES YOU

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

Charlie Mopps posted:

For people wanting to learn Haskell i can recommend the book Haskell Programming From First Principles. Its quite expensive ($60) and still in early access, but its up to ~1000 pages already. Its pretty much the only book thats up to date and explains Haskell from the basis. Its goal is to explain Haskell in such a way that you can learn and understand any Haskell library thats out there, instead of teaching you say web dev with a framework or whatever. A sample can be found here.

Oooh, I hope it stays that cheap until I get money. I only know C, Java, Python and some Haskell, but Haskell has pretty much become my favorite language. It makes so much sense to me.

  • Locked thread