2011-01-27 5 views
19

がどのように私はnewtypeに頼らず(a, a)Functorを作ることができる(a)のファンクタ?メイキング

基本的に私はそれがこのように仕事をしたい:

instance Functor (a, a) where 
    fmap f (x, y) = (f x, f y) 

しかし、もちろん、それを表現するための法的な方法ではないこと:

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)(無効な構文)です。だからタイプエイリアス、おそらく?

type V2 a = (a, a) 
instance Functor V2 where 
    fmap f (x, y) = (f x, f y) 

私はこれがうまくいくと思いますが、そうではありません。まず私は、この苦情を取得:

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拡張子を追加する場合、私は新しいエラーを取得する:

まあ
Type synonym `V2' should have 1 argument, but has been given 0 
In the instance declaration for `Functor V2' 

、当たり前、それがポイントです! V2Functorインスタンスに必要な種類の* -> *を持っています。だけの種類のポイントを破る簡単なタプル、対処することができるというのではなく、私のコード全体V2の自由を振りかけるする

newtype V2 a = V2 (a, a) 
instance Functor V2 where 
    fmap f (V2 (x, y)) = V2 (f x, f y) 

しかし、今、私が持っている:まあ、[OK]を、私はこのようなnewtypeを使用することができますそれをFunctorにすること。その時点で私は自分自身の機能を作るかもしれませんvmap :: (a -> b) -> (a, a) -> (b, b)

のでnewtypeせず、すなわち、うまくこれを行う方法はありますか?

+0

タプルをこのようなFunctorにしたいですか?特別ケースのタプルで操作するためにuber-Functorの権限が必要な場合は、最初にタプルではなくカスタムデータ構造を使用しているはずです。あなたが操作しているタプルは何を表していますか? –

+4

@ダン私は「ユーバー・ファンクタの力」を必要としません。それはちょっと便利だったでしょうし、そうでなければならないと思っていました。 –

+0

@pelotom私は可能であるように思えますが、そうではないようです。私はちょうど私の石鹸ボックスに乗って、タプルのオーバーロードではなく、あなたの問題に合った表現力豊かな構造を作ることを説くために少し時間がかかると思った。 –

答えて

15

他の人が述べたように、newtypesもしくはデータの宣言に頼ることなくこれを行う方法はありません。しかし、あなたはControl.Arrowを見ましたか?これらの機能の多くは、たとえば、タプルと非常に便利です:singletons

vmap :: (a -> b) -> (a,a) -> (b,b) 
vmap f = f *** f 
+0

良いアイデア、ありがとう! –

+1

より良いのは 'vmap = join(***)'です – alternative

4

あなたはペアの最初の要素を制約しない、とfmapのみ第二の要素に作用するだろうしかし

instance Functor ((,) a) where 
    ... 

を宣言することができます。

問題は、タプルは、2つの要素の型との間の関係を強制しないことです。

あなたがあなた自身の新鮮なタイプを作ることができますnewtypeデコレータたくない場合は、次の

data Pair a = P a a 

instance Functor Pair where 
    ... 

タプル周りnewtypeよりで動作するように容易になります。

+1

タプルの要素の1つにしか作用しないファンクタを望んでいません。第1要素と第2要素の両方に作用する '(a、a)'のファンクタが必要です。私は新しいデータ型を作成しないようにしようとしています。 –

+1

@pelotom、不可能です。 Functorはデータコンストラクタの引数 '* - > *'をとり、 '(a、a)'はそれらのどれでもありません。 'newtype'や' data'を使う必要があります。 – luqui

+0

@luqui型コンストラクタが必要だと思っていますか?それは私が恐れていたことです...しかし、タイプエイリアスがうまくいかない理由はありません。 –

0

あなたが脱官能シンボルのFunctor型クラスを定義することができます(Type ~> Type代わりのType -> Type

{-# 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を与えますインスタンスが自動的に

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) 
関連する問題