2011-01-25 2 views
1

в Main.hsНесколько деклараций «MyModule.myTypeclassFunction»

class A aable where 
    getName :: aable → String 

class B bable where 
    getName :: bable → String 

возвращает этот сборник ошибок с Leksah/GHC

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

мне нужны оба, чтобы иметь возможность вернуть имя, с различное значение в обоих случаях. Должен ли я объявлять классы A и B в двух разных модулях?

ответ

3

Реакция на колене: Используйте Show. Читаю лучше, я вижу, что вы хотите разделить семантически (несмотря на идентичные подписи). Почему бы не использовать другое имя? descriptionA и descriptionB возможно? Объявление их в разных модулях решило бы ошибку компиляции, но (1) у вас все еще есть две разные вещи с тем же именем и (2), когда вы импортируете оба модуля (неквалифицированные), вы получите ту же ошибку.

+0

@ok, поэтому вы имеете в виду, что я должен использовать разные имена или использовать Show, когда речь идет о String. Как насчет использования newType, чтобы квалифицировать строки так, как они несовместимы, если они означают совершенно разные вещи? Обычное использование newType? –

+1

@stephane Представьте себе тип 'T' (любой тип, это может быть новый тип), и теперь представьте, что у вас есть экземпляр AT где ...' и экземпляр BT, где ... 'Как вы знаете, какая функция для запускать, когда кто-то вызывает 'getName'? –

+1

@Stephane: Как всегда, это зависит. Если строки представляют концептуально разные вещи, я бы выбрал этот способ (если только сделать подпись типа более выразительной: 'xyz :: thing -> ThingID' вместо' xyz :: thing -> String') – delnan

3

Если у вас разные типы данных, которые ведут себя по-разному, но несколько одинаковы (например, имеют те же методы, но отличаются друг от друга), тогда это классы Haskell для спасения!

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" 

(Если вы еще не видели синтаксис записи еще, есть good explanation at LYAH)

Вы можете даже быть более общим, чем это.

{-# 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\"}" 

Язык Прагма OverlappingInstances необходим только в этом примере, если вы держите как Instance (Show a) => Named a и instance Named A, так как я сделал A экземпляр Show, выводя его. Используйте языковые прагмы с осторожностью и мудростью.

Я сделал A и B данные для иллюстративных целей, но пример (Show a) иллюстрирует, как это можно сделать так же легко для классов.

+0

Можете ли вы выполнить следующую работу: 'x = A" Foo "; y = B "Bar"; z = x {name = "Bar"}; w = y {name = "Foo"} '? – Alexey

Смежные вопросы