【问题标题】:Equivalent of Array.some and Array.every in Haskell?Haskell 中 Array.some 和 Array.every 的等价物?
【发布时间】:2021-06-05 09:25:45
【问题描述】:

类似[(a->b)] -> a -> [b] 这样的类型。我当然可以编写代码,但我想为它指定正确的功能名称。

情况如下:

我是函数式编程的新手,我目前正在使用 JavaScript。

我有一个谓词函数数组:

 //predicate :: string -> a -> boolean

 let arr = [ predicate(foo), predicate(bar), predicate(baz) ]

我想将它们应用到value,并返回一组结果:

 let res = [ arr[0](value), arr[1](value), arr[2](value) ]
 // res = [ true ,false, true]

最后我想使用Any.concatAll.concat 链接数组

 final_result = Any(res[0]).concat(Any(res[1])).concat(Any(res[2])).valueOf()
 // final_result = true | false

谢谢。

【问题讨论】:

  • 我不是 Javascript 专家,但我是 Haskell 专家。 Any(true) 是做什么的?
  • @DanielWagner 对不起我的错,不是 javascript 的一部分。它是在 js 中实现的 Monoid Any 。 crocks.dev/docs/monoids/Any.html.

标签: javascript haskell functional-programming


【解决方案1】:

Haskell 不是范畴论。 Haskell 就是 Haskell。

另一种编写函数的方法是:

import Data.Monoid (Any(..), All (..))
import Data.Coerce

any' :: [a -> Bool] -> a -> Bool
any' = fmap getAny . foldMap (fmap Any)
-- alternatively
any' = fmap getAny . foldMap coerce

all' :: [a -> Bool] -> a -> Bool
all' = fmap getAll . foldMap (fmap All)
-- alternatively
all' = fmap getAll . foldMap coerce

使用foldMap,也可以选择使用coerce,以避免编写fmap Anyfmap All,这可以从其他地方的类型信息中推断出来。

这个答案取决于一个以幺半群结尾的函数本身就是一个幺半群的事实:

Monoid b => Monoid (a -> b)

因为AnyAllMonoid 实例,所以a -> Anya -> All 也将有Monoid 实例。

mempty :: a -> Any 是一个忽略其输入并返回mempty :: Any 的函数,即Any False,即“或”运算的中性元素。 a -> All 也是如此。

mappend :: (a -> Any) -> (a -> Any) -> a -> Any 接受两个函数,并返回一个新函数,该函数将自己的输入提供给之前的每个函数,并执行结果 Anys 的 mappenda -> All 也是如此。

foldMap 函数将映射到某个列表的操作(生成作为Monoid 的实例的值)与mappend 生成所有结果值的操作相结合。在我们的例子中,我们只是将函数的“提示”包装到 Any/All 中,以便能够 mappend 函数。然后——有点烦人——我们必须解开包装。

【讨论】:

  • 您的导入错误:您要导入Any(..),否则您将无法访问 Any 构造函数。此外,我不太喜欢将 (fmap Any) 用作 (. Any) 的同义词 - 函数函子的隐式使用通常很令人困惑。
  • @amalloy 谢谢,已更正。我同意使用函数Functor/Applicative/Monad 经常令人困惑,但在达到函数“结束”以应用一些转换的特殊情况下,我更喜欢它而不是(. Any)。我发现涉及. 的运算符部分难以理解。添加更多fmaps 来处理具有多个参数的函数也很容易。
  • @BabakKarimiAsl 是的。有预先存在的 andall 函数直接使用布尔值,然后(独立地)在 Data.Monoid 中有新类型 AnyAll。这些新类型的值使用它们的Monoid 实例进行组合。这是一种不同的风格:对于新类型,要执行的确切和/或操作与新类型本身相关,然后具有Monoid 实例给出的“混合值”操作。此外,mempty :: Allmempty :: Any 将分别返回 andor 操作的中性元素。
  • @BabakKarimiAssl 把东西“混在一起”的操作叫做mappendhackage.haskell.org/package/base-4.14.1.0/docs/… 也可以用操作符<>hackage.haskell.org/package/base-4.14.1.0/docs/…
  • @BabakKarimiAsl 我不确定我们是否需要flipall' 接收谓词列表以及它们应该应用到的值。这还不够吗?
【解决方案2】:

在 Haskell 中,我们有 sequence,它专门用于:

sequence :: [a -> b] -> a -> [b]

但我不会将它用于您显示的代码。相反,我会写其中之一:

finalResult = or [predicate x value | x <- arr]
finalResult = any (flip predicate value) arr

【讨论】:

  • 我投了反对票,因为它使用了 Applicative 函数(这经常令人困惑,并且暗示确实存在比实际更深层次的东西),甚至没有提及它。
猜你喜欢
  • 1970-01-01
  • 2017-12-22
  • 2015-01-12
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多