OpenGL keyboardMouseCallback ...confused over type

I asked a question the other day about passing application state around an OpenGL program and I've consulted RWH and the inter-web extensively and I think I am on the right lines so far! In my main program, I use Data.IORef like this: gameState <- newIORef $ newGameState and GameState contains all the stuff to do with the game model. Next the confusing bit... to make myself learn things I typed out the full type of the keyboardMouseCallback function: myKeyMouse :: Key -> KeyState -> Modifiers -> Position -> IO () and slotted it into the code like so: keyboardMouseCallback $= Just myKeyMouse In order to be able to pass the "IORef GameState" into the keyboard handler I have to re-type my keyboardMouseCallback function like so: myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO () and modify the assignment in main to this: keyboardMouseCallback $= Just (myKeyMouse gameState) But I haven't really understood *why* that is the case. The displayCallback is also similarly affected as it is now: myDisplay :: IORef GameState -> IO () ... displayCallback $= (myDisplay gameState) and again I am not sure what magic is happening here to have made it compile and work! My real source of confusion is over my apparent victory over the type system in that I appear to have extended the type signature (is that the correct term?) for both of the callbacks be prepending "IORef GameState" to them and yet it all compiles and works. Is "prepending" the key ? I feel a tingling of Eureka! organ but I am not sure yet. Explanations are welcome as I am sure there is something "important" here that will really advance my understanding of the type system. It smells like curry but I don't think... hang on... the keyboard one is wrapped in the Maybe monad... therefore(?) the function I am handing in can be *any* type so long as they actually match types! Is that it then? I can smell partial application and curry now. HELP! Thanks, Sean.

confusing bit... to make myself learn things I typed out the full type of the keyboardMouseCallback function:
(you'll actually do this in production code too! It's a good habit.)
myKeyMouse :: Key -> KeyState -> Modifiers -> Position -> IO ()
and slotted it into the code like so:
keyboardMouseCallback $= Just myKeyMouse
Okay -- so here we're seeing that keyboardMouseCallback itself is an IORef:
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ()))
Keep in mind also:
($=) :: IORef a -> a -> IO ()
In order to be able to pass the "IORef GameState" into the keyboard handler I have to re-type my keyboardMouseCallback function like so:
myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO ()
and modify the assignment in main to this:
keyboardMouseCallback $= Just (myKeyMouse gameState)
Now let's look at the reason it works. Your types are:
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ())) myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO ()
Now, what's the type of the expression `myKeyMouse gameState'? Well, you've assigned the first argument -- all functions are curried -- so you get a partial application:
myKeyMouse gameState :: Key -> KeyState -> Modifiers -> Position -> IO ()
Now you wrap that in Just:
Just (myKeyMouse gameState) :: Maybe (Key -> KeyState -> Modifiers -> Position -> IO ())
What was the type of keyboardMouseCallback again?
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ()))
So the partial application returns a function with the first argument fixed -- and the resulting function's type is that which is used for the callbacks. HTH a little. A

Arlen, thanks for that... I think it confirms that my head was on "the right track" but it was pitch-black in there and I had my eyes closed. It saddens me that the answer to one of my questions is harder to understand than the question was to write in the first place, LMAO, I love Haskell for this... it's making me think about stuff more and more and I like it. I am determined that Haskell is the end of the line until son of Haskell comes out! LOL. Would you mind clarifying a point for me regarding partial application, currying and types as I am now a bit confused... I've written enough point free stuff to understand both partial application and currying so that's fine... what's confusing me is in your reply you say: "So the partial application returns a function with the first argument fixed -- and the resulting function's type is that which is used for the callbacks. " Am I correct in thinking then that data types are constructors, *are* _just functions too_, I think that's correct and if so I will re-read RWH in certain places to see how it wasn't clear enough to me... On page 42(!) of Real World Haskell it says: "We can create a new value of type BookInfo by treating Book as a function and applying it with arguments of types Int, String, and [String]". On page 41 we have this definition: data BookInfo = Book Int String [String] deriving (Show) So, is "Book" a function or is it not a function, as implied by the statement "by treating Book _as_ a function" ? That would help me greatly, to know if data constructors are just functions or something "special" (constructors of data types) but for all intents and purposes they smell, act, look and behave as functions. Singing: "La dee da La dee dee, Eric the half-a-boook...." I created a file containing that definition and loaded it into ghci: *Main> :type Book Book :: Int -> String -> [String] -> BookInfo This looks like a function to me! LOL, so I added another constructor like so: data BookInfo = Book Int String [String] | Paperback Int String [String] deriving(Show) ...and was beheld unto me... *Main> :type Paperback Paperback :: Int -> String -> [String] -> BookInfo Hmmm... another function returning the same -*-. So is the sentence a bit misleading to say "as a function" when it means, at least as far as I can see "because Book _is_ a function" ? I think I am understanding things a little better now but some expert clarification would help! Is this line of reasoning correct: o Haskell is functional therefore... o *everything* is a function o functions are automatically curried where required (to get partials)... o data constructors *are* functions (as opposed to being a separate thing like structs in C for example)... o data constructors can be partially applied (Eureka![?]) Man, I think your answer is more understandable just from typing the above questions, surely the sign of a great answer to a question. Thanks! Sean. On 30/06/11 23:53, Arlen Cuss wrote:
confusing bit... to make myself learn things I typed out the full type of the keyboardMouseCallback function: (you'll actually do this in production code too! It's a good habit.)
myKeyMouse :: Key -> KeyState -> Modifiers -> Position -> IO ()
and slotted it into the code like so:
keyboardMouseCallback $= Just myKeyMouse
Okay -- so here we're seeing that keyboardMouseCallback itself is an IORef:
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ()))
Keep in mind also:
($=) :: IORef a -> a -> IO () In order to be able to pass the "IORef GameState" into the keyboard handler I have to re-type my keyboardMouseCallback function like so:
myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO ()
and modify the assignment in main to this:
keyboardMouseCallback $= Just (myKeyMouse gameState) Now let's look at the reason it works.
Your types are:
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ())) myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO ()
Now, what's the type of the expression `myKeyMouse gameState'? Well, you've assigned the first argument -- all functions are curried -- so you get a partial application:
myKeyMouse gameState :: Key -> KeyState -> Modifiers -> Position -> IO () Now you wrap that in Just:
Just (myKeyMouse gameState) :: Maybe (Key -> KeyState -> Modifiers -> Position -> IO ())
What was the type of keyboardMouseCallback again?
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ()))
So the partial application returns a function with the first argument fixed -- and the resulting function's type is that which is used for the callbacks.
HTH a little.
A

Hi Sean, On 1/07/2011 5:04 PM, Sean Charles wrote:
It saddens me that the answer to one of my questions is harder to understand than the question was to write in the first place, LMAO, I love Haskell for this...
Such is typically my experience, too :D
Am I correct in thinking then that data types are constructors, *are* _just functions too_, I think that's correct and if so I will re-read RWH in certain places to see how it wasn't clear enough to me...
Yes, you're right. I don't mean to imply there's anything special about the function you get as a return result of only a partial application. After all, for some f where:
f :: Int -> Char -> String -> a
Then:
f 1 'a' "xyz"
is exactly the same as saying:
((f 1) 'a') "xyz"
i.e. each argument is bound and fills in the first type in the function type. Thus:
f :: Int -> Char -> String -> a f 1 :: Char -> String -> a f 1 'a' :: String -> a f 1 'a' "xyz" :: a
And thus all parameters 'assigned' (if you like) yield the eventual result (of no type in particular in this example).
On page 42(!)
:D
On page 41 we have this definition: data BookInfo = Book Int String [String] deriving (Show)
So, is "Book" a function or is it not a function, as implied by the statement "by treating Book _as_ a function" ?
I'm not sure how they're represented internally, but they (data constructors) might as well be functions -- or values, in the case of nullary constructors (no-argument constructors, like Nothing of the Maybe type) -- except that you can also pattern match on them! Outside of the content of pattern matching, they act just like functions (or plain values) which can be used curried to all your heart's content. Yum!
*Main> :type Book Book :: Int -> String -> [String] -> BookInfo
This looks like a function to me! LOL, so I added another constructor like so:
data BookInfo = Book Int String [String] | Paperback Int String [String] deriving(Show)
...and was beheld unto me...
*Main> :type Paperback Paperback :: Int -> String -> [String] -> BookInfo
Hmmm... another function returning the same -*-. So is the sentence a bit misleading to say "as a function" when it means, at least as far as I can see "because Book _is_ a function" ?
The value you get when you say `Book' or `Paperback' in a value context is indeed a function, but those words can also be used in pattern matching. I think this more-or-less sums up dealing with them. When you use record types (may be yet to come in RWH), you can also use them as functions, or you can use the record syntax (which is just sugar atop a normal function use).
I think I am understanding things a little better now but some expert clarification would help!
In which case some experts' opinions on whether calling them functions (or not) is just a game of semantics would be much appreciated!
Is this line of reasoning correct:
o Haskell is functional therefore... o *everything* is a function
Not quite - your plain values aren't (7 isn't a function; neither is 'Just 3'. 'Just' is, though! Comes in handy. e.g. `map Just' returns a function that takes a list and returns the same list with all elements in a `Just'. Of course there are nicer ways to do this more monadically ..). But functions *are* first-class values.
o functions are automatically curried where required (to get partials)...
Yep. I don't see it so much as 'automatic currying' (though it's accurate), but more that
f x y = x + y
is a syntax sugar for
f = \x -> \y -> x + y
, thus currying. (I may be off on the technical details, but I think evaluating to WHNF may imply such a conversion?)
o data constructors *are* functions (as opposed to being a separate thing like structs in C for example)...
Yes, and pattern matchable. Note that structs also miss out on the possibities of Haskell types -- there can be many data constructors to one type (which you usually would use a tagged union for, in C, and indeed it's the same thing in Haskell).
o data constructors can be partially applied (Eureka![?])
Indeed! This can often come in handy.
Man, I think your answer is more understandable just from typing the above questions, surely the sign of a great answer to a question.
I'm glad it helped you, and that you think so, but most of the work happened in your head!
Thanks! Sean.
Cheers, Arlen
On 30/06/11 23:53, Arlen Cuss wrote:
confusing bit... to make myself learn things I typed out the full type of the keyboardMouseCallback function: (you'll actually do this in production code too! It's a good habit.)
myKeyMouse :: Key -> KeyState -> Modifiers -> Position -> IO ()
and slotted it into the code like so:
keyboardMouseCallback $= Just myKeyMouse
Okay -- so here we're seeing that keyboardMouseCallback itself is an IORef:
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ()))
Keep in mind also:
($=) :: IORef a -> a -> IO () In order to be able to pass the "IORef GameState" into the keyboard handler I have to re-type my keyboardMouseCallback function like so:
myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO ()
and modify the assignment in main to this:
keyboardMouseCallback $= Just (myKeyMouse gameState) Now let's look at the reason it works.
Your types are:
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ())) myKeyMouse :: IORef GameState -> Key -> KeyState -> Modifiers -> Position -> IO ()
Now, what's the type of the expression `myKeyMouse gameState'? Well, you've assigned the first argument -- all functions are curried -- so you get a partial application:
myKeyMouse gameState :: Key -> KeyState -> Modifiers -> Position -> IO () Now you wrap that in Just:
Just (myKeyMouse gameState) :: Maybe (Key -> KeyState -> Modifiers -> Position -> IO ())
What was the type of keyboardMouseCallback again?
keyboardMouseCallback :: IORef (Maybe (Key -> KeyState -> Modifiers -> Position -> IO ()))
So the partial application returns a function with the first argument fixed -- and the resulting function's type is that which is used for the callbacks.
HTH a little.
A

and modify the assignment in main to this:
keyboardMouseCallback $= Just (myKeyMouse gameState) I think that part of my confusion was, on reflection, caused by the fact
On 30/06/11 23:53, Arlen Cuss wrote: [snip] that coming from a procedural background, the syntax of "Just (myKeyMouse gameState) still reads as "function call arguments", so if I may be permitted to expand on that to see if I now understand Haskell a little more ... The form: "Just (myKeyMouse gameState)" looks like its calling the Just function with two parameters as the () is also used to define a tuple. So is (myKeyMouse gameState) a tuple of one, the result of calling that function with that parameter or is just a way of ensuring that the function is performed before it is passed to Just as the one and only parameter? I know the correct answer but I did sometimes get confused over when is a tuple "()" not a tuple, especially in things like this: foo (x:xs) = ... I *know* it is pattern matching using ':' and that ':' takes a thing and a list of things and returns a list of same things but old habits.. DOH! Back to the chase. If I had rewritten the Just called like this I think it would have been clearer about what was happening: Just $ myKeyMouse gameState as that quite clearly says, call myKeyMouseFirst and then hand the result to Just. From that point, Arlens great description of how it trundles through the type system, resulting in a partially evaluated function that has the *same* type as the expected one for the keyboardMouseCallback is really making it clearer for me now. That was a loud Eureka moment in my kitchen over breakfast this morning I can tell you! It just needs to settle in and join the rest of the facts jostling for top position on the "Don't forget..." list. Once again "list", I thank thee muchly for helping this troubador of trouble travel the road to Haskell... :)

Just to elaborate a bit: On Friday 01 July 2011, 10:19:04, Sean Charles wrote:
On 30/06/11 23:53, Arlen Cuss wrote: [snip]
and modify the assignment in main to this: keyboardMouseCallback $= Just (myKeyMouse gameState)
I think that part of my confusion was, on reflection, caused by the fact that coming from a procedural background, the syntax of "Just (myKeyMouse gameState) still reads as "function call arguments", so if I may be permitted to expand on that to see if I now understand Haskell a little more ...
The form: "Just (myKeyMouse gameState)" looks like its calling the Just function with two parameters as the () is also used to define a tuple.
No, the tuple constructors have commas, "(a,b)" is a tuple, "(a b)" is a grouping, meaning "the function a applied to the argument b". Putting such in parentheses may be necessary if e.g., like here, that expression is the argument of another function. Just (myKeyMouse gameState) === Just $ myKeyMouse gameState is "the function [value constructor] Just, applied to the result of applying myKeyMouse to gameState".
So is (myKeyMouse gameState) a tuple of one, the result of calling that function with that parameter or is just a way of ensuring that the function is performed before it is passed to Just as the one and only parameter?
Yes, except Haskell doesn't have a concept of one-tuples, they're just plain values.
I know the correct answer but I did sometimes get confused over when is a tuple "()" not a tuple, especially in things like this:
Parentheses are a) a value [or type] constructor, when there's nothing in between: () b) grouping signifiers, like in (3+4)*5 or in foo (x:xs) = ... where they delimit the pattern to match; without the parentheses, it would be parsed as (foo x) : xs = ... which would be a definition of (:), except it would be a syntax error [foo x is not a valid patter] and (:) is an infix-constructor, which can't be defined by a function binding] c) a means to make prefix functions from infix operators, like (++) Visually similar to parentheses, but different are tuple constructors: (,) :: a -> b -> (a,b) (,,) :: a -> b -> c -> (a,b,c) ... the parentheses are part of the constructors, these constructors can be applied prefix or roundfix (special wired in syntax, as for lists, "[] a" is the same type as "[a]", but for tuples, it works for values too).
foo (x:xs) = ...
I *know* it is pattern matching using ':' and that ':' takes a thing and a list of things and returns a list of same things but old habits.. DOH!
Back to the chase.
If I had rewritten the Just called like this I think it would have been clearer about what was happening:
Just $ myKeyMouse gameState
as that quite clearly says, call myKeyMouseFirst and then hand the result to Just. From that point, Arlens great description of how it trundles through the type system, resulting in a partially evaluated function that has the *same* type as the expected one for the keyboardMouseCallback is really making it clearer for me now. That was a loud Eureka moment in my kitchen over breakfast this morning I can tell you!
It just needs to settle in and join the rest of the facts jostling for top position on the "Don't forget..." list.
Once again "list", I thank thee muchly for helping this troubador of trouble travel the road to Haskell...
:)

Hello. I didn't read the thread, but I think, that this code help you https://gist.github.com/1031576.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 01/07/11 19:58, Alexey G wrote:
Hello. I didn't read the thread, but I think, that this code help you https://gist.github.com/1031576.
Thanks! This is a great reference. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQIcBAEBAgAGBQJODpuiAAoJEDiWqExGnQ/QdAwQAJOl5d7jXIqDdwzkZDqvdFsw 7mri7D75ljHQHCbSA+uM+93lnw064eUPncrfWVjlLT0wiVq7UaFzBcOe5Rueg4RX YPuKlOyBozyABz/ilXbtWYqOr+bDEOqzpEAZKzCTAOJ7d1QREa+kYcRwekIEQHJc IVnaqlh+n1DUC65FH9WeB09G+pIrwV0NEg0+V92T73jfr3BZhH6isRLTCoEGMOXw 8d2b+efSjfiWProHtyYln9cm+wWwIp54LRzl9qI5AYf50bg3J2yXnXinOAGU3Xxw Ob9VMJzrsD9KLLSuX5DXbaapRdbsRmAb/PKWaZCpxvWLqSy1b+Um48ioUqPRRdoL 4nxcCAX/Dnip4+BBdzpGDbvc3efIny/SAoTtuhLpN20LX5yzd27XbrZvcWcDP+Ul jzOt7/EeGVvT3Fy7gU5ht5dtpmIF+baQ9m5k/hfsB1J5rGtq4TboEXHx5h8CHUzL Qo32CpnGJjIBngmq95mAVvGjmj6hwtbMBQOujV85g85/rx/CdwPgHmUNoJuAVSsV lftdCN/MuTDtroq0KwwDrfAu6N2GU8hZqA/nRbBSKV9ugoLmulfHgQlF0fmxQoTB xWLYv6vJH5PQCKs8VDAIwTG+DbtBLjXdZSO+A2vtRYQrF87s4UyjyUbp/tkrwPOM 4ppkLXwJCLT7C7VWvpUK =mLYx -----END PGP SIGNATURE-----
participants (4)
-
Alexey G
-
Arlen Cuss
-
Daniel Fischer
-
Sean Charles