首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使(a,a)成为函数式

使(a,a)成为函数式
EN

Stack Overflow用户
提问于 2011-01-27 12:06:58
回答 3查看 3.5K关注 0票数 19

如何在不求助于newtype的情况下使(a, a)成为Functor

基本上,我希望它是这样工作的:

代码语言:javascript
复制
instance Functor (a, a) where
  fmap f (x, y) = (f x, f y)

但当然,这不是一种合法的表达方式:

代码语言:javascript
复制
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `(a, a)' has kind `*'
In the instance declaration for `Functor (a, a)'

我真正想要的是一个像这样的类型级函数:\a -> (a, a) (无效语法)。那么,也许是一个类型别名?

代码语言:javascript
复制
type V2 a = (a, a)
instance Functor V2 where
    fmap f (x, y) = (f x, f y)

我本以为这能行得通,但事实并非如此。首先,我收到这样的抱怨:

代码语言:javascript
复制
Illegal instance declaration for `Functor V2'
(All instance types must be of the form (T t1 ... tn)
 where T is not a synonym.
 Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Functor V2'

如果我按照建议添加了TypeSynonymInstances扩展,我会得到一个新的错误:

代码语言:javascript
复制
Type synonym `V2' should have 1 argument, but has been given 0
In the instance declaration for `Functor V2'

好了,对了,这就是问题所在!V2拥有一个Functor实例所需要的友好的* -> *。好吧,好吧,我可以使用这样的newtype

代码语言:javascript
复制
newtype V2 a = V2 (a, a)
instance Functor V2 where
  fmap f (V2 (x, y)) = V2 (f x, f y)

但现在,我必须在代码中自由地使用V2,而不是仅仅处理简单的元组,这有点违背了将其变成Functor的意义;在这一点上,我不妨将自己的函数设为vmap :: (a -> b) -> (a, a) -> (b, b)

那么,有没有什么方法可以很好地做到这一点,也就是不使用newtype

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-01-27 13:46:35

正如其他人所说,如果不求助于新类型或数据声明,就无法做到这一点。但是,你有没有看过Control.Arrow?其中许多函数对元组非常有用,例如:

代码语言:javascript
复制
vmap :: (a -> b) -> (a,a) -> (b,b)
vmap f = f *** f
票数 16
EN

Stack Overflow用户

发布于 2011-01-27 12:13:58

你可以声明

代码语言:javascript
复制
instance Functor ((,) a) where
  ...

然而,这并不限制您的元素对中的第一个元素,并且fmap只会作用于第二个元素。

问题是元组并不强制两个元素的类型之间的关系。

如果你不需要newtype装饰器,你可以自己做一个新的类型:

代码语言:javascript
复制
data Pair a = P a a

instance Functor Pair where
  ...

它将比元组周围的newtype更容易使用。

票数 4
EN

Stack Overflow用户

发布于 2017-12-08 20:12:14

使用singletons,您可以为废弃的符号定义Functor类型类(Type ~> Type而不是Type -> Type)

代码语言:javascript
复制
{-# Language ExplicitNamespaces, TypeApplications, TypeOperators, KindSignatures, ScopedTypeVariables, DataKinds, TypeInType, TypeFamilies, AllowAmbiguousTypes, InstanceSigs #-}

import Data.Kind (Type)
import Data.Singletons (type (~>), Apply)

class Functor' (f :: Type ~> Type) where
  fmap' :: (a -> a') -> (Apply f a -> Apply f a')

data Dup :: Type ~> Type

type instance Dup `Apply` a = (a, a)

instance Functor' Dup where
  fmap' :: (a -> a') -> ((a, a) -> (a', a'))
  fmap' f (a1, a2) = (f a1, f a2)

这将自动提供一个Prelude.Functor实例

代码语言:javascript
复制
newtype f $ a = App (Apply f a)

instance Functor' f => Functor (($) f) where
  fmap :: (a -> a') -> (f $ a -> f $ a')
  fmap f (App fa) = App (fmap' @f f fa) 
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4812633

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档