我可以使用一些 `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 会变得非常笨拙,并且会产生非常混乱的错误消息。
我有这段代码,我想对其进行压缩
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 会变得非常笨拙,并且会产生非常混乱的错误消息。