2013-04-06 19 views
5

私はHList実装を行っていますが、私はmap関数を実装しようとしています。私はさまざまなアプローチを試してきましたが、それぞれについて、その関数に関連するコンパイラエラーが発生します。ジェネリック関数を使用した異種データ構造のマッピング

以下は、入力データ構造のすべての要素に汎用関数Justを適用する方法の例です。

No instance for (Apply (a0 -> Maybe a0) Int (Maybe Int)) 
    arising from a use of `hMap' 
The type variable `a0' is ambiguous 

これを解決するためにすべての方法でありますし、そうでない場合は、なぜ:これで

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FlexibleInstances #-} 

-- | An input heterogenous data structure 
recursivePairs :: (Int, (Char, (Bool,()))) 
recursivePairs = (1, ('a', (True,()))) 

-- | This is how I want to use it 
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool,()))) 
recursivePairs' = hMap Just recursivePairs 

class HMap f input output where 
    hMap :: f -> input -> output 

-- | A counterpart of a Nil pattern match for a list 
instance HMap f()() where 
    hMap _ _ =() 

-- | A counterpart of a Cons pattern match for a list 
instance 
    (HMap f iTail oTail, 
    Apply f iHead oHead) => 
    HMap f (iHead, iTail) (oHead, oTail) 
    where 
    hMap f (head, tail) = (apply f head, hMap f tail) 

class Apply f input output where 
    apply :: f -> input -> output 

instance Apply (input -> output) input output where 
    apply = id 

私は、次のコンパイラエラーを取得していますか?

+0

私はこの問題は、型システムがhMap' 'のあなたの定義は同じ' F'を再利用し続けるので、あなたが連続する各アプリケーションの異なる具体的なタイプで 'Just'をインスタンス化していることを認識しないということだと思います。あなたが最初にそれを適用するとき、型は 'Int - > Maybe Int'です。それを2回目に適用すると、型は' Char - > Maybe Char'になります。しかし、私はそれを修正する方法はまだかなり分かりません。 –

+0

@GabrielGonzalez はい、それはまさに問題です。そして、もしあなたが ''入力出力 - > f'を 'Apply'クラスに渡すと、エラーメッセージは'(Bool - > Maybe Bool)Char(Maybe Char) 'のようなインスタンスを探していると言います。私は['cast'](http://hackage.haskell。タイプレベルで 'f'の2つの使用法を切り離すために、しかし非常に自然な感じではない、 「Typeable」にもよるが、それほど魅力的ではなかった。 –

答えて

5

異なる引数を持つ多相関数を使用しようとしていますが、Applyインスタンスが関数(モノタイプ)を使用するという問題があります。あなたが簡単にあなたのコードで

data JustIfy = JustIfy 
instance Apply JustIfy a (Maybe a) where 
    apply _ = Just 

recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool,()))) 
recursivePairs' = hMap JustIfy recursivePairs 

作品だけで結構

EDITこの複数の方法を修正することができます。同じことのためのより一般的なアプローチは、

--A "universal" action that works on all types 
newtype Univ f = Univ (forall x. x -> f x) 
instance Apply (Univ f) x (f x) where 
    apply (Univ f) x = f x 

recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool,()))) 
recursivePairs' = hMap (Univ Just) recursivePairs 

またはあなたがいる場合を(RankNTypesを必要とする)されますGHCの最近のバージョンを使用しており、さらに拡張機能を有効にする予定です。

newtype Univ' c f = Univ' (forall x. c x => x -> f x) 
instance c x => Apply (Univ' c f) x (f x) where 
    apply (Univ' f) x = f x 

class All x 
instance All x 

recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool,()))) 
recursivePairs' = hMap (Univ' Just :: Univ' All Maybe) recursivePairs 

これはそれ以来素晴らしいですが、マップする関数に "show"を含めるようなことをさせることができます。

より一般的な解決策は、Oleg's Type level lambda caclulusをチェックして、値レベルでコードを記述してから、適切なタイプレベルのプログラムを自動的に推論させることです。残念なことに、オレグの解決策はこの時点ではかなり古く、特に好きではないLCの名目上の実装を使用しています。私はよりうまくやる方法を考えていましたが、家族をタイプするために妥当な平等が得られるまで待つことをお勧めします。

私の見解では、最近ではタプルではなくGADTとDataKindを使用してHLISTを作成する必要があります。型の族は機能的な依存よりも好ましいが、決定的な平等がないため、現在のところより限定されている。

+0

ありがとうございます。あなたはこれを解決する複数の方法があると言います - これについてもっと詳しく教えてください。私は最適なソリューションを探しているので、提供されたコードに固執する必要はありません。これは単なる抽象的な例です。 'hMap'で使用したい各関数の特定のインスタンスを宣言しなくても、これを解決する方法はありますか? –

+0

@NikitaVolkov私はより一般的なソリューションを追加しました –

1

次は正確に質問に答える(ので、私はそれを受け入れることはありません)、それは応用的ファンクタのための任意の追加のインスタンスを必要とせずに構造をマッピングに関する問題を解決していませんが:

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FlexibleInstances #-} 

import Control.Applicative 

main = do 
    print $ (hPure recursivePairs :: (Maybe Int, (Maybe Char, (Maybe Bool,())))) 
    print $ (hPure recursivePairs :: ([Int], ([Char], ([Bool],())))) 

recursivePairs :: (Int, (Char, (Bool,()))) 
recursivePairs = (1, ('a', (True,()))) 

class HPure input output where 
    hPure :: input -> output 

instance HPure()() where 
    hPure _ =() 

instance 
    (Applicative f, 
    HPure iTail oTail) => 
    HPure (iHead, iTail) (f iHead, oTail) 
    where hPure (iHead, iTail) = (pure iHead, hPure iTail) 

出力を:

(Just 1,(Just 'a',(Just True,()))) 
([1],("a",([True],()))) 
関連する問題