Haskell 至少有两个可能

Haskell 至少有两个可能,haskell,maybe,Haskell,Maybe,我想得到两个maybe值中的最小值,或者如果一个值为空,则得到非空值,或者如果两个输入都为空,则返回空值。我可以编写一个简单的函数来实现这一点,但我怀疑有一种方法可以在不编写自定义函数的情况下实现这一点。对不起,如果这是一个小问题,但是有没有比使用这个自定义函数更简单的方法 minMaybe :: Ord a => Maybe a -> Maybe a -> Maybe a minMaybe Nothing b = b minMaybe a Nothing = a minMay

我想得到两个maybe值中的最小值,或者如果一个值为空,则得到非空值,或者如果两个输入都为空,则返回空值。我可以编写一个简单的函数来实现这一点,但我怀疑有一种方法可以在不编写自定义函数的情况下实现这一点。对不起,如果这是一个小问题,但是有没有比使用这个自定义函数更简单的方法

minMaybe :: Ord a => Maybe a -> Maybe a -> Maybe a
minMaybe Nothing b = b
minMaybe a Nothing = a
minMaybe (Just a) (Just b) = Just $ min a b

您不能为此使用
Applicative
Monad
实例,因为这些上下文中的任何
Nothing
都将使您的总结果为
Nothing
。话虽如此,术语“simpler”是非常固执己见的,而且您的函数本身就很好。

您可以使用
替代
实例编写它:

minMaybe a b = liftA2 min a b <|> a <|> b

但我不建议这样做

可以使用
Control.Applicative
中的运算符来满足规范要求

myMin :: Ord x => Maybe x -> Maybe x -> Maybe x
myMin a b = min <$> a <*> b <|> a <|> b
问题是

min <$> Just a <*> Just b = Just (min a b)

您会发现
Topped x的
min
正是您所需要的。最好将类型不仅仅看作是数据的表示,而是具有结构的数据的设备<代码>无
通常表示某种类型的故障,因此最好使用不同类型的故障。

问题是关于提升功能
min::Ord a⇒ A.→ A.→ 与
一起工作的
可能是
的上下文。它是关联的,因此
半群
实例完全满足您的要求:

min' :: forall a. Ord a => Maybe a -> Maybe a -> Maybe a
min' = coerce ((<>) @(Maybe (Min a)))
另外,我想说你的解决方案很好。

我认为radomaj有一个解决方案

现在你可以写作了

minMaybes mx my = addMaxToMaybe $
  (min `on` maybeToAddMax) mx my
你也可以耍点花招:

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
import Data.Ord
import Data.Function
import Data.Coerce

newtype AddMax a = AddMax {unAddMax :: Down (Maybe (Down a))}
  deriving (Eq, Ord)
现在


在我被那个猪倌否决之前;)。。。关于:
让minM a b=也许a只是$mayb只是$mina b
?也许n.m,这是可行的,但它并不比我开始的更简单。注意:社区wiki因为“更简单”是非常固执己见的。因为
max
就像@clay希望它(“更喜欢”只是价值观而不是虚无)那样工作,也许如果@clay使用Data.Ord.Down,那么他们会有他们想要的行为,同时仍然以其他答案所希望的方式“更简单”。
Topped x
有一个合理的
max
,但是如果你想添加一个底部元素,那么预期的语义会改变,那么为什么类型应该保持不变呢?当然,我们可以做一次“从半群生成幺半群”构造,然后将
max
min
等包装为半群结构。然而,后者看起来确实比“更简单”…@chi-Huh,这意味着如果问题使用的是
max
而不是
min
max
将是正确的答案。或者换一种说法,
触底
只是
也许
本身。我知道我回答这个问题已经很晚了,但这到底是怎么回事。Hackage上的monoid extras包(以及
Bottomed
变体)和一些用于处理它的小实用程序。这打破了关注点分离原则——在比较所携带数据时涉及到外部结构(或IOW,不能仅使用
min
将其更改为
maxMaybes
)<代码>向下
还可以翻转相等的选择…@Willenss,您可以通过加倍来修复相等的选择:将其包裹在外部和内部。我同意分离关注点很糟糕。我试过双倍下降,但没能成功。。。我所拥有的:
data xa=X(a,a)
,它只通过第一个元素比较对;然后
max[Down$X(1,2)][Down$X(1,3)]
返回
[Down(X(1,3))]
。使用
Down
两次不会改变这一点(正如
max(Down[Down$X(1,2)])(Down[Down$X(1,3)])
)。这应该怎么做?@WillNess,使用double-down,您可以使用
min
。谢谢。出于某种原因,
max(X(1,2))(X(1,3))
返回
X(1,3)
,这就是让我失望的原因。不管怎么说,整个可分辨的等价物与纯度不太匹配。
data Topped x = Val x | Top deriving (Show, Eq, Ord)
min' :: forall a. Ord a => Maybe a -> Maybe a -> Maybe a
min' = coerce ((<>) @(Maybe (Min a)))
min'' :: Ord a => Maybe a -> Maybe a -> Maybe a
min'' x y = fmap getMin (fmap Min x <> fmap Min y)
import Data.Ord (Down (..))
import Data.Function (on)

minMaybes mx my =
  getDown <$> (max `on` fmap Down) mx my
getDown (Down x) = x
data AddMax a = TheMax | Plain a deriving Eq
instance Ord a => Ord (AddMax a) where
  TheMax <= Plain _ = False
  _ <= TheMax = True
  Plain a <= Plain b = a <= b

maybeToAddMax :: Maybe a -> AddMax a
maybeToAddMax = maybe TheMax Plain

addMaxToMaybe :: AddMax a -> Maybe a
addMaxToMaybe TheMax = Nothing
addMaxToMaybe (Plain a) = Just a
minMaybes mx my = addMaxToMaybe $
  (min `on` maybeToAddMax) mx my
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
import Data.Ord
import Data.Function
import Data.Coerce

newtype AddMax a = AddMax {unAddMax :: Down (Maybe (Down a))}
  deriving (Eq, Ord)
minMaybes :: forall a. Ord a => Maybe a -> Maybe a -> Maybe a
minMaybes = coerce (min @(AddMax a))