在Haskell中重载内置函数

Mat*_*att 3 haskell overloading operator-overloading

在Haskell中,如何重载内置函数,例如!!

我最初试图弄清楚如何重载内置函数!!以支持自己的数据类型.具体来说,!!是这样的类型:

[a] -> Int -> a
Run Code Online (Sandbox Code Playgroud)

我想保留它现有的功能,但也可以在类型签名看起来更像的地方调用它

MyType1 -> MyType2 -> MyType3
Run Code Online (Sandbox Code Playgroud)

我原本想要这样做,因为MyType1就像一个列表,我想使用!!运算符,因为我的操作非常类似于从列表中选择一个项目.

如果我重载了类似的东西,+我可以将我的函数实例添加到适用的类型类中,但我不认为这是一个选项.

我不相信我实际上甚至想要重载这个函数,但我仍然对它将如何完成感兴趣.实际上,关于是否超载运营商的评论!!甚至是一个好主意也将受到赞赏.

Lev*_*son 8

在Haskell中,几乎所有运算符都是库定义的.您最常使用的许多都是在默认情况下导入的Prelude模块的"标准库"中定义的.Gabriel的答案显示了如何避免导入其中一些定义,以便您可以创建自己的定义.

但这并不是超载,因为操作员仍然只是意味着一件事; 你为它定义的新含义.Haskell为重载提供的主要方法,即使用运算符,使其具有不同类型的不同实现,是类型类机制.

类型类标识一组支持某些常用功能的类型.当您使用带有类型的函数时,Haskell会找出适用于您的用法的类型类的正确实例,并确保使用正确的函数实现.大多数类型只有一些函数,有些只需要一两个,需要实现才能创建一个新实例.它们中的许多都提供了许多以核心方式实现的辅助功能,并且您可以将它们全部用于您创建类的实例的类型.

碰巧其他人已经制作了类似于列表的类型,因此已经有一个类型类被调用ListLike.我不确定你的类型与列表有多接近,所以它可能不适合ListLike,但你应该看看它,因为它可以为你提供很多功能,如果你可以让你的类型成为ListLike实例.


Ben*_*Ben 5

实际上,您无法在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
Run Code Online (Sandbox Code Playgroud)

(我使用类型族来暗示对于可以被索引的给定类型,索引的类型和元素的类型会自动跟随;这当然可以以不同的方式完成,但更详细地说到从过载问题旁边跟踪)

然后:

*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'
Run Code Online (Sandbox Code Playgroud)

应该强调的是,这!!对前奏中定义的现有函数以及使用它的任何其他模块都没有任何作用.这里!!定义的是一个新的,完全不相关的函数,恰好具有相同的名称并Prelude.!!在一个特定的实例中委托给它.没有现有的代码就可以!!MyType1没有修改的情况下开始使用(尽管您可以更改的其他模块当然可以导入新的!!以获得此功能).导入此模块的任何代码都必须对模块进行所有使用限定,!!否则使用相同的import Prelude hiding ((!!))行来隐藏原始模块.