A way to declare a constant value in a type class
haskell, typeclass
Solution
The simplest thing you can do is
class FromRow a => StdQueries a where
byId :: Int -> QueryM (Maybe a)
defaultById :: FromRow a => String -> Int -> QueryM (Maybe a)
defaultById table = fmap listToMaybe . queryM sql . Only
where sql = read $ "SELECT * FROM " ++ table ++ " WHERE id = ?"
instance StdQueries SomeType where
byId = defaultById "the_constant_value_for_this_type"
This is simple, but if you have more than one function that needs access to the `table` value, you have to specify that value more than once.
You can avoid that, and sabauma's need for `undefined` and `{-# LANGUAGE ScopedTypeVariables #-}` like this:
newtype Table a = Table String
class FromRow a => StdQueries a where
table :: Table a
byId :: Int -> QueryM (Maybe a)
byId = defaultById table
defaultById :: StdQueries a => Table a -> Int -> QueryM (Maybe a)
defaultById (Table table) = fmap listToMaybe . queryM sql . Only
where sql = read $ "SELECT * FROM " ++ table ++ " WHERE id = ?"
instance StdQueries SomeType where
table = Table "the_constant_value_for_this_type"
The magic here is the type signature for `defaultById`, which forces `byId` to provide the `table` from the same instance. If we provided `defaultById :: (StdQueries a, StdQueries b) => Table a -> Int -> QueryM (Maybe b)` then `defaultById` would still compile, but we would still get a similar error message to the one in your question: the compiler would no longer know which definition of `table` to use.
By making `Table a` a `data` structure instead of a `newtype` wrapper, you can extend this to specify many fields in the constant, if required.
Problem
I want to declare a typeclass that has some implemented functions which utilize an unimplemented constant value (`table`): ``` class FromRow a => StdQueries a where table :: String byId :: Int -> QueryM (Maybe a) byId = fmap listToMaybe . queryM sql . Only where sql = read $ "SELECT * FROM " ++ table ++ " WHERE id = ?" ``` The idea is simple: I want to get the `byId` (and other similar functions) available by instantiating this typeclass by specifying just the `table`: ``` instance StdQueries SomeType where table = "the_constant_value_for_this_type" ``` But the compiler keeps complaining with the following message: ``` The class method `table' mentions none of the type variables of the class StdQueries a When checking the class method: table :: String In the class declaration for `StdQueries' ``` Are there any solutions to that kind of a problem? Can tricking with `newtype` help or anything like that?