読者です 読者をやめる 読者になる 読者になる

関係と代数的データ型との相互変換についての妄想 その2

思い付き その1

型レベルのリストをクエリー函数に与えてやる。(DataKinds が有効)

data Attr = Id | Name | Friends
data User = User { id :: Int, name :: String, friends :: [User] }
query :: Proxy '[??] -> Key -> MonadDB User
userFriends :: Proxy '[Friends] -> User -> [User]

リストだとダメだなーって気付いた。勝手に型の和が取られるわけじゃないからね。

それはそれとして、分からないところが2点。

1つは上記のコードで query の型の ?? って書いているところをどう書けばよいか。やりたいことは「?? の部分に入るのは 'Attr カインドの任意の型」ということを示したい。

しばらく寝かせて思い付いたけど KindSignatures を有効にして下記でいけるっぽい。

data ProxyAttr (t :: [Attr]) = ProxyAttr

もう1つは、下記のをうまいこと推論してくれないのなんでだ。stack --resolver lts-8.12 exec -- ghci -fprint-explicit-kinds -XDataKinds にて。

後から気付いた ProxyAttr を使うとエラーにならなかった。

ghci> :m + Data.Proxy
ghci> data Attr = Id | Name | Friends
ghci> data User = User { id :: Int, name :: String, friends :: [User] } deriving (Show)
ghci> :{
ghci| userFriends :: Proxy '[Friends] -> User -> [User]
ghci| userFriends _ _ = [User 1 "Ada" []]
ghci| :}
ghci> bob = User 2 "Bob" []
ghci> let p = Proxy in userFriends p bob

<interactive>:9:30: error:
    • Couldn't match type*’ with ‘[Attr]’
      Expected type: Proxy [Attr] ((':) Attr 'Friends ('[] Attr))
        Actual type: Proxy * ((':) Attr 'Friends ('[] Attr))
    • In the first argument of ‘userFriends’, namely ‘p’
      In the expression: userFriends p bob
      In the expression: let p = Proxy in userFriends p bob

Proxy に型注釈してやると大丈夫。

ghci> let p = Proxy :: Proxy '[Friends] in userFriends p bob
[User {id = 1, name = "Ada", friends = []}]

どっちにしろリストの戦略は破綻してるのでボツ。

制約の方に情報を乗せないとあかん気がしている。