SHIPWECK
SHIPWECK

Reputation: 99

How to restrict the type of an instance when the instance requires a "* -> *" type in Haskell?

I'm trying to design a type that holds some value and keeps track of all operations done upon it. It does this by storing them in string format (this is not for a project, just learning)

I tried to make it a Functor like this:

data WithLogs a = WithLogs {value :: a, logs :: [String]}
instance Functor WithLogs where
  fmap :: (a -> b) -> WithLogs a -> WithLogs b
  fmap f WithLogs {value, logs} =
    let newValue = f value
        newLogs = logs ++ [show value ++ " -> " ++ show newValue]
    in WithLogs {value = newValue, logs = newLogs}

This gives me an error at the line "newLogs = logs ++ [show value ++ " -> " ++ show newValue]", saying "No instance for (Show a) arising from a use of ‘show’". I then add the required contraints to make sure that both a and b can be shown

instance Functor WithLogs where
  fmap :: (Show a, Show b) => (a -> b) -> WithLogs a -> WithLogs b
  fmap f WithLogs {value, logs} =
    let newValue = f value
        newLogs = logs ++ [show value ++ " -> " ++ show newValue]
    in WithLogs {value = newValue, logs = newLogs}

This then gives me the error "No instance for (Show a) arising from the check that an instance signature is more general than the type of the method (instantiated for this instance)"

I think okay, so I need to constrain the instance, leading to this code:

instance (Show a) => Functor WithLogs where
  fmap :: (Show a, Show b) => (a -> b) -> WithLogs a -> WithLogs b
  fmap f WithLogs {value, logs} =
    let newValue = f value
        newLogs = logs ++ [show value ++ " -> " ++ show newValue]
    in WithLogs {value = newValue, logs = newLogs}

This hits me with two* errors, the first being that the (Show a) in the instance declaration cannot be deduced, and its right, how could it? I can't pass a to Functor (WithLogs a) because Functor expects a (Type -> Type), but I somehow need to constrain fmap so that I can use show on the contained value. I need a way to tell WithLogs that it can only take showable types to be an instance of Functor. Is there a way to do this?

*: in case it's any help, the other error is "Could not deduce (Show b) arising from the check that an instance signature is more general than the type of the method (instantiated for this instance)"

Upvotes: 1

Views: 44

Answers (0)

Related Questions