开发者

Multiple declarations of 'MyModule.myTypeclassFunction'

开发者 https://www.devze.com 2023-02-06 22:36 出处:网络
in Main.hs class A aable where getName :: aable → String clas开发者_开发知识库s B bable where getName :: bable → String

in Main.hs

class A aable where
    getName :: aable → String

clas开发者_开发知识库s B bable where
    getName :: bable → String

returns this compilation error with Leksah/ghc

src\Main.hs:23:4:
    Multiple declarations of `Main.getName'
    Declared at: src\Main.hs:20:4
                 src\Main.hs:23:4

I need both to be able to return a name, with a different signification in both cases. Should I declare class A and B in two different modules ?


Kneejerk reaction: Use Show. Reading better, I see that what you want is propably different semantically (despite identical type signatures). Why not use a different name? descriptionA and descriptionB perhaps? Declaring them in different modules would solve the compilation error, but (1) you still have two different things with the same name and (2) whenever you import both modules (unqualified), you'll get the same error.


When you have different data types that behave differently, but somewhat the same (as in, have the same methods but differing implementations), then it's Haskell classes to the rescue!

data A = A { nameA :: String } deriving (Show, Eq)
data B = B { nameB :: String } deriving (Show, Eq)

class Named a where
    getName :: a -> String

instance Named A where
    getName = nameA

instance Named B where
    getName = nameB

ghci> getName $ A "foo"
"foo"
ghci> getName $ B "bar"
"bar"

(If you haven't seen record syntax yet, there's a good explanation at LYAH)

You can even be more general than that.

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
-- The above line should be at the top of your file

-- add this to the file too (anywhere)
instance (Show a) => Named a where
    getName = show

ghci> getName 3
"3"
ghci> show 3
"3"
ghci> getName $ A "foo"
"foo"
ghci> show $ A "foo"
"A {nameA = \"foo\"}"

The OverlappingInstances language pragma is only necessary in this example if you keep both the Instance (Show a) => Named a and the instance Named A, since I made A an instance of Show by deriving it. Use language pragmas with caution and wisdom.

I made A and B data for illustrative purposes, but the (Show a) instance illustrates how this could also be done just as easily for classes.

0

精彩评论

暂无评论...
验证码 换一张
取 消