2015-06-05 7 views
4

Я хочу иметь перегруженную функцию в Haskell.Устранение двусмысленностей для перегруженных функций

{-# LANGUAGE FlexibleInstances #-} 
class Foo a where 
    foo :: a 

instance Foo (String -> Int) where 
    foo = length 

instance Foo String where 
    foo = "world" 

Однако такая перегрузка очень плохо связана с неоднозначными типами. print $ foo "hello" приведет к ошибке, а print $ length "hello" работает нормально. Однако при условии, что мой список экземпляров исправлен, не должно быть технической причины, по которой Haskell не может понять, что единственным экземпляром foo :: String -> a является foo :: String -> Int. Могу ли я сделать Haskell для этой реализации?

+0

Является ли это действительно то, что вы хотите сделать? Но на вопрос: нет, я не думаю, что это может быть сделано этим генералом. – Carsten

+0

@Carsten, я мог бы жить с функциями 'fooLen' и' fooStr', но я думаю, что перегрузка намного удобнее. –

+2

Проблема заключается в том, что, возможно, вы экспортируете свою функцию ('printFoo' или что-то еще), а затем, если кто-то ее использует и добавляет экземпляр' instance Foo (String -> Double) 'он будет в затруднении – Carsten

ответ

4

В этом конкретном случае это легко сделать. Просто:

instance a ~ Int => Foo (String -> a) where foo = length 
+2

+1 конечно * doh * не сделал этого - хороший * обходной путь * - конечно, я все еще думаю, что класс, подобный 'Foo', здесь является лишь симптомом для другой проблемы;) – Carsten

+0

как боковое примечание, просто ограничивающее' Num 'и использование' genericLength' должно работать также: 'instance Num a => Foo (String -> a), где foo = genericLength', возможно, это легче понять, поскольку я считаю, что * ограничения равенства * широко известны (по крайней мере, начинающие) – Carsten

+0

Отлично. Хотя мне пришлось добавить * IncoherentInstances *, чтобы заставить второй экземпляр работать. Где я могу узнать, почему это работает? –

0

В вашем случае GHCI знает, что foo :: String -> ??

Мы собираемся изменить подпись String -> Int:

print (foo "hello" :: Int) 
+1

Я думаю, вопрос в том, почему это необходимо;) (и если вы можете заставить компилятор найти его сам по себе) – Carsten