我为没有提出这个问题的好标题而道歉.我在表达我需要的东西时遇到了一些麻烦.我在Haskell中有一个简单的问题,我想知道解决它的最佳方法是什么.
假设我有一个数字列表:[-3,2,1,2].我想返回具有最高绝对值的值.也就是说,我想返回-3.所以我想:
f = maximum . map abs
Run Code Online (Sandbox Code Playgroud)
当然,问题是返回计算值(3)而不是原始值(-3).
我可以想办法做到这一点,也许将原始列表映射到(originalValue,calculatdValue)元组,找到snd由我的函数返回的元组(最大值),然后返回该元组的fst.
但对于像这样的简单问题,这似乎有很多"管道",我想知道是否有一些我想念的抽象解决了这个问题.也就是说,我一直都会这样做,我想要一些巧妙的方法:
[-3,2,1,2],我想返回具有最高abs的值,那么我将返回-3).这有库函数吗?这有一个仿函数或一个monad吗?
我想我想要一个带签名的功能:
f :: ([b] -> b) -> (a -> b) -> [a] -> a
Run Code Online (Sandbox Code Playgroud)
即
f maximum abs [-3,2,1,2]
Run Code Online (Sandbox Code Playgroud)
这对我来说非常"乐观",或者可能是"monadic".
aug*_*tss 20
使用带有比较功能的maximumBy.然后,您可以传递一些比较您想要的功能.
maximumBy (compare `on` abs)
Run Code Online (Sandbox Code Playgroud)
另一种方法,如果转换有点贵:
maximumWith :: (Ord b) => (a -> b) -> [a] -> a
maximumWith f = snd . maximumBy (compare `on` fst) . map (f &&& id)
Run Code Online (Sandbox Code Playgroud)
这种类型与GHC.Exts's 类似sortWith,这为我们提供了另一种方法:
maximumWith :: (Ord b) => (a -> b) -> [a] -> a
maximumWith f = head . sortWith (Down . f)
Run Code Online (Sandbox Code Playgroud)
我们可以类似地定义一个最小值:
minimumWith :: (Ord b) => (a -> b) -> [a] -> a
minimumWith f = head . sortWith f
Run Code Online (Sandbox Code Playgroud)
看一下源代码sortWith就会发现它是由它实现的sortBy,因此缺少第一个定义的缓存maximumWith.
这显然需要一些基准测试:
module Main where
import Control.Arrow ((&&&))
import Data.List (sortBy)
import Data.Function (on)
import GHC.Exts (sortWith)
import Criterion.Main
sortWith :: (Ord b) => (a -> b) -> [a] -> [a]
sortWith f = map snd . sortBy (compare `on` fst) . map (f &&& id)
badFib :: Int -> Int
badFib 0 = 1
badFib 1 = 1
badFib n = badFib (n - 1) + badFib (n - 2)
main = defaultMain [ bench "GHC.Exts.sortWith" $ nf (GHC.Exts.sortWith badFib) [0..20]
, bench "Main.sortWith" $ nf (Main.sortWith badFib) [0..20]
]
Run Code Online (Sandbox Code Playgroud)
我的笔记本电脑上的结果:
benchmarking GHC.Exts.sortWith
collecting 100 samples, 12 iterations each, in estimated 1.504415 s
bootstrapping with 100000 resamples
mean: 1.264608 ms, lb 1.260519 ms, ub 1.270248 ms, ci 0.950
std dev: 24.42169 us, lb 19.21734 us, ub 31.50275 us, ci 0.950
found 8 outliers among 100 samples (8.0%)
5 (5.0%) high mild
3 (3.0%) high severe
variance introduced by outliers: 0.996%
variance is unaffected by outliers
benchmarking Main.sortWith
collecting 100 samples, 50 iterations each, in estimated 1.516733 s
bootstrapping with 100000 resamples
mean: 305.9089 us, lb 304.0602 us, ub 310.9257 us, ci 0.950
std dev: 14.41005 us, lb 6.680240 us, ub 30.26940 us, ci 0.950
found 18 outliers among 100 samples (18.0%)
9 (9.0%) high mild
9 (9.0%) high severe
variance introduced by outliers: 0.999%
variance is unaffected by outliers
Run Code Online (Sandbox Code Playgroud)