我有一个类型为Read a => String -> a
的函数,是否有可能有另一个同名的函数在a
时做不同的事情例如String
?是否有任何 GHC 扩展允许这样做?
类似于:
f :: Read a => String -> a
f = read
f :: String -> String
f = id
最佳答案
在 Haskell 中,这种函数重载(即席多态性)是通过使用类型类来完成的,而不是通过在多个类型下绑定(bind)相同的名称来完成。
{-# 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
也许不直观的是,这不仅针对具有 Read
实例的类型声明 F
实例。因为 GHC 仅使用实例声明的头部(=>
右侧的部分)来解析实例,这实际上将所有类型 a
声明为 的实例>F
,但对任何不是 Read
实例的对象调用 f
会导致类型错误。
如果启用 UndecidableInstances
扩展,它将编译,但这只会导致其他问题。这是一个你不想冒险进入的兔子洞。
相反,您应该为您想要 f
操作的每个单独类型声明一个 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
实例的类型,您仍然需要为 f
编写显式实现。
关于haskell - Haskell 中的函数类型特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9881726/