"find minimum" 函数的另一个 Maybe
Another Maybe for "find minimum" functions
当我们搜索“最大”值而不方便查找最小值时,也许有用
-- update maximum could be used as "lambda"
updateMaximum :: (Ord a) => Maybe a -> Maybe a -> Maybe a
updateMaximum saved new = max new saved
-- update minimum could't be used as "lambda"
updateMinimum Nothing new = new
updateMinimum saved Nothing = saved
updateMininum saved new = min new saved
理想的解决方案是 standard monad 和另一个构造函数顺序,但我没有找到它:
data Maybe' a = Just' a | Notheing'
-- all standard functions implementations:
safeHaad' :: [a] -> Maybe' a
...
所以问题是:haskell 中编写“updateMinimum”函数的标准方法是什么?
P.S。
有两种可能的解决方案,但各有其缺点:
- 更改问题措辞:找到函数“f()”的最小值 -> 找到函数“0-f()”的最大值
- 将“MyMaybe”与交换的构造函数顺序一起使用:data MyMaybe a = Value a | None
可以暂时用Down
换行,倒序,取反序下的max
,待会再展开:
import Data.Ord
updateMaximum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMaximum x y = max x y
updateMinimum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMinimum x y = getDown <$> max (Down <$> x) (Down <$> y)
注意微妙的部分:我们在 Maybe
下换行,因此即使我们颠倒顺序,Nothing
仍然是最小值。这使得 max
做正确的事。
一些测试证实这可以按需工作。下面,前两个值是测试输入,第三个是输出。
max: (Nothing,Nothing,Nothing)
min: (Nothing,Nothing,Nothing)
max: (Nothing,Just 1,Just 1)
min: (Nothing,Just 1,Just 1)
max: (Nothing,Just 2,Just 2)
min: (Nothing,Just 2,Just 2)
max: (Just 1,Nothing,Just 1)
min: (Just 1,Nothing,Just 1)
max: (Just 1,Just 1,Just 1)
min: (Just 1,Just 1,Just 1)
max: (Just 1,Just 2,Just 2)
min: (Just 1,Just 2,Just 1)
max: (Just 2,Nothing,Just 2)
min: (Just 2,Nothing,Just 2)
max: (Just 2,Just 1,Just 2)
min: (Just 2,Just 1,Just 1)
max: (Just 2,Just 2,Just 2)
min: (Just 2,Just 2,Just 2)
完整代码:
module Main where
import Data.Foldable
import Data.Ord
updateMaximum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMaximum x y = max x y
updateMinimum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMinimum x y = getDown <$> max (Down <$> x) (Down <$> y)
main :: IO ()
main = do
let xs = [ Nothing, Just 1, Just 2 ] :: [Maybe Int]
for_ xs $ \x ->
for_ xs $ \y -> do
putStr "max: "
print (x, y, updateMaximum x y)
putStr "min: "
print (x, y, updateMinimum x y)
pure ()
您并不是真的希望 Nothing 成为此处排序的一部分,而是在您进行二元运算时“被忽略”,或者换句话说,就像一个身份一样。这是 Maybe 的 Monoid 行为,我们可以使用 Semigroup 实例 Min 和 Max。
updateMinimum x y = fmap getMin (fmap Min x <> fmap Min y)
updateMaximum x y = fmap getMax (fmap Max x <> fmap Max y)
point-free 版本并没有真正的改进,但它看起来像这样:
updateMinimum = (fmap getMin .) . ((<>) `on` fmap Min)
在 的基础上什至有一个更简洁的解决方案,它仍然是无意义的,但我感觉更清楚一些,因为它隐藏了 .
的复杂双重使用到 ad-hoc来自模块 Data.Composition
的运算符 .:
:
import Data.Function (on)
import Data.Semigroup
import Data.Composition ((.:))
-- (.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
updateMinimum :: (Ord a) => Maybe a -> Maybe a -> Maybe a
updateMinimum = fmap getMin .: ((<>) `on` fmap Min)
其中 updateMinimum
的定义对此数据流进行编码
┌───────────┐
┌┤fmap getMin├─ first input
┌───────────┐ ┌────┐ │└───────────┘
output ─┤fmap getMin├──┤(<>)├─┤
└───────────┘ └────┘ │┌───────────┐
└┤fmap getMin├─ second input
└───────────┘
monoid-extras 包提供 Inf
数据类型,具有变体 PosInf
和 NegInf
,正是为了这个目的。您的两个函数如下所示:
updateMaximum :: Ord a => NegInf a -> NegInf a -> NegInf a
updateMaximum = max
updateMinimum :: Ord a => PosInf a -> PosInf a -> PosInf a
updateMinimum = min
我什至懒得给他们起名字。
当我们搜索“最大”值而不方便查找最小值时,也许有用
-- update maximum could be used as "lambda"
updateMaximum :: (Ord a) => Maybe a -> Maybe a -> Maybe a
updateMaximum saved new = max new saved
-- update minimum could't be used as "lambda"
updateMinimum Nothing new = new
updateMinimum saved Nothing = saved
updateMininum saved new = min new saved
理想的解决方案是 standard monad 和另一个构造函数顺序,但我没有找到它:
data Maybe' a = Just' a | Notheing'
-- all standard functions implementations:
safeHaad' :: [a] -> Maybe' a
...
所以问题是:haskell 中编写“updateMinimum”函数的标准方法是什么?
P.S。 有两种可能的解决方案,但各有其缺点:
- 更改问题措辞:找到函数“f()”的最小值 -> 找到函数“0-f()”的最大值
- 将“MyMaybe”与交换的构造函数顺序一起使用:data MyMaybe a = Value a | None
可以暂时用Down
换行,倒序,取反序下的max
,待会再展开:
import Data.Ord
updateMaximum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMaximum x y = max x y
updateMinimum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMinimum x y = getDown <$> max (Down <$> x) (Down <$> y)
注意微妙的部分:我们在 Maybe
下换行,因此即使我们颠倒顺序,Nothing
仍然是最小值。这使得 max
做正确的事。
一些测试证实这可以按需工作。下面,前两个值是测试输入,第三个是输出。
max: (Nothing,Nothing,Nothing)
min: (Nothing,Nothing,Nothing)
max: (Nothing,Just 1,Just 1)
min: (Nothing,Just 1,Just 1)
max: (Nothing,Just 2,Just 2)
min: (Nothing,Just 2,Just 2)
max: (Just 1,Nothing,Just 1)
min: (Just 1,Nothing,Just 1)
max: (Just 1,Just 1,Just 1)
min: (Just 1,Just 1,Just 1)
max: (Just 1,Just 2,Just 2)
min: (Just 1,Just 2,Just 1)
max: (Just 2,Nothing,Just 2)
min: (Just 2,Nothing,Just 2)
max: (Just 2,Just 1,Just 2)
min: (Just 2,Just 1,Just 1)
max: (Just 2,Just 2,Just 2)
min: (Just 2,Just 2,Just 2)
完整代码:
module Main where
import Data.Foldable
import Data.Ord
updateMaximum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMaximum x y = max x y
updateMinimum :: Ord a => Maybe a -> Maybe a -> Maybe a
updateMinimum x y = getDown <$> max (Down <$> x) (Down <$> y)
main :: IO ()
main = do
let xs = [ Nothing, Just 1, Just 2 ] :: [Maybe Int]
for_ xs $ \x ->
for_ xs $ \y -> do
putStr "max: "
print (x, y, updateMaximum x y)
putStr "min: "
print (x, y, updateMinimum x y)
pure ()
您并不是真的希望 Nothing 成为此处排序的一部分,而是在您进行二元运算时“被忽略”,或者换句话说,就像一个身份一样。这是 Maybe 的 Monoid 行为,我们可以使用 Semigroup 实例 Min 和 Max。
updateMinimum x y = fmap getMin (fmap Min x <> fmap Min y)
updateMaximum x y = fmap getMax (fmap Max x <> fmap Max y)
point-free 版本并没有真正的改进,但它看起来像这样:
updateMinimum = (fmap getMin .) . ((<>) `on` fmap Min)
在 .
的复杂双重使用到 ad-hoc来自模块 Data.Composition
的运算符 .:
:
import Data.Function (on)
import Data.Semigroup
import Data.Composition ((.:))
-- (.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
updateMinimum :: (Ord a) => Maybe a -> Maybe a -> Maybe a
updateMinimum = fmap getMin .: ((<>) `on` fmap Min)
其中 updateMinimum
的定义对此数据流进行编码
┌───────────┐
┌┤fmap getMin├─ first input
┌───────────┐ ┌────┐ │└───────────┘
output ─┤fmap getMin├──┤(<>)├─┤
└───────────┘ └────┘ │┌───────────┐
└┤fmap getMin├─ second input
└───────────┘
monoid-extras 包提供 Inf
数据类型,具有变体 PosInf
和 NegInf
,正是为了这个目的。您的两个函数如下所示:
updateMaximum :: Ord a => NegInf a -> NegInf a -> NegInf a
updateMaximum = max
updateMinimum :: Ord a => PosInf a -> PosInf a -> PosInf a
updateMinimum = min
我什至懒得给他们起名字。