2016-11-18 6 views
2

私はSQLインタープリタを書いています。私は、コンパイル時の不正な表現とランタイムエラーとを区別する必要があります。同じコンストラクタに対して異なる動作をすることは可能ですか?

整形式である必要がありますが、実行時に失敗する可能性がある例を示します。

SELECT $ [ColumnName "first_name" `AS` "name"] `FROM` TABLE "people.csv" `WHERE` (ColumnName "age" `Gte` LiteralInt 40) 

私は表現に注目したいと思います:

(ColumnName "age" `Gte` LiteralInt 40) 

これは、型チェッカーを渡す必要があります。しかし、「年齢」にはLiteralIntと表現できるものが含まれていないとします。

だから、私はGteのようなものをIO Boolのようなものにしたいと思うでしょう。

IO Boolを作成するのに、必ずしもGteが必要なわけではありません。イベントで私はこのようなものを持っていた:

(LiteralInt 40 `Gte` LiteralInt 10)私はちょうどブールが必要です。 など: (LiteralInt 40 `Gte` LiteralBool True)はコンパイル時に失敗する必要があります。

私はデータファミリやGADTを使いこなしてきましたが、私がそれらを解明すれば、状況を混乱させるだけの多くのデッドエンドが崩壊しました。

私の問題は理にかなっていますか?そうであれば私は解決策につながる探査の道を探っていますか?

+0

'IO Bool'の代わりに' Bool'を返す式をいくつか持つことで、実際に何を得ることができますか? – chepner

+1

型安全なSQLインターフェイス? [_The Power of Pi_](https://cs.ru.nl/~wouters/Publications/ThePowerOfPi.pdf)と[singletons'論文のハスケル翻訳(http://cs.brynmawr .edu /〜rae/papers/2012/singletons/paper.pdf)。大きなアイデアは、スキーマを先に宣言し、DB接続を開く際にスキーマと一致するかどうかをチェックすることです。 –

+0

ベンジャミンに感謝、私はウサギの穴を下って行く。 :) –

答えて

7

だから私はGteは(今のところ例外処理を気にしない)IO Boolのようなものを生産したいと思います。

IO Boolを作成するのに、必ずしもGteが必要なわけではありません。

これは不可能ではありません。 Gteは常に同じタイプを返す必要があります。また、クエリの作成を実行から切り離したいと思うかもしれません...

または何かのように:(LiteralInt 40 `Gte` LiteralBool True)はコンパイル時に失敗する必要があります。

ここでははるかに合理的です。あなたがその道を離れることに決めたら、新しいTypeError機能でGHCのタイプエラーをカスタマイズすることさえできます。その後

{-# LANGUAGE GADTs #-} 

data Expr a where 
    LiteralInt :: Int -> Expr Int 
    LiteralBool :: Bool -> Expr Bool 
    Gte :: Expr Int -> Expr Int -> Expr Bool 
    Add :: Expr Int -> Expr Int -> Expr Int 
    ColumnName :: String -> Expr a 

は、以下のすべてをコンパイルします::しばらく

ColumnName "age" `Gte` LiteralInt 40 
LiteralInt 40 `Gte` LiteralInt 10 
(LiteralInt 40 `Add` ColumnName "age") `Gte` LiteralInt 10 

しかし、ちょうどLiteralIntLiteralBoolGteを含む単純な例にこだわり、あなただけGADTsで、次のような何かを行うことができではないでしょう以下:

LiteralInt 40 `Gte` LiteralBool True 
LiteralInt 40 `Add` LiteralBool True 

をしかし、 "言います年齢 "にはLiteralIntと表現できるものは含まれていませんでした。

あなたはコンパイル時にスキーマを知っていたし、あなたがタイプ牛車の多くをやってみたかった場合潜在的に、これはまた、コンパイル時間を作ることができます。単純な解決策は、クエリを実行するときにエラー処理を実行させるだけです。だから、

evalExpr :: Expr a -> ExceptT e IO a 

のようなものを探して機能を持っているでしょうそして、あなたはおそらく、ここで、列の種類に関する適切なチェックを実行します。

関連する問題