临时多态性函数



我有一些我想打印的数据(有些可能是,有些不是),我试图创建一个通用的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

但是,没有办法定义"除了可能的所有其他类型"的实例,因此您只需要定义您实际关心的类型的实例:

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的实例。它是 arigid 类型变量,因为它是由显式类型签名定义的。

它也告诉我们:

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

通过应用函数 isJustisNothing(类型Maybe a -> Bool) - 在第一个参数中,您也要求第一个参数的类型为 Maybe a,显然与 forall a. Show a => a -> Text不同。

您只需删除showField的类型签名即可将其变成正确的程序,但这不会具有您想要的行为 - 推断的类型签名将是(Show a) => Maybe a -> Text,显然只接受Maybe a的值(其中a也是如此Show的实例)。

在Haskell中,您无法具有接受aMaybe a见值的函数。没有更多的背景,目前尚不清楚您的实际目标是什么,但是几乎可以肯定有一种更惯用的方法来实现它。

¹除非您有一个类型类,该类别具有aMaybe a的实例。

最新更新