我可以使用一些 `map` 或 `apply` 来压缩这个表达式吗?

Can I condense this expression by using some `map` or `apply`?

我有这段代码,我想对其进行压缩

runFn someFn $ toArray a1 $ toArray a2 $ toArray a3 $ toArray a4

我想像

runFn someFn <$> fmap toArray [a1, a2, a3, a4]

在这种情况下,runFn someFn 将创建一个部分应用的函数,该函数等待其缺少的参数,然后一个一个地应用于数组的元素。

我必须承认我不知道类型系统是否允许这样做。

编辑 正如所要求的那样 - 这里是实际的类型签名。 但是我的问题更笼统:

如果函数的参数类型相同,并且按数组元素部分应用函数数组元素,我可以将这些函数的参数放入数组中吗?

type Numbers = Array Number
foreign import _intersect :: Numbers -> Numbers -> Numbers -> Numbers -> Point2D
data Point2D = Point2D Number Number
toArray :: Point2D -> Numbers
toArray (Point2D x y) = [x, y]

a1 = Point2D 0.5 7.0
a2 = Point2D 3.0 5.1
b1 = Point2D 2.5 9.0
b2 = Point2D 2.1 3.6

intersection :: Numbers -- 2 element Array Number
intersection = _intersect (toArray a1) (toArray a2) (toArray b1) (toArray b2)

如果我明白你在这里问什么,不,你不能。您需要依赖类型才能表达这一点,因为您需要某种方法来确保函数元数和数组长度在类型级别相等。

如果允许我们稍微改变一下问题,我们也许能够实现我认为你想要的。所有函数都是柯里化的事实允许我们使用类型 class 实例解析来想出一些技巧,这些技巧可以让我们使用任意数量的函数来做事。例如:

module Main where

import Prelude
import Data.Foldable (sum)
import Control.Monad.Eff.Console (print)

class Convert a b where
  convert :: a -> b

data Point2D = Point2D Number Number
type Numbers = Array Number

instance convertId :: Convert a a where
  convert = id

instance convertPoint :: Convert Point2D (Array Number) where
  convert (Point2D x y) = [x, y]

instance convertChain :: (Convert b a, Convert r r') => Convert (a -> r) (b -> r') where
  convert a2r b = convert (a2r (convert b))

f :: Numbers -> Numbers -> Number
f xs ys = sum xs * sum ys

g :: Point2D -> Point2D -> Number
g = convert f

f' :: Numbers -> Numbers -> Numbers -> Numbers -> Number
f' a b c d = f a b + f c d

g' :: Point2D -> Point2D -> Point2D -> Point2D -> Number
g' = convert f'

main =
  print $ g'
    (Point2D 1.0 2.0)
    (Point2D 3.0 4.0)
    (Point2D 5.0 6.0)
    (Point2D 7.0 8.0)

这些技术有一些不错的应用。例如,QuickCheck 使用类似的技术允许您在任何参数的函数上调用 quickCheck,只要所有参数都具有 Arbitrary 实例。不过,在这种特定情况下,我认为我会坚持使用更简单、更样板式的解决方案:无限制地使用类型 classes 会变得非常笨拙,并且会产生非常混乱的错误消息。