2017-07-16 18 views
8

コードAllowAmbiguousTypesとは何ですか?なぜこの "forall"の例ではなぜ必要ですか?

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-} 

-- I know this particular example is silly. 
-- But that's not the point here. 
g :: forall a . RealFloat a => Bool 
g = True 

main :: IO() 
main = print (g @Double) 

だからAllowAmbiguousTypesを追加すると、コードのコンパイルを行いますエラー

• Could not deduce (RealFloat a0) 
     from the context: RealFloat a 
     bound by the type signature for: 
        g :: RealFloat a => Bool 
     at app/Main.hs:3:6-35 
     The type variable ‘a0’ is ambiguous 
    • In the ambiguity check for ‘g’ 
     To defer the ambiguity check to use sites, enable AllowAmbiguousTypes 
     In the type signature: 
     g :: forall a. RealFloat a => Bool 

でGHC 8.0でコンパイルに失敗します。ここで

私の質問は以下のとおりです。

  • 正確AllowAmbiguousTypesは何?
  • この特定のコードを動作させる必要があるのはなぜですか?
  • 私はAllowAmbiguousTypesを追加すると、私が本当にこの特定のコードに必要以上のことを与えていることを恐れています。それは恐ろしいように聞こえる。これは、Haskellの型システムの安全性を損なう可能性があります。おそらく、この特定のコードとは関係のない他の領域ではおそらく安全です。これらの恐怖は根拠がありませんか?
  • 代替手段はありますか?この場合、Haskellは私が決して聞いたことのない型変数a0を挿入しているようです。これらの無関係な型変数を作成しないようにHaskellに指示する拡張子はありません - 明示的に私自身が明示的に指定したものだけを使用して、自分の明示的なforall aで追加しますか?
  • user2407038さんのコメントのために1つの質問が追加されました:あなたはそのAllowAmbiguousTypesは名前の誤りですか? AllowUnusedTypeVariablesという名前の方がいいでしょうか?
+7

あいまいな型は、その型の変数(型の '=>')の本文には言及されていない型変数を持つ型です。 'RealFloat a => ..'は' ..'が 'a'を言及していないときはあいまいです。あいまいな型は一般的にプログラマーのエラーであり、TypeApplicationsの前ではまったく役に立たなかったので、それらを許可する拡張が必要です。最後の2つの質問のために、それはどのようにしても型チェックを「安全でない」ものにしません。 'RealFloat a => Proxy a - > Bool'と書くこともできます。ここで[Proxy](https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Proxy.html)は次のようになります。ここに。 – user2407038

+3

代わりに 'RealFloat a => Tagged a Bool'を使うことができます。ここで、' Tagged'は 'tagged'パッケージから来ており、場合によってはプロキシの方法よりも効率的です。 – dfeuer

+3

'AllowAmbiguousTypes'は私の目では無害です。多くのラムダ計算では、型は常に明示的に渡されます(例えば 'map @ a @b f xs')。普通のハスケルでは、タイプが推論されています。つまり、それらを渡す必要はありません(良い)ことを意味し、必要であってもそれらを渡すことはできません。そのため、引数の型や戻り値から推測できないタイヴァー型の型は禁止する必要があります。それゆえ、私たちはそれらを推測不能にするためだけにプロキシ/タグ付けを使用しなければなりません。しかし、現在、GHCは明示的な型のアプリケーションを許可しているので、もはやそれを行う必要はありません。 – chi

答えて

9

正確にはAllowAmbiguousTypesとは何ですか? latest GHC docsから

は、「のみ((undefined :: ty) :: ty)場合です。TypeCheckに失敗するならばタイプtyがあいまいです」。拡張子AllowAmbiguousTypesは、このチェックを無効にするだけです。これにより、間違って入力されたプログラムは許可されません。

この特定のコードを動作させる必要があるのはなぜですか?

gが使用されるたびにRealFloat aが満たされていることを確認するために、GHCはaが何であるかを知る必要があります。 agのタイプではどこでも発生しないので、あなたはGHCに何を伝えるべきか(vanilla Haskell )の方法はありません。アノテーションの量がないと、曖昧な型の変数エラーが発生することなくgを使用できます。

どこでもgを使用していない場合は、AllowAmbiguousTypesをオンにしてコードをコンパイルすることができます。

AllowAmbiguousTypesを追加すると、この特定のコードで本当に欲しいものよりも多くのことがわかります。それは恐ろしいように聞こえる。これは、Haskellの型システムの安全性を損なう可能性があります。おそらく、この特定のコードとは関係のない他の領域ではおそらく安全です。これらの恐怖は根拠がありませんか?

はい、彼らは以下のとおりです。あいまいさのチェックは、あなたが(TypeApplications を持っていないバニラハスケルに)あいまいな型の変数の誤差を生じることなく使用することができません定義をキャッチすることができます。このチェックを無効にすると、その定義サイトではなく式(または関数)を使用するときに、あいまいなタイプの変数メッセージが表示されます。

代替手段はありますか?この場合、Haskellは私が決して聞いたことのない型変数a0を挿入しているようです。これらの無関係な型変数を作成しないようにHaskellに指示する拡張子はありません - 明示的に私自身が明示的に指定したものだけを使用して、自分の明示的なforall aで追加しますか?

a0は、私がこの回答の冒頭で言及したあいまいチェックから来ています。 GHCはaとは異なることを明確にするために名前a0を使用しています。あいまいさチェックは、基本的に型チェックを試みるだけです。

((undefined :: forall a. RealFloat a => Bool) :: forall a0. RealFloat a0 => Bool) 

AllowAmbiguousTypesはこのチェックを削除します。私は、明示的なforallでタイプシグネチャのみのあいまい性チェックを無効にする拡張機能はないと思いますが(これはきちんと役に立つかもしれませんが)!

AllowAmbiguousTypesは名前の間違いですか? AllowUnusedTypeVariablesという名前の方がいいでしょうか?

名前を付けるのは難しいです。 :)

現在の名前は拡張機能を有効にせずに取得するエラーのタイプを参照するため、悪い名前ではありません。私はこれが意見の問題だと思う。 (多くの人がまたMonadFlatMapAbleのようなものと呼ばれていた希望。)前TypeApplications


(GHC 8.0から比較的新しい拡張である)、実際にトリガー式を使用する方法はありませんでしたあいまいな型の変数エラーを取得せずにあいまい性チェックを行ったので、AllowAmbiguousTypesはずっと役に立たなかった。

+0

'aは型の型だけでなく、体内にも存在しないg'型のどこにも存在しないからです。関数本体に 'a'変数を使用すると、' -XAllowAmbiguousTypes'は必要ありません。 – Shersh

+0

@Shershあなたは何を覚えていますか?関数の本体で(おそらく 'ScopedTypeVariables'を有効にして)型変数を使用すると、' a'がコールサイトにあるべきであると解決するために型チェッカーに渡されません... – Alec

+0

申し訳ありません。どういうわけか私は間違っています。昨年のghc 8.0.1でこのスライドのコードをテストしたところ、うまくいきました。しかし、今は '-XAllowAmbiguousTypes'がなければ動作しません:http://slides.com/fp-ctd/lecture-15#/17 :( – Shersh

関連する問題