繁体   English   中英

Ad hoc多态函数

[英]Ad hoc polymorphic functions

我有一些我想要打印的数据(有些是Maybe,有些则不是),我正在尝试创建一个通用的showField函数,如下所示:

showField :: (Show a) => a -> Text
showField x
  | isJust x = Text.pack $ show $ fromJust x
  | isNothing x = "None"
  | otherwise = Text.pack $ show x

这是一个严格的类型错误:

• Couldn't match expected type ‘Maybe a0’ with actual type ‘a’
  ‘a’ is a rigid type variable bound by
    the type signature for:
      showField :: forall a. Show a => a -> Text
    at /data/users/jkozyra/fbsource/fbcode/experimental/jkozyra/hs/holdout_cleanup/HoldoutReaper.hs:244:18
• In the first argument of ‘isNothing’, namely ‘x’
  In the expression: isNothing x
  In a stmt of a pattern guard for
                 an equation for ‘showField’:
    isNothing x

我一般都明白这个错误,但我不明白是否有办法实现我想要的。 我也尝试过模式匹配而不是守卫,但也不能完全解决问题。 我可以用这种格式构建一些可行的东西吗?

看起来你正在尝试构建一个adhoc多态函数 - 一个函数,其定义根据其类型而变化。

参数化多态函数对所有数据类型执行相同的操作:

both :: a -> (a,a)
both a = (a,a)

在Haskell中,adhoc多态性是使用类型类实现的:

class ShowField a where
  showField :: a -> Text

instance Show a => ShowField (Maybe a) where
  showField Nothing = "None"
  showField (Just a) = Text.pack $ show a

但是,没有办法为类型类定义“除了Maybe a之外的所有其他类型”的实例,因此您只需要为实际关注的类型定义实例:

class ShowField Int where
  showField = Text.pack . show
class ShowField Float where
  showField = Text.pack . show

您可以使用-XDefaultSignatures减少样板:

class ShowField' a where
  showField :: a -> Text
  default showField :: Show a => a -> Text
  showField = Text.pack . show

instance ShowField' Int where
instance ShowField' Float where

错误告诉我们:

‘a’ is a rigid type variable bound by
  the type signature for:
    showField :: forall a. Show a => a -> Text

基本上,这告诉我们根据您提供的类型签名,第一个参数的类型是forall a. Show a forall a. Show a (签名隐含' forall a. '位),这意味着第一个参数可以是Show的实例的任何类型。 它是一个严格的类型变量,因为它是由显式类型签名定义的。

它还告诉我们:

Couldn't match expected type ‘Maybe a0’ with actual type ‘a’

通过应用功能isJustisNothing -两个类型的Maybe a -> Bool -你也声称第一个参数的类型,第一个参数是Maybe a这显然是不一样的类型forall a. Show a => a -> Text forall a. Show a => a -> Text

您可以通过删除showField的类型签名将其转换为正确的程序,但不会有您想要的行为 - 推断的类型签名将是(Show a) => Maybe a -> Text显然只接受值Maybe a (其中a也是Show一个实例)。

在Haskell中,你不能拥有一个接受aMaybe a值的函数。 没有更多的背景,目前还不清楚你的实际目标是什么,但几乎可以肯定有一种更为惯用的方式来实现它。

¹除非你有一个类型类,它包含aMaybe a实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM