Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何为单个类型专门化(重载)函数行为?_Haskell_Polymorphism_Typeclass - Fatal编程技术网

Haskell 如何为单个类型专门化(重载)函数行为?

Haskell 如何为单个类型专门化(重载)函数行为?,haskell,polymorphism,typeclass,Haskell,Polymorphism,Typeclass,我正在研究真实世界的Haskell,作为练习的一部分,我意识到我想要一个类似于show::Showa=>a->String的函数,但它不改变字符串,而不是转义引号。在伪代码中,我想要的是: 显示“::字符串->字符串 显示“=id” show'::Showa=>a->String show'=show 显然,这是行不通的,ghc抱怨有多个类型签名和多个声明。看来我应该改用TypeClass。当我试图写这篇文章时,编译器一直建议我添加更多的语言扩展: {-语言灵活实例,不可判定实例,不连贯-} 课

我正在研究真实世界的Haskell,作为练习的一部分,我意识到我想要一个类似于show::Showa=>a->String的函数,但它不改变字符串,而不是转义引号。在伪代码中,我想要的是:

显示“::字符串->字符串 显示“=id” show'::Showa=>a->String show'=show 显然,这是行不通的,ghc抱怨有多个类型签名和多个声明。看来我应该改用TypeClass。当我试图写这篇文章时,编译器一直建议我添加更多的语言扩展:

{-语言灵活实例,不可判定实例,不连贯-} 课堂表演a在哪里 显示“::a->字符串 “实例显示”字符串,其中 显示“=id” 实例Show a=>Show'a where show'=show -x==abc x=显示“abc” y=show'9 起初,这似乎是可行的:x==abc,y==9。但当我尝试在另一个多态函数中使用它时,编译器似乎总是将其解析为一般实现:

使用::Show a=>a->String 使用x=show'x -z==\abc\ z=使用abc
所以我在这里做错了一些事情,我想知道是否有一种方法可以在没有大量语言扩展的情况下做到这一点,其中一些似乎不是我应该不计后果地使用的东西。如何使用现有的show函数定义此show?

use只知道它的参数类型是show的一个实例。因为它只知道这些,所以必须使用只需要Show的通用实例

你真正想要的,不是那样,而是告诉它,它可以是“Show”的任何实例,而不是Show的任何实例。一个小小的改变可以解决这个问题:

use :: (Show' a) => a -> String
旁白:如果我没记错的话,不连贯有时会引起一些问题。我认为在这里是可以的,但是如果您在启用该扩展名的同一文件中创建更多实例,则需要记住这一点

如果类型类的实例之间的依赖关系存在循环,则不可判定实例可能会导致类型检查器以及编译器作为一个整体进入无限循环。这里的情况并非如此,但值得一提


回答另一个问题:如果不使用这些语言扩展,就不可能完成这个特定的任务。对于这个问题,你是否遗漏了更多的细节,等等?也许有更好的方法来解决更大的问题。

来自OP的评论:

[一] 令人惊讶的是,如此简单的函数描述是如此难以实现

这根本不是一个简单的函数,因为它打破了基于类型类的多态性的通常保证。当我们看到一个实例时

instance Show' a => Show' [a] where ...
我们通常假定此实例适用于所有列表类型,没有例外。a型上的通用量化实际上意味着所有a型

正如David在回答中指出的那样,重叠/不连贯的实例打破了这一假设,允许出现像您这样的特殊情况。这是一个可能的解决方案,但请注意,通过打破上述假设,重叠/不连贯的实例会使实例解析变得相当脆弱,有时会导致意外地采用错误的实例

作为一种选择,你可以考虑使用可打字的类型,我相信它没有什么争议:

import Data.Typeable

show' :: (Show a, Typeable a) => a -> String
show' x = case cast x of
   Just s  -> s           -- cast succeeded, it is a string
   Nothing -> show x      -- case failed, it is not a string
请注意,Typeable的存在表明,在type中,该函数是使用ad-hoc多态性定义的,这使我们能够检查a是否为某某类型,这在参数多态性下通常是不可能的


请注意,这不需要不连贯或重叠的实例。

谢谢,当我修复它并添加单焦点绑定时,这似乎是可行的。上下文实际上就是我正在阅读和学习的内容,我很惊讶这样一个简单的函数很难实现。@HarrisEnniss困难的出现是因为一个案例是带有Show约束的完全多态的,而另一个案例是一个特定的、具体的类型字符串。值得一提的是,根据我的经验,这种情况在实践中不会发生太多,而且,在少数不可避免的情况下,我相信这种实现模式通常是一种可接受的解决方案。我很惊讶没有人提到这一点,但你不应该需要不连贯。摆脱它并使用实例{-OVERLAPPABLE-}Show a=>Show'a where Show'=Show编写catch all实例。那么使用的定义应该是错误的,因为正如公认的答案所解释的,它是错误的。基本上,对于GHC来说,不连贯性是指即使某些类型有多个实例,所有实例实际上都是一致的,因此您可以根据需要在它们之间进行选择,这在这里是不正确的。OVERLAPPABLE说的是事实:一个类型只有一个有效的实例。我刚刚意识到,我实际上重新编写了一个2016年的答案,与Daniel Wagner发现的副本相同。