Haskell:可怕的类型签名

4

我很难理解这个类型签名:

Prelude Text.Regex.Posix> :t (=~)
(=~)
  :: (Text.Regex.Base.RegexLike.RegexMaker
        Regex CompOption ExecOption source,
      Text.Regex.Base.RegexLike.RegexContext Regex source1 target) =>
     source1 -> source -> target

我认为它们列出了类型类,sourcesource1target应该是实例,但语义看起来完全晦涩(也就是说,即使我理解了它所说的内容,我也无法复制它)。


=~ 在其返回类型和参数类型上都是多态的。这意味着如果您期望一个布尔值,它将返回一个布尔值。如果您期望一个字符串列表,它将返回捕获的列表。等等。(多态参数类型是为了匹配字符串和字节串,例如。) - jrockway
1
那并不能帮助我理解上下文定义部分。source 应该是哪种类型的类的实例? - artemave
2个回答

4

这里没有什么奇怪的事情:只是一些带有许多参数的类型类。(长长的 Text.Regex.Base... 模块名称也没有帮助。)

  • 必须为以下类型创建RegexMaker实例: RegexCompOptionExecOption,以及任何类型的 source
  • 必须为以下类型创建RegexContext实例: Regex、任何类型的 source1,以及任何类型的 target
  • (=~) 函数本身接受一个 source1 和一个 source,并返回一个 target

Haskell 自己的 (+) 运算符与 (=~) 形状相似,但它的类型应该更容易阅读:

(+) :: Num a => a -> a -> a

我不太理解。也许我还是太菜了。我正在阅读这章节的中间部分:http://book.realworldhaskell.org/read/efficient-file-processing-regular-expressions-and-file-name-matching.html - artemave
但是如果有 Num SomeOtherType a,我就不会这样做。 - artemave
好的,现在读起来更清晰了。然而,如果 Num a 的意思是“类型 a 必须是 Num 的实例”,那么 Class1 Class2 a 的含义仍然不清楚(看起来我无法理解一些基本概念或其他什么)。 - artemave
3
我第一次看到有多个参数的类型类时也感到困惑。我会这样理解:Num a = “必须存在一个带有参数 aNum 实例”……Class1 Class2 a = “必须存在一个带有参数 Class2aClass1 实例”。 - Tim Robinson
多参数类型类需要启用一个名为MultiParamTypeClasses的Haskell扩展。只要该类和您使用的所有实例在其他地方定义,您实际上可以在不启用扩展的模块中使用多参数类型类。 - Jeremy List
显示剩余4条评论

3
我在另一个答案中详细描述了Text.Regex类型类。所有的Text.Regex.*模块都大量使用类型类,这种类型类用于扩展和"重载"行为,但从类型上来看,使用方式不是很明显。现在,你可能已经从基本的=~匹配器开始了。
(=~) ::
  ( RegexMaker Regex CompOption ExecOption source
  , RegexContext Regex source1 target )
  => source1 -> source -> target
(=~~) ::
  ( RegexMaker Regex CompOption ExecOption source
  , RegexContext Regex source1 target, Monad m )
  => source1 -> source -> m target

要使用=~,必须存在LHS的RegexMaker ...实例和RHS以及结果的RegexContext ...

class RegexOptions regex compOpt execOpt | ...
      | regex -> compOpt execOpt
      , compOpt -> regex execOpt
      , execOpt -> regex compOpt
class RegexOptions regex compOpt execOpt
      => RegexMaker regex compOpt execOpt source
         | regex -> compOpt execOpt
         , compOpt -> regex execOpt
         , execOpt -> regex compOpt
  where
    makeRegex :: source -> regex
    makeRegexOpts :: compOpt -> execOpt -> source -> regex

所有这些类的有效实例(例如,regex=RegexcompOpt=CompOptionexecOpt=ExecOptionsource=String)意味着可以从某种形式的source编译带有compOpt,execOpt选项的regex。 (此外,对于给定的一些regex类型,恰好有一个与之相应的compOpt,execOpt设置。虽然可以使用许多不同的source类型。)
class Extract source
class Extract source
      => RegexLike regex source
class RegexLike regex source
      => RegexContext regex source target
  where
    match :: regex -> source -> target
    matchM :: Monad m => regex -> source -> m target

所有这些类的有效实例(例如,regex=Regexsource=Stringtarget=Bool)意味着可以匹配一个source和一个regex以产生一个target。(在给定这些特定regexsource的情况下,其他有效的target包括IntMatchResult StringMatchArray等。)
将它们结合起来,很明显=~=~~只是方便的函数。
source1 =~ source
  = match (makeRegex source) source1
source1 =~~ source
  = matchM (makeRegex source) source1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接