我正在尝试编写一个接受比较器列表的函数,并返回一个比较器,它将使用第一个比较器比较一对值,如果第一个比较器返回则返回第二个比较器EQ.
我想出的是以下功能:
import Data.Monoid
chainCompare :: [a -> a -> Ordering] -> a -> a -> Ordering
chainCompare = mconcat . map ($)
Run Code Online (Sandbox Code Playgroud)
编辑:chainCompare也可以写成(感谢Vitus指出):
chaincompare = mconcat
Run Code Online (Sandbox Code Playgroud)
使用此功能的示例如下:
import Data.List
import Data.Ord
sortBy (chainCompare [comparing length, comparing sum]) [[1..100], [1..20], [100..200]]
Run Code Online (Sandbox Code Playgroud)
但是,这个函数需要明确地使用比较,所以我试着像这样修改函数:
chainCompare :: Ord b => [a -> b] -> a -> a -> Ordering
chainCompare = mconcat . map (comparing $)
Run Code Online (Sandbox Code Playgroud)
但是,chainCompare在这种情况下会导致编译错误(此外,即使此示例编译,它也不适用于空字符串):
sortBy (chainCompare [length, head]) [['a'..'z'], ['A'..'Z'], "Lorem ipsum dolor sit amet"]
Run Code Online (Sandbox Code Playgroud)
是否可以在任何类型chainCompare的意义上使多态?我已经看到一些使用扩展的Haskell代码并尝试搜索它们,但我仍然无法弄清楚每个特定扩展对哪些有用.binstance Ordforall
chainCompare [f, g]如果f并且g是不同类型的函数,将始终导致错误- 无论您如何定义chainCompare.你甚至可以删除chainCompare并只是写[f, g],它仍然会导致错误.原因在于,根本不可能在列表中具有不同类型的值.
有时,当您想要将不同类型的值存储在同一列表中时,使用存在类型(GHC扩展)是有意义的.有了它,您可以定义一个存在类型Comparator并使用该列表[Comparator length, Comparator head].然而,comparing与你在第一个例子中所做的相比,这没有任何好处,所以在这种情况下它将毫无意义.
因此,您使用的第一个代码comparing实际上是您能做的最好的代码.
为了记录,这里是代码使用存在类型的样子:
{-# LANGUAGE ExistentialQuantification #-}
import Data.Monoid
import Data.Ord
data Comparator a = forall b. Ord b => Comparator (a -> b)
chainCompare :: [Comparator a] -> a -> a -> Ordering
chainCompare = mconcat . map comp
where comp (Comparator f) = comparing f
-- Usage:
list = [['a'..'z'], ['A'..'Z'], "Lorem ipsum dolor sit amet"]
sortedList = sortBy (chainCompare [Comparator length, Comparator head]) list
Run Code Online (Sandbox Code Playgroud)
与第一个版本相比,唯一的区别在于您必须编写Comparator而不是comparing使用不能基于密钥进行比较的比较函数.正如我所说,它并没有真正为你的第一个版本带来任何好处.
| 归档时间: |
|
| 查看次数: |
603 次 |
| 最近记录: |