2015-10-11 20 views
5
次のスニペットで

(私は他のすべての些細な部分を抽象化している)Haskell:同じ名前空間の "where"節に型変数がありますか?

data T s = T (s -> s) 

foo :: T s -> s -> s 
foo (T f) x = bar x where 
    bar :: s -> s 
    bar a = f a 

私は

Couldn't match expected type `s1' with actual type `s' 
    `s1' is a rigid type variable bound by 
     the type signature for bar :: s1 -> s1 at /tmp/test.hs:5:12 
    `s' is a rigid type variable bound by 
     the type signature for foo :: T s -> s -> s at /tmp/test.hs:3:8 
In the return type of a call of `f' 
In the expression: f a 
In an equation for `bar': bar a = f a 

エラーを以下しまった私の推測では、barの署名で型変数が共有していないということでしたfooという名前空間を使用しているため、コンパイラは2つの型が実際に同じ型を意味していると推測することはできません。

私はこのページScoped type variablesを見つけました。私は{-# LANGUAGE ScopedTypeVariables #-}を使うことができますが、それは役に立たなかったことを示唆しています。私は同じエラーがあります。

+3

wiki上の例として、 'ScopedTypeVariables'で実際に使用するには' foo'の型シグネチャに 'forall s'が必要です。 –

答えて

6

「where」節の型変数は、同じ名前空間内で親と一緒に指定されていますか?

いいえ*。 foo :: s -> sfoo :: forall s. s -> sの形で考えると、これは少し簡単になります。結局のところ、型変数は、関数が任意の型のsで機能することを示します。さんがあなたのコードに明示的な定量化を追加してみましょう:あなたが見ることができるように、そこに2 forall s.がある

{-# LANGUAGE ExplicitForAll #-} 

data T s = T (s -> s) 

foo :: forall s. T s -> s -> s 
foo (T f) x = bar x where 
    bar :: forall s. s -> s 
    bar a = f a 

。しかし、barのものは間違っています。結局、sを選択することはできませんが、すでにsで使用されています。これはScopedTypeVariablesを有効にすることによって行うことができます。

{-# LANGUAGE ScopedTypeVariables #-} 

data T s = T (s -> s) 

--  vvvvvvvv explicit here 
foo :: forall s. T s -> s -> s 
foo (T f) x = bar x where 
    --  vvvvvv same as above here 
    bar :: s -> s 
    bar a = f a 

しかし、ScopedTypeVariablesを取り除くためにいくつかのトリックがあります。例えば、この場合には、次のいずれかのx :: ss -> sを入力しており、asTypeOfが同じ型を有することの両方を強制idType x用語について

data T s = T (s -> s) 

foo :: T s -> s -> s 
foo (T f) x = (bar `asTypeOf` idType x) x where 

    bar a = f a 

    idType :: a -> a -> a 
    idType a _ = a 

-- For completion, definition and type of 'asTypeOf' 
-- asTypeOf :: a -> a -> a 
-- asTypeOf x _ = x 

実際のコードによっては、このようなものが多かれ少なかれ実現可能性があります。


*それはScopedTypeVariablesを使用することが可能ですので、まあ、この場合には、答えの後の部分を参照してください。

+0

'' bar 'typeOf'' typeOf''を使っている間、私は上記の明示的な' idType'定義をはるかに読みやすくしています。おそらく、 'idType _a = a'、または' idType = undefined'として定義したでしょうが、実際の定義はすべて重要ではありません。 – chi

+0

私は 'idType = undefined'について考えましたが、型を使用していても、この場合には部分的な機能に慣れていません。しかし、はい、 'idType = asTypeOf'。 – Zeta

5

ScopedTypeVariablesは確かに解決策ですが、それらを使用するための追加要件があります:あなたは、このようなスコープにしたい変数を、宣言型シグネチャに明示的なforall Sを置く必要があります。

foo :: forall s. T s -> s -> s 

これがそうですコード内のシグネチャの意味は、拡張機能が有効かどうかによって異なります。

関連する問題