多态参数类型的模式匹配 - 替代方案

muc*_*aho 2 haskell pattern-matching polymorphic-functions

假设我需要不同的输出,具体取决于函数的多态参数的类型.我的初始尝试失败了一些神秘的错误消息:

choice :: a -> Int
choice (_ :: Int) = 0
choice (_ :: String) = 1
choice _ = 2
Run Code Online (Sandbox Code Playgroud)

但是,我们可以通过将所需类型包装在不同的数据构造函数中并在模式匹配中使用它们来轻松解决这个问题:

data Choice a = IntChoice Int | StringChoice String | OtherChoice a

choice :: Choice a -> Int
choice (IntChoice _) = 0
choice (StringChoice _) = 1
choice (OtherChoice _) = 2
Run Code Online (Sandbox Code Playgroud)

问题:你知道如何绕过这个吗?Haskell2010,GHC或任何扩展中是否有一个功能允许我使用第一个变体(或类似的东西)?

Dav*_*vid 5

这混淆了两种不同的多态性.你想要的是ad-hoc多态,这是通过类型类完成的.类型函数的多态性类型a -> Int参数多态性.使用参数多态,一个函数定义choice必须适用于任何可能的类型a.在这种情况下,这意味着它实际上不能使用类型的值,a因为它对它没有任何了解,所以choice必须是一个常量函数,如choice _ = 3.这实际上为您提供了关于函数可以做什么的非常有力的保证,只需查看它的类型(此属性称为参数化).

使用类型类,您可以将您的示例实现为:

class ChoiceClass a where
  choice :: a -> Int

instance ChoiceClass Int where
  choice _ = 0

instance ChoiceClass String where
  choice _ = 1

instance ChoiceClass a where
  choice _ = 2
Run Code Online (Sandbox Code Playgroud)

现在,我应该指出,这种类型的方法通常是错误的,特别是当刚开始的人想要使用它时.你肯定不想这样做,以避免像Choice你的问题类型中的简单类型.它可能会增加许多复杂性,实例解析可能会让人感到困惑.请注意,为了使类型类解决方案起作用,需要打开两个扩展:FlexibleInstances并且TypeSynonymInstances因为它String是一个同义词[Char].OverlappingInstances还需要因为类型类工作在"开放世界"的假设(意味着任何人都可以在以后出现并为新类型添加实例,这必须考虑在内).这不一定是坏事,但在这里它表明了使用类型类解决方案而不是更简单的数据类型解决方案所导致的复杂性.OverlappingInstances特别是可以让事情更难以思考和合作.