31

Existential型を使用する場合、foralled値を抽出するためにパターンマッチング構文を使用する必要があります。通常のレコードセレクターを関数として使用することはできません。GHCはエラーを報告し、次の定義でパターンマッチングを使用することを提案しますyALL

{-# LANGUAGE ExistentialQuantification #-}

data ALL = forall a. Show a => ALL { theA :: a }
-- data ok

xALL :: ALL -> String
xALL (ALL a) = show a
-- pattern matching ok

-- ABOVE: heaven
-- BELOW: hell

yALL :: ALL -> String
yALL all = show $ theA all
-- record selector failed

forall.hs:11:19:
    Cannot use record selector `theA' as a function due to escaped type variables
    Probable fix: use pattern-matching syntax instead
    In the second argument of `($)', namely `theA all'
    In the expression: show $ theA all
    In an equation for `yALL': yALL all = show $ theA all

私のデータのいくつかは5つ以上の要素を取ります。パターンマッチングを使用すると、コードを維持するのが難しくなります。

func1 (BigData _ _ _ _ elemx _ _) = func2 elemx

そのようなコードを保守可能にするか、ある種のセレクターを使用できるようにラップするための良い方法はありますか?

4

2 に答える 2

22

既存の型は、通常の型よりも複雑に機能します。GHCは、関数としての使用を(当然のことながら)禁止しtheAています。しかし、そのような禁止がなかったと想像してください。その関数にはどのようなタイプがありますか?次のようなものである必要があります。

-- Not a real type signature!
theA :: ALL -> t  -- for a fresh type t on each use of theA; t is an instance of Show

非常に大雑把に言えば、forallGHCはコンストラクターの引数の型を「忘れる」ようにします。型システムが知っているのは、この型がのインスタンスであるということだけですShow。したがって、コンストラクターの引数の値を抽出しようとすると、元の型を復元する方法はありません。

GHCが舞台裏で行うことは、上記の偽の型シグネチャへのコメントが言うことです。コンストラクターとパターンマッチするたびALLに、コンストラクターの値にバインドされた変数に、他のすべての型とは異なることが保証された一意の型が割り当てられます。 。たとえば、次のコードを見てください。

case ALL "foo" of
    ALL x -> show x

変数xは、プログラム内の他のすべての型とは異なり、どの型変数とも一致しない一意の型を取得します。theAこれらの一意の型をトップレベルにエスケープすることは許可されていません。これが、関数として使用できない理由です。

于 2012-04-17T17:42:33.530 に答える
18

パターン マッチングでレコード構文を使用できます。

func1 BigData{ someField = elemx } = func2 elemx

動作し、巨大な型の入力がはるかに少なくなります。

于 2012-04-17T14:10:09.860 に答える