寻找类似sequenceA的函数
Looking for a function similar sequenceA
想了解有关应用程序的更多信息。
我有以下定义:
class Applicative' f where
pack :: a -> f a
unpack :: f a -> a
instance Applicative' Box where
pack x = Box x
unpack (Box x) = x
instance Applicative' Bag where
pack x = Bag x
unpack (Bag x) = x
instance Applicative' Basket where
pack x = Basket x
unpack (Basket x) = x
pack1::(Applicative' f)=>(a->b)->f a->f b
pack1 fn ta = pack (fn (unpack ta))
pack2::(Applicative' f)=>(a->b->c)->f a->f b->f c
pack2 fn ta tb = pack(fn (unpack ta) (unpack tb))
我正在寻找的是一种概括这个概念的方法(类似于 sequenceA 函数),所以应该可以通过以下方式使用这个函数(我们称之为 someFn):
somefn (\x->x+1) (Box 2)
Box 3
somefn (\x->\y->x+y) (Box 1) (Box 2)
Box 3
somefn (\x->\y->\z->x+y+z) (Box 1) (Box 2) (Box 3)
Box 6
不确定如何在 Haskell 中实现此目的。
您需要的函数类型为:
somefn :: Applicative' t => (a -> b) -> (t a -> t b)
somefn :: Applicative' t => (a -> b -> c) -> (t a -> t b -> t c)
somefn :: Applicative' t => (a -> b -> c -> d) -> (t a -> t b -> t b -> t c -> t d)
但是这些不是包含所有这些的类型,因此不存在这样的功能。特别是没有办法决定 somefn (\x y -> (x, y)) (Box 3)
应该是 Box (\y -> (3,y))
还是 \(Box y) -> Box (3,y)
.
查看 liftA2
或 liftA3
等正常 Applicative
s。
您正在寻找 liftA*
函数族:
liftA :: Applicative f => (a -> b) -> f a -> fb
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA3 :: Applicative f => (a -> b -> d -> e) -> f a -> f b -> f c -> f d
在Haskell中这些函数是分开定义的。但我想您想将其概括为一个功能。这在 Haskell 中是不可能的,因为它需要更改函数的签名。 Haskell 方法是对运算符 <$>
和 <*>
进行排序,如下所示:
liftA f a = f <$> a
liftA2 f a b = f <$> a <*> b
liftA3 f a b c = f <$> a <*> b <*> c
liftA4 f a b c d = f <$> a <*> b <*> c <*> d -- (actually not pre-defined in haskell)
.
.
.
and so on
这里发生的事情是 f <$> a
在应用容器中提升(推动)您的功能,然后您在整个 a
、b
、[=18= 中对该功能进行排序] 和 d
.
希望对您有所帮助。
正如在其他答案中已经指出的那样,您不能使用您想要的签名来编写函数。相反,您可以通过定义 (<$>)
和 (<*>)
运算符的类似物来做类似于 Applicative 所做的事情。
您可以很容易地定义这些函数:
(<@>) :: Applicative' f => (a -> b) -> f a -> f b
f <@> x = pack . f . unpack $ x
(<%>) :: Applicative' f => f (a -> b) -> f a -> f b
f <%> x = pack . unpack f . unpack $ x
这样你就可以写
(\x y z->x+y+z) <@> Box 1 <%> Box 2 <%> Box 3 -- results in Box 6
或者,如果您不介意启用几个扩展,则可以采用不同的方法。您的 Applicative' 是比 Applicative 更强的约束,因此您可以为每个 Applicative' 实例自动派生 Functor 和 Applicative 实例,免费获得 (<$>)
和 (<*>)
:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
instance Applicative' f => Functor f where
fmap f x = pack . f . unpack $ x
instance Applicative' f => Applicative f where
pure = pack
f <*> x = pack . unpack f . unpack $ x
现在我们可以写
(\x y z->x+y+z) <$> Box 1 <*> Box 2 <*> Box 3 -- results in Box 6
而且,令人高兴的是,我们还可以访问 liftA
函数族,这意味着对于相当少的参数,您实际上可以使用与您想要的函数等效的函数:
import Control.Applicative (liftA3)
liftA3 (\x y z->x+y+z) (Box 1) (Box 2) (Box 3) -- results in Box 6
你可以统一这些东西。我们需要一个异构列表,表示映射到类型列表上的某种类型构造函数:
{-# LANGUAGE GADTs, DataKinds, PolyKinds, TypeOperators, PatternSynonyms #-}
import Data.Kind (Type)
import Data.Functor.Identity
infixr 4 :<, ::<
data Rec :: [k] -> (k -> Type) -> Type where
Nil :: Rec '[] f
(:<) :: f x -> Rec xs f -> Rec (x ': xs) f
-- For convenience and clarity:
type HList xs = Rec xs Identity
pattern HNil :: () => xs ~ '[] => HList xs
pattern HNil = Nil
pattern (::<) :: () => xxs ~ (x ': xs) => x -> HList xs -> HList xxs
pattern x ::< xs = Identity x :< xs
{-# COMPLETE HNil, (::<) #-}
现在我们可以表达我们的版本 Applicative
:
class Appl f where
appl :: (HList xs -> r) -> Rec xs f -> f r
我们可以根据Applicative
定义appl
:
applApplic :: Applicative f => (Rec xs Identity -> r) -> Rec xs f -> f r
applApplic f xs0 = f <$> gather xs0
where
gather :: Applicative f => Rec xs f -> f (Rec xs Identity)
gather Nil = pure HNil
gather (x :< xs) = (\y ys -> y ::< ys) <$> x <*> gather xs
我们还可以使用 appl
:
定义 Applicative
方法
fmapAppl :: Appl f => (a -> b) -> f a -> f b
fmapAppl f xs = appl (\(q ::< HNil) -> f q) (xs :< Nil)
pureAppl :: Appl f => a -> f a
pureAppl x = appl (\HNil -> x) Nil
liftA2Appl :: Appl f => (a -> b -> c) -> f a -> f b -> f c
liftA2Appl f xs ys = appl (\(x ::< y ::< HNil) -> f x y) (xs :< ys :< Nil)
您可以使用 appl
作为一种 n 元提升:
appl (\(x ::< y ::< z ::< HNil) ->
x : y ++ z) (readLn @Int :< readLn @[Int] :< readLn @[Int] :< Nil)
不幸的是,类型推断在这里不是很好。
想了解有关应用程序的更多信息。
我有以下定义:
class Applicative' f where
pack :: a -> f a
unpack :: f a -> a
instance Applicative' Box where
pack x = Box x
unpack (Box x) = x
instance Applicative' Bag where
pack x = Bag x
unpack (Bag x) = x
instance Applicative' Basket where
pack x = Basket x
unpack (Basket x) = x
pack1::(Applicative' f)=>(a->b)->f a->f b
pack1 fn ta = pack (fn (unpack ta))
pack2::(Applicative' f)=>(a->b->c)->f a->f b->f c
pack2 fn ta tb = pack(fn (unpack ta) (unpack tb))
我正在寻找的是一种概括这个概念的方法(类似于 sequenceA 函数),所以应该可以通过以下方式使用这个函数(我们称之为 someFn):
somefn (\x->x+1) (Box 2)
Box 3
somefn (\x->\y->x+y) (Box 1) (Box 2)
Box 3
somefn (\x->\y->\z->x+y+z) (Box 1) (Box 2) (Box 3)
Box 6
不确定如何在 Haskell 中实现此目的。
您需要的函数类型为:
somefn :: Applicative' t => (a -> b) -> (t a -> t b)
somefn :: Applicative' t => (a -> b -> c) -> (t a -> t b -> t c)
somefn :: Applicative' t => (a -> b -> c -> d) -> (t a -> t b -> t b -> t c -> t d)
但是这些不是包含所有这些的类型,因此不存在这样的功能。特别是没有办法决定 somefn (\x y -> (x, y)) (Box 3)
应该是 Box (\y -> (3,y))
还是 \(Box y) -> Box (3,y)
.
查看 liftA2
或 liftA3
等正常 Applicative
s。
您正在寻找 liftA*
函数族:
liftA :: Applicative f => (a -> b) -> f a -> fb
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA3 :: Applicative f => (a -> b -> d -> e) -> f a -> f b -> f c -> f d
在Haskell中这些函数是分开定义的。但我想您想将其概括为一个功能。这在 Haskell 中是不可能的,因为它需要更改函数的签名。 Haskell 方法是对运算符 <$>
和 <*>
进行排序,如下所示:
liftA f a = f <$> a
liftA2 f a b = f <$> a <*> b
liftA3 f a b c = f <$> a <*> b <*> c
liftA4 f a b c d = f <$> a <*> b <*> c <*> d -- (actually not pre-defined in haskell)
.
.
.
and so on
这里发生的事情是 f <$> a
在应用容器中提升(推动)您的功能,然后您在整个 a
、b
、[=18= 中对该功能进行排序] 和 d
.
希望对您有所帮助。
正如在其他答案中已经指出的那样,您不能使用您想要的签名来编写函数。相反,您可以通过定义 (<$>)
和 (<*>)
运算符的类似物来做类似于 Applicative 所做的事情。
您可以很容易地定义这些函数:
(<@>) :: Applicative' f => (a -> b) -> f a -> f b
f <@> x = pack . f . unpack $ x
(<%>) :: Applicative' f => f (a -> b) -> f a -> f b
f <%> x = pack . unpack f . unpack $ x
这样你就可以写
(\x y z->x+y+z) <@> Box 1 <%> Box 2 <%> Box 3 -- results in Box 6
或者,如果您不介意启用几个扩展,则可以采用不同的方法。您的 Applicative' 是比 Applicative 更强的约束,因此您可以为每个 Applicative' 实例自动派生 Functor 和 Applicative 实例,免费获得 (<$>)
和 (<*>)
:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
instance Applicative' f => Functor f where
fmap f x = pack . f . unpack $ x
instance Applicative' f => Applicative f where
pure = pack
f <*> x = pack . unpack f . unpack $ x
现在我们可以写
(\x y z->x+y+z) <$> Box 1 <*> Box 2 <*> Box 3 -- results in Box 6
而且,令人高兴的是,我们还可以访问 liftA
函数族,这意味着对于相当少的参数,您实际上可以使用与您想要的函数等效的函数:
import Control.Applicative (liftA3)
liftA3 (\x y z->x+y+z) (Box 1) (Box 2) (Box 3) -- results in Box 6
你可以统一这些东西。我们需要一个异构列表,表示映射到类型列表上的某种类型构造函数:
{-# LANGUAGE GADTs, DataKinds, PolyKinds, TypeOperators, PatternSynonyms #-}
import Data.Kind (Type)
import Data.Functor.Identity
infixr 4 :<, ::<
data Rec :: [k] -> (k -> Type) -> Type where
Nil :: Rec '[] f
(:<) :: f x -> Rec xs f -> Rec (x ': xs) f
-- For convenience and clarity:
type HList xs = Rec xs Identity
pattern HNil :: () => xs ~ '[] => HList xs
pattern HNil = Nil
pattern (::<) :: () => xxs ~ (x ': xs) => x -> HList xs -> HList xxs
pattern x ::< xs = Identity x :< xs
{-# COMPLETE HNil, (::<) #-}
现在我们可以表达我们的版本 Applicative
:
class Appl f where
appl :: (HList xs -> r) -> Rec xs f -> f r
我们可以根据Applicative
定义appl
:
applApplic :: Applicative f => (Rec xs Identity -> r) -> Rec xs f -> f r
applApplic f xs0 = f <$> gather xs0
where
gather :: Applicative f => Rec xs f -> f (Rec xs Identity)
gather Nil = pure HNil
gather (x :< xs) = (\y ys -> y ::< ys) <$> x <*> gather xs
我们还可以使用 appl
:
Applicative
方法
fmapAppl :: Appl f => (a -> b) -> f a -> f b
fmapAppl f xs = appl (\(q ::< HNil) -> f q) (xs :< Nil)
pureAppl :: Appl f => a -> f a
pureAppl x = appl (\HNil -> x) Nil
liftA2Appl :: Appl f => (a -> b -> c) -> f a -> f b -> f c
liftA2Appl f xs ys = appl (\(x ::< y ::< HNil) -> f x y) (xs :< ys :< Nil)
您可以使用 appl
作为一种 n 元提升:
appl (\(x ::< y ::< z ::< HNil) ->
x : y ++ z) (readLn @Int :< readLn @[Int] :< readLn @[Int] :< Nil)
不幸的是,类型推断在这里不是很好。