2012-03-27 74 views
2

我有一个函数,它有类型Read a => String -> a,是否有可能有另一个功能具有相同的名称,做不同的事情a是例如String?是否有任何GHC扩展允许这样做?Haskell中的函数类型专业化

喜欢的东西:

f :: Read a => String -> a 
f = read 

f :: String -> String 
f = id 
+0

如果您只关心性能,那么编译器应该优化这些类型的东西。 – leftaroundabout 2012-03-27 00:31:28

+0

我不关心性能,我想有一个版本,不需要周围的字符串引号read'的',但工作正常'read'的一切。 – 2012-03-27 00:37:46

+0

问题http://stackoverflow.com/questions/9870962/haskell-making-a-superclass-of-num/地址完全相同的问题;有些答案可能有用。 – 2012-03-27 01:23:32

回答

12

在Haskell,这种函数重载(广告-hoc多态性)是通过使用类型类实现的,而不是通过在多个类型下绑定相同的名称。

{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-} 

class F a where f :: String -> a 

instance F String where f = id 
instance F Int where f = read 
instance F Char where f = read 
instance F Float where f = read 
-- etc. 

现在,f可以对其中的F实例已被宣布任何类型的工作。

不幸的是,你不能逃脱如下:

instance Read a => F a where f = read 

也许unintuitively,这并不仅适用于有Read一个实例类型声明的F一个实例。因为GHC解决只用实例声明(部分为=>的右侧)的头部的情况下,这实际上宣告各类a是的F情况下,反而使得它一个类型错误调用f任何东西这不也是Read的实例。

如果您启用UndecidableInstances扩展名,它会编译,但这只会导致其他问题。这是一个你不想冒险的兔子洞。

相反,您应该针对您打算运行的每个单独类型声明F的实例。这不是一个简单的类像这样的一个非常繁重的,但如果你使用最新GHC的版本,可以使用以下使它稍微容易:现在

{-# LANGUAGE DefaultSignatures #-} 

class F a where f :: String -> a 
       default f :: Read a => String -> a 
       f = read 

,对于任何类型的是的Read例如,你可以声明其F实例,而无需提供f实施明确:

instance F Int 
instance F Char 
instance F Float 
-- etc. 

对于任何类型的Read情况下,你仍然必须写明确的实施。

4

我得到它的工作,但我不得不打开了一堆可疑的语言选项:

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE UndecidableInstances #-} 
{-# LANGUAGE TypeSynonymInstances #-} 
{-# LANGUAGE OverlappingInstances #-} 

class SpecialRead a where 
    specialRead :: String -> a 

instance Read a => SpecialRead a where 
    specialRead = read 

instance SpecialRead String where 
    specialRead = id 

main = do 
    print (specialRead "10" :: Int) 
    print (specialRead "10" :: String) 
+5

'FlexibleInstances'和'TypeSynonymInstances'是无争议的;他们只是放松了Haskell标准强加的一些限制,但没有什么可担心的。然而,'UndecidableInstances'和'OverlappingInstances'是危险区域,除非你知道你在做什么,否则通常应该避免。 – bitbucket 2012-03-27 01:12:15