[Haskell-beginners] OpenGL keyboardMouseCallback ...confused over type

Arlen Cuss celtic at sairyx.org
Fri Jul 1 09:21:41 CEST 2011


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
> 




More information about the Beginners mailing list