4

型推論アルゴリズムが埋める「空白」を含む Haskell 値に型署名を提供することは可能ですか?

コンテキストの非常に不自然な例:

m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

b = isJust m

これは機能します。isJust minの使用はbの型mを beMaybe <something>m制約し、 の定義は の型mを be<something> (Char, ((String, String), String, [String], String), String)に制約し、コンパイラはこれら 2 つの情報を組み合わせて の正確な型を計算しmます。

Maybeしかし、特定の関数を に適用していないmので、ポリモーフィックであることを止めるために手動の型シグネチャが必要になりますreturn。私はこれを言うことはできません:

m :: Maybe a
m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is")

それは間違っているからです。型はMaybe aすべてaではありません。コンパイラに推論さMaybe aaたいものもあります。コンパイラがこれを行うのに十分な情報がプログラムにあり、最初の例から、コンパイラ型に複数の制約をまとめることができることがわかります。一緒にそれらはタイプを完全に指定します。

私が望むのは、のような「これは厳密な型変数である」という意味ではなく、「ここに何が入るかを理解する」という意味m :: Maybe _のような型を与えることができるようにすることです。_m :: Maybe a

このようなことを言う方法はありますか?私が見ることができる代替手段は、明示的に完全な型を与えています:

m :: Maybe (Char, ((String, String), String, [String], String), String)
m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is")

または、式の一部に型シグネチャを与えると、型シグネチャの一部を制約する効果がありますが、次のようにMaybeはなりません。a

m = (return :: a -> Maybe a) ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is")

または、明示的な型署名なしで残しm、制約する未使用の追加の定義を導入しますm

m = return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is") 

b = isJust m

または、単相関数を直接使用します。

m = Just ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is")

明らかに、これは に固有のものでも、型コンストラクターMaybeの引数にも固有のものではありません。「この値はモナドのモナドです」と言いたいのではなく、「この値はモナドモナドです」、または「これは他の型への関数です」とは言わず* -> *に言いたいことが想像できます。関数から他型へ`.IntIntIntInt

私は主に、読みにくい回避策 ( return. 私の目標が単純に追加の型情報をコンパイラに取得して、あいまいな型変数についてそれを黙らせることである場合、それを行う方法は無数にあります。

4

4 に答える 4

5

次のように書くことができます。

asMaybe :: Maybe a -> Maybe a
asMaybe = id

m = asMaybe $ return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is")

私はclassy-preludeasByteStringで、asSetasList、 などを提供する際に、この種のトリックを使用します。

于 2012-12-07T07:28:59.307 に答える
3

GHC 7.10 では、PartialTypeSignatures拡張機能が追加されました。これにより、質問で書いた架空のアンダースコア構文が正確に有効になります。上記のリンクのドキュメント ページの例:

not' :: Bool -> _
not' x = not x
-- Inferred: Bool -> Bool

maybools :: _
maybools = Just [True]
-- Inferred: Maybe [Bool]

just1 :: _ Int
just1 = Just 1
-- Inferred: Maybe Int

filterInt :: _ -> _ -> [Int]
filterInt = filter -- has type forall a. (a -> Bool) -> [a] -> [a]
-- Inferred: (Int -> Bool) -> [Int] -> [Int]

拡張子だけPartialTypeSignaturesを使用すると、最終バージョンの前に入力する予定の単なるプレースホルダーである場合に備えて、コンパイラは推論された型で警告を発行します。フラグを追加-fno-warn-partial-type-signaturesすることで、署名を部分的に残すつもりだったことを伝えることができます。

于 2016-02-09T10:32:41.067 に答える
1

マイケル・スノイマンの提案から少し合成すると、次のようになります。

  1. 作成したい型アサーションごとに特定の関数を定義する必要はありませんでした
  2. 私がタイプアサーションを行っていたものに近いタイプを実際に書きたかった
  3. 型を 2 回記述する必要はありませんでした

私は次のようなことができます:

type Assert a = a -> a

m = (id :: Assert (Maybe a)) $ return ('I', (("don't", "really"), "care", ["what", "this"], "type"), "is")
于 2012-12-07T07:49:07.223 に答える