2013-10-08 6 views
7

Я знаю, что String определяется как [Char], но я хотел бы сделать разницу между ними из экземпляра класса. Возможно ли это с помощью какого-то умного трюка, кроме использования newtype для создания отдельного типа? Я хотел бы сделать что-то вроде:Различают строки и [Char]

class Something a where  
    doSomething :: a -> a 

instance Something String where 
    doSomething = id 

instance (Something a) => Something [a] where 
    doSomething = doSoemthingElse 

И получить разные результаты, когда я называю его doSomething ("a" :: [Char]) и doSomething ("a" :: String).

Я знаю о FlexibleInstances и OverlappingInstances, но они, очевидно, не вырезают корпус.

+1

Вы не можете сделать это, на листе компилятора, '[Char]' и 'String' - это то же самое. Типичные имена синонимов исчезают. Если вы должны явно аннотировать в любом случае, почему бы не использовать новый тип. – jozefg

+6

Если вам интересно иметь другое поведение для 'Something => [a]' и для 'String', используя haskell98, вы можете сделать то, что делает класс Show, и использовать трюк [extra method] (http: // brandon.si/code/how-the-haskell-prelude-avoids-overlapping-types-in-show/) – jberryman

+0

Проблема в том, что, насколько я понимаю, он всегда будет вызывать экземпляр 'String', потому что' type String = [ Char] ', поэтому он не решает моего дела. – qwe2

ответ

11

Это невозможно. String и [Char] - это тот же тип. Невозможно различать два типа. С помощью OverlappingInstances вы можете создавать отдельные экземпляры для String и [a], но [Char] всегда будет использовать экземпляр для String.

+0

Это то, чего я ожидал. Как вы считаете, моя лучшая ставка будет заключаться в решении проблемы? Потому что все, о чем я могу думать, представляет собой «новый тип», делающий их дизъюнктами, но это не так красиво, как хотелось бы. – qwe2

+5

Используйте новый тип. Это подход, который std libs дает – jozefg

+2

. Еще лучше: если вы имеете дело с текстовыми данными, используйте тип данных «Текст». В этом смысле вы могли бы рассматривать его как предварительно обработанную оболочку newtype вокруг String, которая имеет прекрасный API и лучшую производительность. –

4

Почему вы не определить функции для каждого случая:

doSomethingString :: String -> String 
doSomethingString = id 

doSomethingChars :: (Char -> Char) -> String -> String 
doSomethingChars f = ... 
+0

Или (если имеется больше экземпляров, чем просто '[a]'), одна функция для строк 'doSomethingString' и сохраняет класс типа – jozefg

0

Как было сказано ранее, String и [Char] фактически то же самое.

Что вы можете сделать, хотя и определяет newtype. Он обертывает тип (без каких-либо затрат, поскольку он полностью удаляется при компиляции) и заставляет его вести себя как другой тип.

newtype Blah = Blah String 

instance Monoid Blah where 
    mempty = Blah "" 
    mappend (Blah a) (Blah b) = Blah $ a ++ "|" ++ b 
Смежные вопросы