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

时间:2016-05-10 14:26:39

标签: purescript

我有这个我要浓缩的代码

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)

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

如果允许我们稍微改变一下这个问题,我们可能会达到我想要的效果。所有函数都是curried的事实允许我们使用类型类实例解析来提出一些技巧,这些技巧允许我们使用任意arity的函数来做事。例如:

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使用类似的技术,允许您在任何arity的函数上调用quickCheck,只要所有参数都有Arbitrary个实例。但是,在这个特定的情况下,我认为我会坚持使用更简单,更多样板的解决方案:无限制地使用类型类会变得非常笨拙,并且会产生非常混乱的错误消息。