Mar*_*ota 2 haskell types generic-programming ghc
我有一个具有类型的函数Read a => String -> a,是有可能有难同当,做不同的事情同名的另一个功能a是例如String?是否有任何GHC扩展允许这样做?
就像是:
f :: Read a => String -> a
f = read
f :: String -> String
f = id
Run Code Online (Sandbox Code Playgroud)
bit*_*ket 12
在Haskell中,这种函数重载(ad-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.
Run Code Online (Sandbox Code Playgroud)
现在,f可以对F已声明实例的任何类型进行操作.
不幸的是,你不能逃避以下事情:
instance Read a => F a where f = read
Run Code Online (Sandbox Code Playgroud)
也许是不直观的,这并不是F仅为具有实例的类型声明实例Read.因为GHC仅使用实例声明(该部分的右侧头部解决实例=>),这实际上宣告所有类型a为的情况下F,反而使得它一个类型错误调用f任何东西这不也是一个实例Read.
如果启用UndecidableInstances扩展,它将编译,但这只会导致其他问题.这是一个你真不想冒险的兔子洞.
相反,您应该F为f要操作的每个单独类型声明一个实例.对于像这样的简单类来说,这不是很麻烦,但是如果你使用最新版本的GHC,你可以使用以下内容使它更容易:
{-# LANGUAGE DefaultSignatures #-}
class F a where f :: String -> a
default f :: Read a => String -> a
f = read
Run Code Online (Sandbox Code Playgroud)
现在,对于任何类型的实例Read,您可以声明其实例而F无需提供f显式的实现:
instance F Int
instance F Char
instance F Float
-- etc.
Run Code Online (Sandbox Code Playgroud)
对于没有实例的任何类型Read,您仍然必须为其编写显式实现f.