如何让Haskell中的函数依赖于其参数的类型?

Tur*_*ion 4 haskell types pattern-matching pattern-guards

我尝试写一个变体show来处理字符串与其他实例不同Show,不包括"并直接返回字符串.但我不知道怎么做.模式匹配?警卫?我找不到任何关于在任何文件中.

这是我试过的,不编译的:

show_ :: Show a => a -> String
show_ (x :: String) = x
show_ x             = show x
Run Code Online (Sandbox Code Playgroud)

GS *_*ica 5

如果可能的话,你应该将你的类型值包装Stringnewtype@wowofbob中.

然而,有时这是不可行的,在这种情况下,有两种通用方法可以使某些东西String具体识别.

第一种方法,即自然的Haskell方法,是使用类型类就像Show为不同类型获得不同的行为.所以你可以写

class Show_ a where
    show_ :: a -> String
Run Code Online (Sandbox Code Playgroud)

然后

instance Show_ String where
    show_ x = x

instance Show_ Int where
    show_ x = show x
Run Code Online (Sandbox Code Playgroud)

等您要使用的任何其他类型.这样做的缺点是您需要为Show_所需的所有类型显式写出实例.

@AndrewC显示了如何将每个实例切割成一行,但您仍然必须明确地列出它们.理论上你可以解决这个问题,详见这个问题,但这并不令人愉快.

第二个选项是使用Typeable类获取真正的运行时类型信息,这在这种特定情况下非常简短:

import Data.Typeable

[...]

show_ :: (Typeable a, Show a) => a -> String
show_ x =
    case cast x :: Maybe String of
        Just s -> s
        Nothing -> show x
Run Code Online (Sandbox Code Playgroud)

这不是一种自然的Haskell-ish方法,因为它意味着调用者无法详细说明该函数将从该类型中做什么.

类型类通常给出约束多态,因为特定函数的行为的唯一变化必须来自相关类型类实例中的变体.本Show_类给出了一些指示其主题,从它的名字,它可能会被记录在案.

然而,这Typeable是一个非常普遍的课程 您将所有内容委托给您正在调用的特定功能; 具有Typeable约束的函数可能对许多不同的具体类型具有完全不同的实现.

最后,对Typeable更接近原始代码的解决方案的进一步阐述是使用几个扩展:

{-# LANGUAGE ViewPatterns, ScopedTypeVariables #-}
import Data.Typeable

[...]

show_ :: (Typeable a, Show a) => a -> String
show_ (cast -> Just (s :: String)) = s
show_ x = show x
Run Code Online (Sandbox Code Playgroud)

使用ViewPatterns允许我们在cast内部编写一个模式,这可能更适合更复杂的例子.事实上,我们可以省略:: String类型约束,因为这种情况的主体强制s成为结果类型show_,即String无论如何.但这有点模糊,所以我认为最好是明确的.