ghc 8で従属型を使用していますが、私の型のShowインスタンスを作成する際に問題が発生しています。従属型のインスタンスを表示する
#!/usr/bin/env stack
-- stack exec --resolver=lts-7.14 --package singletons -- ghci
{-# LANGUAGE GADTs, ScopedTypeVariables, TypeInType, TemplateHaskell, LambdaCase, TypeApplications #-}
import Data.Kind
import Data.Singletons.Prelude
import Data.Singletons.TypeLits
data EmailAddress :: Symbol -> Symbol -> * where
EmailAddress :: (KnownSymbol a, KnownSymbol b) => EmailAddress a b
-- works
testEmail :: EmailAddress "blah" "blah.com"
testEmail = EmailAddress
私は自分のアドレスを表示したいと思っていました。
instance Show (EmailAddress a b)
where show = showEmailAddress
showEmailAddress :: forall a b. EmailAddress a b -> String
showEmailAddress = \case
EmailAddress -> symbolVal (Proxy :: Proxy a) ++ "@" ++ symbolVal (Proxy :: Proxy b)
test1 = show testEmail -- works
ランタイムEmailAddress
をユーザー提供の文字列から作成します。まず、シングルトンからアドレスを取得します。ちょうど今のところ1本の弦を取る
fromString' :: Sing i -> EmailAddress i i
fromString' = \case
SSym -> EmailAddress
test2 = fromString' @"asdf" sing -- works
パズルの最後の部分は、次のようなことができるはずです。
fromString :: String -> EmailAddress a a
fromString str = case toSing str of
SomeSing s -> fromString' s
しかし、動作しません。関数のさまざまな部分にどのような型のシグネチャを適用しても、型チェックを行うことができません。次のコードでは、常に次のエラーが発生します。Couldn't match type ‘a’ with ‘a1’
エラー。
fromString1 :: String -> EmailAddress a a
fromString1 str = case toSing str of
SomeSing s -> fromString' s
fromString2 :: forall a. String -> EmailAddress a a
fromString2 str = case toSing str of
SomeSing (s :: Sing a) -> fromString' s
fromString3 :: forall a. String -> EmailAddress a a
fromString3 str = case toSing str of
(SomeSing s :: Sing (a :: Symbol)) -> fromString' s
これは完全なエラーです。私はa1
がどこから来ているのか分かりません。
Existentials5.hs:45:20: error:
• Couldn't match type ‘a’ with ‘a1’
‘a’ is a rigid type variable bound by
the type signature for:
fromString3 :: forall (a :: Symbol). String -> EmailAddress a a
at Existentials5.hs:43:16
‘a1’ is a rigid type variable bound by
a pattern with constructor:
SomeSing :: forall k k1 (k2 :: k1) (a :: k). Sing a -> SomeSing k,
in a case alternative
at Existentials5.hs:45:5
Expected type: EmailAddress a a
Actual type: EmailAddress a1 a1
• In the expression: fromString' s
In a case alternative: (SomeSing s) -> fromString' s
In the expression:
case toSing str of { (SomeSing s) -> fromString' s }
• Relevant bindings include
s :: Sing a1 (bound at Existentials5.hs:45:14)
fromString3 :: String -> EmailAddress a a
(bound at Existentials5.hs:44:1)
このチュートリアルは、私がこれをしようとしてくれたものです:https://blog.jle.im/entry/practical-dependent-types-in-haskell-2.html彼はそれを使用して実行時に型を生成します。しかし、それは 'SomeSing'部分の周りに私を失った。私はそれがどのように使用されることが意図されているのか直感を見つけることはできません。 –
直感は、GHCのシングルトンが複雑で不都合な近似であるため、理想的には依存型理論から来るべきです。しかし、初心者のマテリアルはあまりありません。 [こちら](https://www.manning.com/books/type-driven-development-with-idris)は良いようですが、無料ではありません。あなたは[これらの](http://people.inf.elte.hu/divip/AgdaTutorial/Index.html)[two](http://oxij.org/note/BrutalDepTypes/)Agdaチュートリアルを見ることができますが、プログラミングよりもフォーマル化に向いています。 –
また、[ソフトウェア基盤](https://www.cis.upenn.edu/~bcpierce/sf/current/index.html)も見ることができます。これは非常に徹底的で初心者向きですが、プルーフにも焦点を当てていますCoqはIdrisやAgdaよりもHaskellersにとってより疎外です。 –