I'm trying to deriving Eq from data type with a function as a field but doesn't work as expected.
I also try to write te instance but still doesn't work
data Conf = Conf {
rule :: ([Char] -> Char),
start :: Int,
numLines :: Double,
window :: Int,
move :: Int,
actualLine :: Int,
lastLine :: String
} deriving (Eq)
It's a project that consist in print graphicaly the wolfram pyramids, for instance, the rules are for example:
rule30 :: [Char] -> Char
rule30 "***" = ' '
rule30 "** " = ' '
rule30 "* *" = ' '
rule30 "* " = '*'
rule30 " **" = '*'
rule30 " * " = '*'
rule30 " *" = '*'
rule30 " " = ' '
rule30 _ = ' '
There are many rules to follow, it's for that reason that I want to save the "function pointer" directly in Conf data type.
So, why I need the deriving(Eq)? I need it because in the main I check if is Nothing (error handling check, for example if the user puts a bad rule...)
Error Msg:
src/Wolf.hs:24:13: error:
• No instance for (Eq ([Char] -> Char))
arising from the first field of ‘Conf’ (type ‘[Char] -> Char’)
(maybe you haven't applied a function to enough arguments?)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Eq Conf)
|
24 | } deriving (Eq)
| ^^
What am I missing?x
CodePudding user response:
What makes you think that this should be possible? If your type contains a function field, then comparing values of your type for equality is at least as difficult as comparing functions for equality. But to check that two functions are equal (in Haskell, the only sensible meaning is extensional equality), you'd need to check that they agree on all possible inputs. That's an utterly infeasible thing to do, even for simple Int
inputs but certainly if the arguments have type [Char]
.
So, why I need the
deriving(Eq)
? I need it because in themain
I check if isNothing
You totally don't need Eq
for that! Testing whether a Maybe
value is Nothing
by using ==
is ineffective, even on those types where it is possible. You should instead use either pattern matching
main = do
...
let myConfq = ... :: Maybe Conf
case myConfq of
Nothing -> error "Meh, couldn't have conf"
Just conf -> ...
...or use higher level combinators, perhaps based on Maybe
s Applicative
or Traversable
instances
import Data.Traversable
main = do
...
let myConfq = ... :: Maybe Conf
traverse ... myConfq
CodePudding user response:
I am thinking about ideas that would allow annotating fields of a datatype that would allow what you want: Via fields: finer granularity in deriving
The idea is to define a newtype where comparisons always succeed:
newtype Ignore a = Ignore a
instance Eq (Ignore a) where
_ == _ = True
instance Ord (Ignore a) where
compare _ _ = EQ
and then annotating only the function field; then when we derive instances of the datatype the instances that manipulate the field (==) @([Char] -> Char)
are actually performed via the newtype (==) @(via Ignore)
:
data Conf = Conf
{ rule :: [Char] -> Char
via Ignore ([Char] -> Char)
, start :: Int
, ..
}
deriving
stock (Eq, Ord)