为什么纯的类型是 - > fa,而不是(a - > b) - > F(a - > b)应用?

发布于 2025-01-22 02:10:52 字数 291 浏览 3 评论 0原文

PURE用于将正常函数转换为应用程序容器中的功能。这样,任何多参数操作都可以在应用上使用。在这种情况下,不希望纯为a - > f a类型,它只是希望为(a - > b) - > f(a - > b)类型。但是pure的类型是a - > f a。为什么应该将正常值转换为应用?使用是否有更多目的比转换功能更多?

Pure is used to transform normal function into function in Applicative container. With this, any multi-parameter operations become can be used on Applicative. In this context, pure is not desired to be a -> f a type, it is just desired to be (a -> b) -> f (a -> b) type. But type of pure is a -> f a. Why should normal values can be transformed into Applicative? Is there more purpose for use pure more than transforming functions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

好倦 2025-01-29 02:10:52

我找不到应用提升功能的应用接口(即,(<*>))是一个很好的直觉。由于各种原因,概念化功能更为复杂。

我更喜欢考虑应用作为举起 n - ary函数

liftA0 :: Applicative f => (a)                -> (f a)
liftA  :: Functor     f => (a -> b)           -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c)      -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)

,其中lifta0 = purelifta已经存在为<代码> fmap 根据应用定义。

事实是,0-ary和1-ary升降机

liftA0 @f @a    :: Applicative f => a -> f a
liftA  @f @a @b :: Applicative f => (a -> b) -> (f a -> f b)

都可以采用a - &gt; b函数如果我们实例化lifta0 = pure在功能类型上:

liftA0 @f @(a->b) :: Applicative f => (a -> b) -> f (a->b)
liftA  @f @a @b   :: Applicative f => (a -> b) -> (f a -> f b)

so pure @f @(a-&gt; b)已经具有该类型。

有很多目的,理论上在haskell中是实用的,如果应用程序被视为monoid,则是单位。自然转化的类别,带有() https://hackage.haskell.org/package/kan-extensions-5.2.3/docs/data-functor-day.html“ rel =“ nofollow noreferrer”> day day

type Mempty :: Type -> Type
type Mempty = Identity

type Mappend :: (Type -> Type) -> (Type -> Type) -> (Type -> Type)
type Mappend = Day

mempty :: Applicative f => Mempty ~> f
mempty (Identity a) = pure a

mappend :: Mappend f f ~> f
mappend (LiftA2 (·) as bs) = liftA2 (·) as bs

刚刚发布了一个与应用同构的库,该库是尊重应用结构的多态函数。它为此类结构定义类型类

type  Idiom :: k -> (Type -> Type) -> (Type -> Type) -> Constraint
class (Applicative f, Applicative g) => Idiom tag f g where
  idiom :: f ~> g

,其中pure初始应用态度

-- https://chrisdone.com/posts/haskell-constraint-trick/
instance (Identity ~ id, Applicative f) => Idiom Initial id f where
  idiom :: Identity ~> f
  idiom (Identity a) = pure a

然后,经常使用纯作为计算单元。这是traverable Haskell的成功故事之一,

instance Traversable [] where
  traverse :: Applicative f => (a -> f b) -> ([a] -> f [b])
  traverse f []     = pure []
  traverse f (x:xs) = ...

我们需要pure,因为我们唯一产生应用>应用程序 -Action的参数为<代码> f x ,但是使用一个空列表,我们没有x :: a对其进行喂食。因此,我们需要0-1年的举重。

I don't find the Applicative interface of applying lifted functions (namely, (<*>)) a good intuition. Functions are more complicated to conceptualize for various reasons.

I prefer thinking of Applicative as lifting an n-ary function

liftA0 :: Applicative f => (a)                -> (f a)
liftA  :: Functor     f => (a -> b)           -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c)      -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)

where liftA0 = pure and liftA already exists as fmap defined in terms of Applicative.

The thing is that 0-ary and 1-ary liftings

liftA0 @f @a    :: Applicative f => a -> f a
liftA  @f @a @b :: Applicative f => (a -> b) -> (f a -> f b)

can both take an a -> b function if we instantiate liftA0 = pure at a function type:

liftA0 @f @(a->b) :: Applicative f => (a -> b) -> f (a->b)
liftA  @f @a @b   :: Applicative f => (a -> b) -> (f a -> f b)

So pure @f @(a->b) already has that type.

And pure has plenty of purposes, theoretical which turn out to be practical in Haskell, it is the unit if Applicative is viewed as a Monoid in the category of natural transformations, with (Notions of Computation as Monoids) with Day

type Mempty :: Type -> Type
type Mempty = Identity

type Mappend :: (Type -> Type) -> (Type -> Type) -> (Type -> Type)
type Mappend = Day

mempty :: Applicative f => Mempty ~> f
mempty (Identity a) = pure a

mappend :: Mappend f f ~> f
mappend (LiftA2 (·) as bs) = liftA2 (·) as bs

I just released a library that works with Applicative homomorphisms, that are polymorphic functions that respect the applicative structure. It defines a type class for such structures

type  Idiom :: k -> (Type -> Type) -> (Type -> Type) -> Constraint
class (Applicative f, Applicative g) => Idiom tag f g where
  idiom :: f ~> g

where pure is the initial applicative morphism.

-- https://chrisdone.com/posts/haskell-constraint-trick/
instance (Identity ~ id, Applicative f) => Idiom Initial id f where
  idiom :: Identity ~> f
  idiom (Identity a) = pure a

pure is then frequently used, as a unit for a computation. It is the driving force in Traversable one of the success stories of Haskell

instance Traversable [] where
  traverse :: Applicative f => (a -> f b) -> ([a] -> f [b])
  traverse f []     = pure []
  traverse f (x:xs) = ...

we require pure because our only argument that produces an Applicative-action is f x but with an empty list we don't have an x :: a to feed it. Thus, we need 0-ary lifting.

柠栀 2025-01-29 02:10:52

您可以定义pure :: a - &gt; f alift ::(a - &gt; b)的方面 - &gt; f(a - &gt; b)&lt;*&gt;

pure x = lift (const x) <*> lift (const ())

因此,无论哪种方式,它都是等效的,通常更简单地编写pure

(这是Iceland_jack的设计原因的出色总结,这是应该这样的。)

You can define pure :: a -> f a in terms of lift :: (a -> b) -> f (a -> b) and <*>:

pure x = lift (const x) <*> lift (const ())

So it's equivalent either way, and usually simpler to write pure.

(This is in addition to Iceland_jack's excellent summary of the design reasons it should be this way.)

眼眸 2025-01-29 02:10:52

有时候,值得从相反方向探讨问题。如果的类型是(a - &gt; b) - &gt; f(a - &gt; b)

正如某人打电话一样,严格来说,这是一个降级。如前所述,(a - &gt; b) - &gt; F(a - &gt; b)已经是当前类型的pure的实例化。因此,在呼叫方面,您只会失去选项。

但是,实现方是这里的双重。 A类型的具体类型越多,实现的选项越多。要求参数成为函数意味着实现可以利用它来执行特定功能的事情。喜欢...叫它。这是您在Haskell中唯一要做的特殊事情。因此,要调用它,您只需要为其提供某种类型a的值,pure可以选择的呼叫者。您可以得到其中之一..呃..您无法得到其中之一。唯一的选项是使用undefined或具有普遍定量类型的其他底部值。你会怎样做? 纯F = Let X = F在...中的UNDEFINE?这有助于实施纯净?

要返回初始问题,然后:如果pure的类型是(a - &gt; b) - &gt; f(a - &gt; b)?作为呼叫者,严格来说,它有用。作为实施者,它提供了额外的功能,但是额外的功能并不能帮助您做任何有用的事情。更具体的类型的Upsides在哪里?

Sometimes it's worth approaching questions from the opposite direction. What would you gain if the type of pure was (a -> b) -> f (a -> b)?

As someone calling pure, that's strictly a downgrade. As mentioned, (a -> b) -> f (a -> b) is an instantiation of the current type of pure already. So on the calling side, you only lose options.

The implementation side is the dual here, though. The more concrete a type is, the more options an implementation has. Requiring the argument to be a function means the implementation can take advantage of that to do function-specific things. Like... calling it. That's the only special thing you get to do with functions in Haskell. So to call it, you just need to provide it with a value of some type a that the caller of pure gets to choose. You can get one of those by.. uh.. you can't get one of those. The only option is using undefined or some other bottom value that has a universally-quantified type. What are you going to do? pure f = let x = f undefined in ...? How can that be helpful for implementing pure?

To return to the initial question, then: what would you gain if the type of pure was (a -> b) -> f (a -> b)? As a caller, it's strictly less useful. As an implementer, it provides additional power, but that additional power doesn't help you do anything useful. Where are the upsides to a more concrete type?

梦幻之岛 2025-01-29 02:10:52

是的,的目的比转换功能更多。 do块以pure结尾是非常常见的。通过将其用途与&lt; |&gt;相结合,也很方便地提供后备值。

此外,它与基本类别理论很好地融合;但是我真的不认为这是一个激励人心的原因。相反,它首先是有用的,然后发现与以前知名的类别理论概念相吻合。 (实际上,从历史上看,我认为它“定义了一些有用的东西”;意识到这是monad的概念;发现应用函数的相关概念;意识到它们有用。因此,实际上是“有用的第一”和“理论的混合” “但是我永远不会捍卫它的存在,因为它在理论上就是在那里 - 只对理论有见地感到兴奋。)

Yes, there is more purpose for pure than transforming functions. It is very common for do blocks to end with a call to pure. It's also handy for giving fallback values by combining its use with <|>.

Also, it meshes well with the underlying category theory; but I don't really consider that a motivating reason. Rather it's first useful and then discovered to coincide with a previously-known category theory concept. (Actually, historically I think it went "define something useful; realize it's the concept of monad; discover the related concept of applicative functors; realize they're useful. So it is in fact a mix of "useful first" and "theory first". But I would never defend its existence because it's there in theory -- only get excited that the theory was insightful.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文