2013-11-20 16 views
11

私はControl.Lensで作業しています。私が書いている実際の機能はかなり複雑ですが、この質問の目的のために、私は、最小限の失敗例にそれを煮詰めてきました:Control.Lensの "不正な多型または修飾型"

import Control.Lens  

exampleFunc :: Lens s t a b -> String 
exampleFunc _ = "Example" 

これはコンパイルに失敗し、次のエラーメッセージが生じる:

Illegal polymorphic or qualified type: Lens s t a b 
Perhaps you intended to use -XRankNTypes or -XRank2Types 
In the type signature for `exampleFunc': 
    exampleFunc :: Lens s t a b -> String 

なぜこれは違法ですか?

import Data.Maybe 

exampleFunc' :: Maybe (s, t, a, b) -> String 
exampleFunc' _ = "Example" 

だから私は違いを想定していLensの定義である:それはコンパイルが行う以下にひどく似ているようです。しかし、Lensタイプの場合、exampleFuncのタイプは違法ですか?私はLensの定義でFunctorの資格と関係があると疑っているが、間違っている可能性がある。参考のため、Lensdefinitionは次のとおりです。

type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t 

だから、私は何とかexampleFuncの私の定義でFunctor資格を満たさなければならないのですか?もしそうなら、どうですか?私は自分の型署名のどこにこの制約を宣言する機会があるのか​​分かりません。または、私は間違ったトラックにいるかもしれません。問題はFunctorという制約とは関係ありません。

「違法ポリモーフィック」エラーメッセージに関するすべてのスタックオーバーフローに関する質問を読んだことがあります。おそらく、これはHaskellの見解に精通していないことですが、現在の状況に該当する質問は表示されません。

エラーメッセージの意味に関する一般的なドキュメントを見つけることはできませんでした。

+0

「RankNTypes」は、コンパイラが示唆しているように安全にスイッチを入れることができる拡張機能の1つです。おそらく 'OverlappingInstances'と' IncoherentInstances'ではそうではありませんが、これは他の多くの拡張もOKです。 – leftaroundabout

答えて

9

レンズは、ランク2種類を使用し、あなたはどのませんか?

(forall a. foo) -> bar 

のようにも全く何かにそれを法的にする必要があり、このように、レンズの種類のいずれかを使用するので、矢印の左側にそれを持っています

{-# LANGUAGE RankNTypes #-} -- Rank2Types is a synonym for RankNTypes 

をファイルの先頭に付けます。それがなければ、レンズタイプシノニムを使用することは、あなたが使用可能にしなければならない言語の一部を使用するので、違法です。

+0

負の位置の意味ではありません。たとえば、 '(a - > r) - > r 'の場合、' a'は正の位置に現れます。 –

+0

@BenMillwoodこれは単純化されたバージョンです。そして、負と正の位置は、負の位置の負の位置が正の位置であるという点で、乗算のように動作します。しかしこの事例では、簡略化された説明が十分であると感じました。 – jozefg

7

タイプシノニムが多態型であり、「負の位置」と呼ばれる、つまり->の左側にあるシグネチャで発生するため、コンパイルが失敗します。

RankNTypesをオンにしなくても、タイプシグネチャにLensを使用できます。

import Control.Lens 

lensy :: Lens' (a,b) a 
lensy = _1 

をしかし、これはです。TypeCheckに失敗した:これはtypechecks

oops :: Lens' (a,b) a -> Int 
oops = const 5 

なぜ?これはまた、RankNTypesなしです。TypeCheckに失敗した同じ理由:

{-# LANGUAGE ExplicitForAll #-} 

fails :: (forall a. a -> Int) -> Int 
fails = undefined 

ここforallは負の位置にあり、かつ唯一のa -> Int上の範囲です。 の実装failsであり、の発信者failsではなく、aのタイプを選択した人です。呼び出し元はすべてaで動作する引数関数を指定する必要があります。この機能requires the RankNTypes extension

forallが署名全体に渡っている場合(Lensが孤立して定義されている場合など)、RankNTypesは必要ありません。

{-# LANGUAGE ExplicitForAll #-} 

typechecks :: forall a. (a -> Int) -> Int 
typechecks = undefined 

しかし、ここで、それはaの種類を選択します、発信者であるため、この機能は、以前のものと異なっている:これはtypechecks。彼は特定のaのためだけに機能する引数関数を渡すことができます。

exampleFunc'は、forallが指定されていないと、シグネチャ全体にわたる各変数の暗黙のforallsが存在するために機能しました。

This explanationからのHaskellメーリングリストが役に立つかもしれません。

関連する問題