应用类型类基于两个不同的仿函数

问题描述 投票:3回答:4

是否有类似于Applicative类型的类,但是应用程序的每一侧有两个仿函数是不同的?

即yaazkssvpoi

haskell functor applicative
4个回答
5
投票

(根据评论中@dfeuer的建议。)

有一个名为(<*>) :: (Functor f, Functor g) => f (a -> b) -> g a -> f b的结构,可以让你在执行应用程序操作时保留两个仿函数之间的区别,并延迟将一个仿函数转换为另一个仿函数的时刻。

day convolution类型只是一对函数值,以及结合各自结果的函数:

Day

请注意,仿函数的实际返回值是存在的;组合的返回值是函数的返回值。

data Day f g a = forall b c. Day (f b) (g c) (b -> c -> a) 优于其他组合应用函子的方法。与Day不同,该作品仍然适用。与Sum不同,该组合是“无偏见的”,并不强加嵌套顺序。与Compose不同,它让我们可以轻松地将应用程序操作与不同的返回类型相结合,我们只需要提供合适的适配器功能。

例如,这里有两个Product值:

Day ZipList (Vec Nat2) Char

{-# LANGUAGE DataKinds #-} import Data.Functor.Day -- from "kan-extensions" import Data.Type.Nat -- from "fin" import Data.Vec.Lazy -- from "vec" import Control.Applicative day1 :: Day ZipList (Vec Nat2) Char day1 = Day (pure ()) ('b' ::: 'a' ::: VNil) (flip const) day2 :: Day ZipList (Vec Nat2) Char day2 = Day (ZipList "foo") (pure ()) const 来自Nat2包,它用于参数化来自fin的固定大小的Vec。)

我们可以把它们拉在一起就好了:

vec

然后将res :: Day ZipList (Vec Nat2) (Char,Char) res = (,) <$> day1 <*> day2 变成Vec并坍塌ZipList

Day

使用res' :: ZipList (Char,Char) res' = dap $ trans2 (ZipList . toList) res ghci> res' ZipList {getZipList = [('b','f'),('a','o')]} dap函数。

可能的性能问题:当我们将一个仿函数提升到trans2时,另一个被赋予一个虚拟的Day值。但是当将pure ()s与Day结合时,这是一个沉重的负担。通过在(<*>)中包装变形金刚的仿函数,可以更聪明地工作,以便为简单的“纯”情况​​获得更快的操作。


2
投票

“序列类型”的一个一般概念是自由的幺半群。既然你正在研究多态序列类型,我们可以建立在Lift上。

Traversable

见下面的注释。

class Semigroup1 t where
  (<=>) :: t a -> t a -> t a

class Semigroup1 t => Monoid1 t where
  mempty1 :: t a

这是一个序列类型?非常低效。但是我们可以添加一些带有默认实现的方法来提高效率。以下是一些基本功能:

class (Traversable t, Monoid1 t) => Sequence t where
  singleton :: a -> t a

使用这些工具,您可以将任意两个序列压缩成第三个。

cons :: Sequence t => a -> t a -> t a
cons x xs = singleton x <=> xs

fromList
  :: (Foldable f, Sequence t)
  => f a -> t a
fromList = foldr cons mempty1

uncons :: Sequence t => t a -> Maybe (a, t a)
uncons xs = case toList xs of
  y:ys -> Just (y, fromList ys)
  [] -> Nothing

Note on recent GHC versions

对于前沿的GHC,你可以使用zipApp :: (Foldable t, Foldable u, Sequence v) = t (a -> b) -> u a -> v b zipApp fs xs = fromList $ zipWith ($) (toList fs) (toList xs) QuantifiedConstraintsRankNTypes并定义

ConstraintKinds

这样做会让你写,例如,

type Semigroup1 t = forall a. Semigroup (t a)

type Monoid1 t = forall a. Monoid (t a)

1
投票

从您的评论中,我认为您可能正在尝试构建:

fromList = foldMap singleton

这允许,例如:

import Data.Foldable
import Data.Traversable
foo :: (Traversable f, Foldable g) => f (a -> b) -> g a -> f b
foo f g = snd $ mapAccumR (\(a:as) fab -> (as, fab a)) (toList g) f

0
投票

我不知道任何一般的> import qualified Data.Vector as V > foo [(+1),(+2),(+3)] (V.fromList [5,6,7]) [8,8,8] > 。 我会写具体版本,或者最多概括一下输入类型。以下是fromList的例子,忽略了Vector已经存在。

Data.Vector.zip

你可以在第二个例子中使用import qualified Data.Vector as V import Data.Vector (Vector) import Data.Foldable import GHC.Exts (IsList(fromList)) zipV1 :: Vector (a -> b) -> Vector a -> Vector b zipV1 fs as = V.fromList (zipWith ($) (V.toList fs) (V.toList as)) zipV2 :: (Foldable f, Foldable g, IsList (f b)) => f (a -> b) -> g a -> f b zipV2 fs as = fromList (zipWith ($) (toList fs) (toList as)) 而不是IsList

© www.soinside.com 2019 - 2024. All rights reserved.