Created
March 3, 2015 22:39
-
-
Save Sam-Serpoosh/4463277597a03b2b4341 to your computer and use it in GitHub Desktop.
Type Deduction problem in Haskell (type class and instance declarations)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances #-} | |
module Sized where | |
import Data.Monoid | |
newtype Size = Size { getSize :: Int } | |
deriving (Eq, Ord, Show, Num) | |
class Sized a where | |
size :: a -> Size | |
instance Sized Size where | |
size = id | |
instance Monoid Size where | |
mempty = Size 0 | |
mappend = (+) | |
data JoinList m a = Empty | |
| Single m a | |
| Append m (JoinList m a) (JoinList m a) | |
deriving (Eq, Show) | |
testSomething :: (Sized b, Monoid b) => JoinList b a -> JoinList b a | |
testSomething (Single s value) = let numOfElem = getSize (size s) | |
newSize = Size (numOfElem + 1) | |
in Single newSize value | |
testSomething jl = jl | |
tree = Single (Size 5) "A" | |
main :: IO () | |
main = putStrLn $ show $ testSomething tree | |
{- | |
Produces the following error: | |
Sized.hs:27:44: | |
Could not deduce (b ~ Size) | |
from the context (Sized b, Monoid b) | |
bound by the type signature for | |
testSomething :: (Sized b, Monoid b) => | |
JoinList b a -> JoinList b a | |
at Sized.hs:24:18-68 | |
‘b’ is a rigid type variable bound by | |
the type signature for | |
testSomething :: (Sized b, Monoid b) => | |
JoinList b a -> JoinList b a | |
at Sized.hs:24:18 | |
Relevant bindings include | |
s :: b (bound at Sized.hs:25:23) | |
testSomething :: JoinList b a -> JoinList b a | |
(bound at Sized.hs:25:1) | |
In the first argument of ‘Single’, namely ‘newSize’ | |
In the expression: Single newSize value | |
-} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That
Money
example was FANTASTIC, it cleared all the confusion I had about this situation. The problem I had was that I tried to map this to the hierarchy of interface -> concrete implementation like the following Java code for instance:But that is the comparison of Apples and Oranges in this situation. In case of the Haskell code, I'm not specifying the return type as something that is
Sized
andMonoid
which makes it ok to return a concrete data type which is an instance of both Monoid and Sized! I'm reaching into the parameterized datatype (e.g JoinList) and replacing the contained item (as you mentioned) with something more specific that it needs to be and I can end up with a situation like the Money example that you drew above! I putMoney
in theJoinList
and get backSize
in theJoinList
which is not permitted in ANY language of course! That Java interface example distracted me from the root cause of the problem and I could never get out of that rabbit hole 😄Thank you SO MUCH, I highly appreciate it. It was a very interesting discussion and I learned a bunch of cool things actually 👍