0

我有这段代码,我想压缩

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)
4

2 回答 2

2

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

于 2016-05-10T15:48:06.093 回答
1

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

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实例。不过,在这种特定情况下,我想我会坚持使用更简单、更样板化的解决方案:无限制地使用类型类可能会变得非常笨拙,并且会产生非常混乱的错误消息。

于 2016-05-11T00:00:38.827 回答