您实际上不能在 Haskell 中重载现有的非类型类函数。
你可以做的是在一个新类型类中定义一个新函数,它足够通用,可以包含原始函数和你想要作为重载的新定义。您可以将其命名为与标准函数相同的名称,并避免导入标准函数。这意味着在您的模块中,您可以使用名称!!
来获取新定义和原始定义的功能(解析将由类型决定)。
例子:
{-# LANGUAGE TypeFamilies #-}
import Prelude hiding ((!!))
import qualified Prelude
class Indexable a where
type Index a
type Elem a
(!!) :: a -> Index a -> Elem a
instance Indexable [a] where
type Index [a] = Int
type Elem [a] = a
(!!) = (Prelude.!!)
newtype MyType1 = MyType1 String
deriving Show
newtype MyType2 = MyType2 Int
deriving Show
newtype MyType3 = MyType3 Char
deriving Show
instance Indexable MyType1 where
type Index MyType1 = MyType2
type Elem MyType1 = MyType3
MyType1 cs !! MyType2 i = MyType3 $ cs !! i
(我使用类型族来暗示对于可以被索引的给定类型,索引的类型和元素的类型会自动跟随;这当然可以以不同的方式完成,但更详细地了解这一点从超载问题中偏离)
然后:
*Main> :t (!!)
(!!) :: Indexable a => a -> Index a -> Elem a
*Main> :t ([] !!)
([] !!) :: Int -> a
*Main> :t (MyType1 "" !!)
(MyType1 "" !!) :: MyType2 -> MyType3
*Main> [0, 1, 2, 3, 4] !! 2
2
*Main> MyType1 "abcdefg" !! MyType2 3
MyType3 'd'
应该强调的是,这!!
对前奏中定义的现有功能绝对没有任何作用,也对使用它的任何其他模块没有任何作用。这里!!
定义的是一个新的且完全不相关的函数,它恰好具有相同的名称并Prelude.!!
在一个特定的实例中委托给它。没有现有代码将能够!!
在MyType1
不修改的情况下开始使用(尽管您可以更改的其他模块当然可以导入您的新模块!!
以获得此功能)。任何导入此模块的代码都必须对所有使用进行模块限定,!!
或者使用同一import Prelude hiding ((!!))
行来隐藏原始的。