Type Constraints : Can they be inferred from the datatype of a function's arguments?
This
newtype ( Show a , Show b , Show c ) => T a b c = T Int
t :: T a b c -> a -> b -> c -> String
t ( T x ) a b c = show a ++ show b ++ show c
gives me an error:
No instance for (Show c)
arising from a use of `show'
In the second argument of `(++)', namely `show c'
In the second argument of `(++)', namely `show b ++ show c'
In the expression: show a ++ show b ++ s开发者_Python百科how c
But this
newtype ( Show a , Show b , Show c ) => T a b c = T Int
t :: ( Show a , Show b , Show c ) => T a b c -> a -> b -> c -> String
t ( T x ) a b c = show a ++ show b ++ show c
compiles.
Why?
In the first case, doesn't "T a b c" already imply that "( Show a , Show b , Show c )"? Why is it necessary to explicitly specify the constraint?
No, putting a context on a data (newtype) definition never did quite what one might expect. It only changes the type of the constructor when constructing values, nothing new happens when pattern matching. It's a basically useless feature and it has been removed in the latest version of Haskell.
What you expect is quite reasonable, but it's not what data type contexts do.
What @augustss said is correct, however you can achieve something similar using GADTs.
{-# LANGUAGE GADTs #-}
data T a b c where
T :: (Show a, Show b, Show c) => Int -> T a b c
t :: T a b c -> a -> b -> c -> String
t (T x) a b c = show a ++ show b ++ show c
In most cases, however, putting the constraint on the function is the right thing to do.
精彩评论