はい、なので実際のコードでは
実際のところは正確にわからないので本当は
Word64
にしています。実際のところは正確にわからないので本当は
Integer
のほうがいいのかもしれませんが。Word64
にしています。Integer
のほうがいいのかもしれませんが。universum
を使ってみたんですけど、第一印象は「かゆいところに手が届かない」Preludeでした。type SomeMap = Map String int
import Data.Map.Strict
ができないんです。3.2 Fold
は確かに Parametricity と代数の可換性から自然に fusion が導かれているのが分かりました 重ねてご教示有難うございましたtype family ConsUnless (b :: Bool) (x :: k) (xs :: [k]) :: [k] where ConsUnless False x xs = (x ': xs) ConsUnless True _ xs = xs type family Reject (p :: (k -> Bool)) (xs :: [k]) :: [k] where Reject p '[] = '[] Reject p (x ': xs) = ConsUnless (p x) x (Reject p xs) type family Same (x :: k) (y :: k) :: Bool where Same x x = 'True Same x y = 'False type family Without (x :: k) (xs :: [k]) :: [k] where Without x xs = Reject (Same x) xs
• The type family ‘Same’ should have 2 arguments, but has been given 1 • In the equations for closed type family ‘Without’ In the type family declaration for ‘Without’
Same
が2つ引数をとるのはいいとして、 Reject
の第一引数が引数を1つとる型族をとるよう宣言しているので、 Same x
とすればいいんじゃないかと思えるのですが、なんでエラーになってしまうのでしょうか?Remove
に相当するのは Without
と呼んでいます。type family Result (x :: k) (xs :: [k]) :: [k] where Result x '[] = '[] Result x (x ': xs) = Result x xs Result x (y ': ys) = y ': Result x ys class Without (x :: k) (xs :: [k]) where without :: Membership xs x -> (h :* xs) -> (h :* Result x xs) instance Without x '[] where without _ _ = nil instance Without x (x ': xs) where without key rec = let (_, ys) = huncons $ toHList rec in without key (fromHList ys) instance Without x (y ': ys) where without key rec = let (y, ys) = huncons $ toHList rec in y <: without key (fromHList ys) huncons :: HList h (x ': xs) -> (h x, HList h xs) huncons (HCons hx hxs) = (hx, hxs)
app\Main.hs:41:21: error: ? Couldn't match type ‘xs’ with ‘x : xs’ ‘xs’ is a rigid type variable bound by the instance declaration at app\Main.hs:38:10-28 Expected type: h :* (x : xs) Actual type: h :* xs ? In the second argument of ‘without’, namely ‘(fromHList ys)’ In the expression: without key (fromHList ys) In the expression: let (_, ys) = huncons $ toHList rec in without key (fromHList ys) ? Relevant bindings include ys :: HList h xs (bound at app\Main.hs:40:13) rec :: h :* (x : xs) (bound at app\Main.hs:39:15) key :: Membership (x : xs) x (bound at app\Main.hs:39:11) without :: Membership (x : xs) x -> (h :* (x : xs)) -> h :* Result x (x : xs) (bound at app\Main.hs:39:3) | 41 | in without key (fromHList ys) | ^^^^^^^^^^^^ app\Main.hs:46:26: error: ? Couldn't match type ‘ys’ with ‘y : ys’ ‘ys’ is a rigid type variable bound by the instance declaration at app\Main.hs:43:10-28 Expected type: h :* (y : ys) Actual type: h :* ys ? In the second argument of ‘without’, namely ‘(fromHList ys)’ In the second argument of ‘(<:)’, namely ‘without key (fromHList ys)’ In the expression: y <: without key (fromHList ys) ? Relevant bindings include y :: h y (bound at app\Main.hs:45:10) ys :: HList h ys (bound at app\Main.hs:45:13) rec :: h :* (y : ys) (bound at app\Main.hs:44:15) key :: Membership (y : ys) x (bound at app\Main.hs:44:11) without :: Membership (y : ys) x -> (h :* (y : ys)) -> h :* Result x (y : ys) (bound at app\Main.hs:44:3) | 46 | in y <: without key (fromHList ys)
newtype Cell = Cell (Maybe Int)
newtype
とすることで、 Cell
はまさにおっしゃるような、 「 Maybe Int
と ほとんど同じなんだけど、ほんの少し振る舞いが異なる型」として定義できます。Show
はあくまでもデバッグ用の文字列に変換するものとして使ったほうがよいのではないかと考えています。newtype
でセル専用の型を用意するにせよしないにせよ、Show
や Read
のインスタンスを無理に書き換えずに、文字列からパースして作成したり文字列に変換する用の関数は独立して作った方がいいんじゃないかと思います。instance Without x ys => Without x (y:ys) where
type family Result (x :: k) (xs :: [k]) :: [k] where Result x '[] = '[] Result x (x ': xs) = Result x xs Result x (y ': ys) = y ': Result x ys
ただ、個人的には `Show` はあくまでもデバッグ用の文字列に変換するものとして使ったほうがよいのではないかと考えています。
String
の show
関数は、受け取った文字列をそのまま返すのではなく、Show
のインスタンスは、traceShowId
など Show
のインスタンスをデバッグ用に使う関数に渡して表示させた際、(特に何カ所も出力させた場合に)どの型の値を出力したのか区別できるようにした方が、視認性が上がるためでしょう。Read
のインスタンスにする必要はないだろうな、と思って触れてませんでした。