Proxy型
前提としてread, showの型はこう
hsread :: Read a => String -> a
show :: Show a => a -> String
これを組み合わせたような関数を定義すると、
これは普通に考えれば型は、 String -> String
だが、そうすると Read a
や Show a
の制約が消えてしまうので型安全でない
そのため f :: String -> String
のような型注釈はエラーになる
かと言って、こういうふうにも定義できない
hsf :: (Read a, Show a) => String -> String
f = show . read
これは、 a
に制約を入れているが、結局、引数にも戻り値にも a
が現れていないため、エラーになる
使用する側から見ても f "hoge"
のようになるので、これだけではどういう中間型 a
を経過すればよいのかわかるはずもない
そこで、 a
を使用するために、例えばこういう定義ができる
hs{-# LANGUAGE ScopedTypeVariables #-}
g :: forall a. (Read a, Show a) => a -> String -> String
g _ = (show :: a -> String) . read
ただただ a
を型情報を得るためだけに引数に取っている
要は、こういうノリのことがしたい
でも、Haskellは依存型を扱うわけではないので、型を値として扱えない
こうやって利用できる
この 0
は数値なら何でもよく、 1
でも 100
でも何でも良い
ただ単に Int
ですよ、というのが伝われば良い
でも、こう書くと「 0
ってなに??」となる
型情報を伝えるのが責務なのであれば、よりそれに制限されていたほうが良い
そこで、Proxyを使う
今回は自前で定義する
わかりやすさのため、値コンストラクタの名前をずらしている
関数は高定義する
hs{-# LANGUAGE ScopedTypeVariables #-}
f :: forall proxy a. (Read a, Show a) => proxy a -> String -> String
f _ = (show :: a -> String) . read
PureScriptでは
purs(hs)class Read a where
read :: String -> a
f ::
∀ a.
Read a =>
Show a =>
Proxy a ->
String ->
String
f _ = (show :: a -> String) <<< read
こう使う
hsf (ProxyC :: Proxy Int) "3"
最終的には Int
であることが伝わればよいのだが、
値である ProxyC
を見ただけでは、型の Proxy a
の a
が確定しないため、 ::
で明示する必要がある
結果的にかなり冗長になっているが、仕方がない

これが、Proxyの存在意義の一つ
他の例はまだよく知らん

し、もっと簡潔に書ける
TypeApplicationsを使って簡潔に型アノテーションを書く
hs{-# LANGUAGE TypeApplications #-}
main = do
print $ map (read @Int) ["33", "4"]
print $ show @Int . read $ "42"
何が嬉しい?
Proxyの定義
無いとどうなる
同じ引数の者同士は同じもの?
Proxyという名前
tsで言うとどういうものになるのか
1つもGHC拡張使わずに嬉しい例を見てみたい
存在型のこと?
カッコつけて
わかりやさすたのため、こうする
(hs)ghci> import Data.Proxy
ghci> :t ProxC
ProxyC :: Proxy t
ghci> :t ProxyC :: Proxy Int
ProxyC :: Proxy Int :: Proxy Int
わかると自明だが、
1つ目の方は、「ProxyCの型は?」と聞いて、 Proxy t
です、と返ってきている
2つ目は、「 ProxyC :: Proxy Int
の型は?」と聞いて、 Proxy Int
ですと返ってきている
括弧を付けるなら、 ((ProxyC) :: Proxy Int) :: Proxy Int
のような感じ
「 1 :: Int
の型は?」と聞いて、「 Int
です(そらそう)」と返ってきているのと同じ
hsdata Proxy t = Proxy deriving Bounded
purs(hs)data Proxy :: forall k. k -> Type
data Proxy a = Proxy
任意のkindの型を引数に取る
purs(hs)data SProxy :: Symbol -> Type
data SProxy sym = SProxy
Symbolを引数に取る
Proxyでもあるので、この値は、 Proxy
型を要請する場でも適用できる
本当は型レベルの計算において、モノとモノを区別するためにタグ付けするために使う感じ
ただ、実際には関数も必要になるので(?)、関数側には値コンストラクタを与えるてきな?
purs(hs)zero :: Proxy Zero
zero = Proxy
Void
と同じようなもの
終対象
Voidに型パラメータを与えたようなもの
データは何も持たない
幽霊型を使ってType-Level Literalsをやる
tsのliteral typeみたいなやつ
