generated at
Proxy型









https://stackoverflow.com/a/27047260 の前半の説明などを読んで
前提としてread, showの型はこう
hs
read :: Read a => String -> a show :: Show a => a -> String
これを組み合わせたような関数を定義すると、
hs
f = show . read
これは普通に考えれば型は、 String -> String だが、そうすると Read a Show a の制約が消えてしまうので型安全でない
そのため f :: String -> String のような型注釈はエラーになる
かと言って、こういうふうにも定義できない
hs
f :: (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 を型情報を得るためだけに引数に取っている
要は、こういうノリのことがしたい
hs
g Int "3"
でも、Haskellは依存型を扱うわけではないので、型を値として扱えない
こうやって利用できる
hs
g 0 "3"
この 0 は数値なら何でもよく、 1 でも 100 でも何でも良い
ただ単に Int ですよ、というのが伝われば良い
でも、こう書くと「 0 ってなに??」となる
型情報を伝えるのが責務なのであれば、よりそれに制限されていたほうが良い
そこで、Proxyを使う
今回は自前で定義する
わかりやすさのため、値コンストラクタの名前をずらしている
hs
data Proxy t = ProxyC
関数は高定義する
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
こう使う
hs
f (ProxyC :: Proxy Int) "3"
最終的には Int であることが伝わればよいのだが、
値である ProxyC を見ただけでは、型の Proxy a a が確定しないため、 :: で明示する必要がある
結果的にかなり冗長になっているが、仕方がないmrsekut
これが、Proxyの存在意義の一つ
他の例はまだよく知らんmrsekut
これに関しては、これはTypeApplicationsを使えばProxyは不要になる
し、もっと簡潔に書ける
TypeApplicationsを使って簡潔に型アノテーションを書く
hs
{-# LANGUAGE TypeApplications #-} main = do print $ map (read @Int) ["33", "4"] print $ show @Int . read $ "42"




何が嬉しい?
Proxyの定義
無いとどうなる
同じ引数の者同士は同じもの?
Proxyという名前
tsで言うとどういうものになるのか
1つもGHC拡張使わずに嬉しい例を見てみたい
TypeApplicationsがあれば不要だったりする?
存在型のこと?


カッコつけて
わかりやさすたのため、こうする
hs
data Proxy t = ProxyC
(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 です(そらそう)」と返ってきているのと同じ






hs
data 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に型パラメータを与えたようなもの
データは何も持たない



AllowAmbiguousTypesを使えばProxyは不要?




幽霊型を使ってType-Level Literalsをやる
tsのliteral typeみたいなやつmrsekut