3

コンストラクターでシンボルを使用して新しい型を作成し、IncoherentInstances をオンにすると、コンパイル時にシンボルが入力された場合にのみ、型の正しいインスタンスが選択されます....

{-# LANGUAGE DataKinds, GADTs, KindSignatures, FlexibleInstances, IncoherentInstances #-}

import GHC.TypeLits

data Object:: Symbol -> * where
    Object :: Object sy

instance Show (Object "dog") where
    show _ = "dog"

instance Show (Object x) where
    show _ = "other"

main = do
    let name = "dog"
    print (undefined :: Object "dog") -- outputs "dog", as expected
    print (undefined :: Object "cat") -- outputs "other", as expected
    print (undefined :: Object name) -- outputs "other", I expected "dog"

実行時に文字列 Symbol 値を提供する方法はありますか? これが許可されていない場合、なぜそれはコンパイルされますか (つまり、デフォルトのケース以外に解決されない場合、3 番目の印刷で割り当てを使用したいのはいつですか?)

4

1 に答える 1

4

Haskell [GHC] には、用語と型 [および種類] という 2 つ [3] の完全に独立した名前空間があります。これが、この種のものが常に表示される理由です。

data Foo a = Foo a | Bar Int

(とりわけ)2つの別々の名前を宣言しますFoo。1 つは型コンストラクターである型レベルの名前で、もう 1 つはデータ コンストラクターでFooある用語レベルの名前です。Foo同様に、

foo :: a -> a
foo a = a

2 つの別個の名前がありますa。1 つは型変数である型レベルの名前aで、もう 1 つは項変数である項レベルの名前aです。

2 つのレベル間の唯一の相互作用は、タイピングの判断です。あるレベルの名前は、上のレベルで既知の分類を持つ場合があります。たとえばJust、用語レベルの名前はa -> Maybe a、タイプ レベルのタイプによって分類されます。ただし、ここでも名前は相互作用しません。用語レベルの名前と型レベルの名前を結び付けたい場合は、非常に風変わりなトリックを行う必要があります。

したがって、書くときはlet name = "dog" in undefined :: Object name、次のように読む必要がありますlet TermLevel.name = "dog" in undefined :: Object TypeLevel.name。が役に立たないことは明らかであり、let単にundefined :: forall name. Object name. このタイプに一致する多くのインスタンスがあり、そのような状況でどのインスタンスを選択してもかまわないと GHC に伝えたので、GHC は先に進み、1 つを選択しました。それはあなたが望んでいたものではありませんでしたが、それは一貫性のないインスタンスで支払う代償です.

于 2013-11-13T19:23:10.817 に答える