作为示例,让我们采用以下算法来计算两个序列的最长公共子序列,从Rosetta Code复制:
longest xs ys = if length xs > length ys then xs else ys
lcs [] _ = []
lcs _ [] = []
lcs (x:xs) (y:ys)
| x == y = x : lcs xs ys
| otherwise = longest (lcs (x:xs) ys) (lcs xs (y:ys))
lcs
隐含地假设两个参数都是 type Eq a => [a]
;实际上,如果我尝试明确给出签名lcs :: [a] -> [a] -> [a]
,则会在 where 行发生错误x == y
,而签名lcs :: Eq a => [a] -> [a] -> [a]
有效。
现在假设我有两个列表l1
and l2
,两者都是 type [(a,b)]
,并且我想要它们之间的 LCS,但是在==
定义中使用运算符的方式lcs
仅在snd
每个元素的 s 之间(显然b
需要属于Eq
typeclass) .
我不仅可以提供lcs
这两个列表,还可以提供相等运算符,在上面的具体示例中是(==) `on` snd
. 的签名lcs
将是(a -> a -> Bool) -> [a] -> [a] -> [a]
。
然而,这将迫使用户提供相等运算符,即使是在人们想要使用 plain 的琐碎情况下,并且将参数(==)
包装在 a 中也无济于事。(a -> a)
Maybe
换句话说,我觉得在一般情况下,参数 via 的约束Eq a =>
是可以的,但在其他情况下,可能想要传递一个自定义相等运算符来删除该约束,这使我成为函数重载的事情。
我该怎么办?