views:

173

answers:

2
+7  Q: 

Haskell typeclass

I have a Haskell typeclass question. I can't munge the syntax to get this (seemingly reasonable) program to compile under GHC.

import Control.Concurrent.MVar

blah1 :: [a] -> IO ([a])
blah1 = return

blah2 :: [a] -> IO (MVar [a])
blah2 = newMVar

class Blah b where
  blah :: [a] -> IO (b a)

instance Blah [] where
  blah = blah1

-- BOOM
instance Blah (MVar []) where
  blah = blah2

main :: IO ()
main = do
  putStrLn "Ok"

I get the following error message, which kind of makes sense, but I don't know how to fix it:

`[]' is not applied to enough type arguments
Expected kind `*', but `[]' has kind `* -> *'
In the type `MVar []'
In the instance declaration for `Blah (MVar [])'
+10  A: 

What you want isn't directly expressible. This is probably as close as you'll get:

newtype MVarList a = MVarList (MVar [a])
instance Blah MVarList where
    blah = fmap MVarList . newMVar
ephemient
I tried playing around with this to get a sense of why an instance of `Blah` where `blah` returns `IO (MVar [a])` isn't possible. Is it because the "b" type variable in the class definition of `Blah` must refer to a single type?
Michael Steele
It looks like the "b" type variable must be of kind * -> *, and there's no way to write out a type expression from `MyType -> MVar [MyType]`.
Michael Steele
Correct. For functions there exists `(.) :: (b -> c) -> (a -> b) -> a -> c` but there is no such composition for rank-1 (or rank-n) types.
ephemient
Yeah I came to the same conclusion. So, Haskell's type system is more expressive than its type syntax! Weird.
Geoff
It's not just syntax — Haskell doesn't support type level lambda expressions at all. Apparently because it makes unification during type inference impossible. See: http://www.mail-archive.com/[email protected]/msg20984.html (btw, the UHC/EHC referred to on that page, also **doesn't** support type level lambdas in Haskell syntax)
Tom Lokhorst
You can use the TypeCompose package by Conal Elliot: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/TypeCompose It would allow you to write `instance Blah (O MVar [])`, where O is the type-level composition.
Alexey Romanov
@Alexey: That's true, and also roughly equivalent to this: you get a `MVarList` or `MVar :. []` wrapped around your result either way.
ephemient
Conal
P.S. two "t"s in Elliott
Conal
+1  A: 

I was reading about Conal Elliot's TypeCompose library, and was reminded of this question. Here's an example of how you can do type-level composition.

{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Main where

...

import Control.Compose

...

instance Blah (MVar `O` []) where
  blah = liftM O . blah2

...
Michael Steele