Haskell中内置的重载函数 [英] Overload built in function in Haskell

查看:182
本文介绍了Haskell中内置的重载函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Haskell中,如何重载一个内置的函数,如 !!



我原本是试图找出如何重载内置函数 !! 来支持自己的数据类型。具体而言, !! 的类型为:

  [a]  - > Int  - >一个

并且我想保留它的现有功能,但是也能够在其类型签名看起来更像

  MyType1  - > MyType2  - > MyType3 

我原本想这样做,因为MyType1就像一个列表,我想用 !! 操作符,因为我的操作与从列表中选择一个项目非常相似。

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

我不确信我实际上甚至想重载这个函数,但我仍然对如何完成它感兴趣。实际上,如果重载一个运算符如 !! 甚至是一个好主意,那么我们也会很感激。

解决方案

您实际上无法在Haskell中重载现有的非类型类型函数。 $ b

你可以做的是在新的类型类中定义一个新的函数,这个函数的通用性足以涵盖原始函数和你想作为重载的新定义。您可以将其与标准功能同名,并避免导入标准功能。这意味着在你的模块中,你可以使用名称 !! 来获得新定义的功能和原始定义(分辨率将由类型决定)。



示例:

  { - #LANGUAGE TypeFamilies# - } 

导入前导隐藏((!!))
导入合格前奏

类别索引a其中
类型索引a
类型元素a
(!!):: a - >索引a - > Elem a


实例可索引的[a]其中
类型索引[a] = Int
类型Elem [a] = a
(!!) =(Prelude。!!)


newtype MyType1 = MyType1字符串
派生显示
newtype MyType2 = MyType2 Int
派生显示
newtype MyType3 = MyType3 Char
导出显示

实例可索引MyType1其中
类型索引MyType1 = MyType2
类型Elem MyType1 = MyType3
MyType1 cs !! MyType2 i = MyType3 $ cs!我已经使用类型族来暗示对于可以被索引的给定类型,类型的索引和元素的类型自动遵循;这当然可以做不同的处理,但更详细地讨论这个问题是从重载问题中获得侧面追踪)

然后:

  * Main> :t(!!)
(!!)::可转位a => a - >索引a - > Elem a
* Main> :t([] !!)
([] !!):: Int - > a
* Main> :t(MyType1!!)
(MyType1!!):: MyType2 - > MyType3
* Main> [0,1,2,3,4]! 2
2
* Main> MyType1abcdefg! MyType2 3
MyType3'd'

需要强调的是,前奏中定义的现有 !! 函数,以及任何其他使用它的模块。这里定义的 !! 是一个新的完全不相关的函数,它恰好具有相同的名称并委托给 Prelude。!! code>在一个特定的实例中。没有现有的代码就可以开始在 MyType1 上使用 !! 而无需修改(尽管其他模块可以更改课程导入新的 !! 以获得此功能)。任何导入此模块的代码都必须模块化 !! 的所有用法,否则使用相同的导入前导隐藏((!!) )一行来隐藏原始文件。


In Haskell, how can one overload a built in function such as !!?

I originally was trying to figure out how to overload the built in function !! to support by own data types. Specifically, !! is of the type:

[a] -> Int -> a

and I want to preserve it's existing functionality, but also be able to call it where its type signature looks more like

MyType1 -> MyType2 -> MyType3

I originally wanted to do this because MyType1 is like a list, and I wanted to use the !! operator because my operation is very similar to selecting an item from a list.

If I was overloading something like + I could just add an instance of my function to the applicable type class, but I don't think that is an option here.

I'm not convinced I actually even want to overload this function anymore, but I am still interested in how it would be done. Actually, comments on if overloading an operator such as !! is even a good idea would be appreciated as well.

解决方案

You can't actually overload an existing non-typeclass function in Haskell.

What you can do is define a new function in a new type class, which is general enough to encompass both the original function and the new definition you want as an overload. You can give it the same name as the standard function, and avoid importing the standard one. That means in your module you can use the name !! to get both the functionality of your new definition, and the original definition (the resolution will be directed by the types).

Example:

{-# 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

(I've used type families to imply that for a given type that can be indexed, the type of the indices and the type of the elements automatically follows; this could of course be done differently, but going into that in more detail is getting side-tracked from the overload question)

Then:

*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'

It should be emphasised that this has done absolutely nothing to the existing !! function defined in the prelude, nor to any other module that uses it. The !! defined here is a new and entirely unrelated function, which just happens to have the same name and to delegate to Prelude.!! in one particular instance. No existing code will be able to start using !! on MyType1 without modification (though other modules you can change can of course import your new !! to get this functionality). Any code that imports this module will either have to module-qualify all uses of !! or else use the same import Prelude hiding ((!!)) line to hide the original one.

这篇关于Haskell中内置的重载函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆