[解決済み] 上位互換型はどんなときに役立つのか?
質問
私はしばらくの間、F#で開発をしていて、それが好きです。 しかし、私が知っている1つの流行語は、F#に存在しない、より高いレベルの型です。 私は高次の型についての資料を読み、その定義を理解しているつもりです。 ただ、なぜそれが有用なのかがよくわからないのです。 ScalaやHaskellでは簡単にできることが、F#では回避策が必要になるという例をどなたか教えていただけませんか? また、これらの例では、高階調型がなければ、どのような回避策があるのでしょうか(F#ではその逆もあります)? 私が回避策に慣れていて、その機能がないことに気づかないだけかもしれません。
の代わりに、(私が思うに) 私はそれを得る
myList |> List.map f
または
myList |> Seq.map f |> Seq.toList
より高いキンダーの型では、単純に次のように書くことができます。
myList |> map f
と書くと
List
. それは素晴らしいことですが(それが正しいと仮定して)、ちょっと小難しいように思えますが? (そして、それは単に関数のオーバーロードを許可することによって行うことができなかったのですか?) 私は通常、変換して
Seq
に変換し、その後で好きなものに変換することができます。 また、私がそれを回避することに慣れすぎているだけなのかもしれません。しかし、より高次の型である
が本当に
がキーストロークまたは型の安全性のどちらかを節約する例はありますか?
どのように解決するのですか?
つまり、型の種類はその単純な型ということになります。例えば
Int
は種類
*
を持ち、これは基底型であり、値によってインスタンス化されることを意味します。高次元の型の緩やかな定義によって(F#がどこで線引きしているのか分からないので、とりあえず入れておきましょう)。
ポリモーフィックコンテナ
は高次元型の素晴らしい例です。
data List a = Cons a (List a) | Nil
タイプ・コンストラクタ
List
は、種類
* -> *
を持っています。これは、具象型を生成するために具象型が渡されなければならないことを意味します。
List Int
は次のような住民を持つことができます。
[1,2,3]
しかし
List
自体はできません。
ポリモーフィックコンテナの利点は明白であると仮定しますが、より便利な種類の
* -> *
の型はコンテナ以外にも存在します。例えば、リレーション
data Rel a = Rel (a -> a -> Bool)
またはパーサ
data Parser a = Parser (String -> [(a, String)])
もまた、親切な
* -> *
.
しかし、Haskellではさらに高次の種類を持つ型を持つことで、これをさらに推し進めることができます。例えば、私たちは種類
(* -> *) -> *
. この簡単な例としては
Shape
という種類のコンテナを満たそうとする
* -> *
.
data Shape f = Shape (f ())
Shape [(), (), ()] :: Shape []
を特徴づけるのに有効です。
Traversable
を特徴づけるのに便利です。
split :: Traversable t => t a -> (Shape t, [a])
別の例として、枝の種類をパラメータとする木を考えてみましょう。例えば、通常の木は
data Tree a = Branch (Tree a) a (Tree a) | Leaf
しかし、ブランチ型には
Pair
の
Tree a
のように、パラメトリックに型からその部分を取り出すことができます。
data TreeG f a = Branch a (f (TreeG f a)) | Leaf
data Pair a = Pair a a
type Tree a = TreeG Pair a
これは
TreeG
型コンストラクタは
(* -> *) -> * -> *
. のような他の面白いバリエーションを作るために使うことができます。
RoseTree
type RoseTree a = TreeG [] a
rose :: RoseTree Int
rose = Branch 3 [Branch 2 [Leaf, Leaf], Leaf, Branch 4 [Branch 4 []]]
のような病的なものも
MaybeTree
data Empty a = Empty
type MaybeTree a = TreeG Empty a
nothing :: MaybeTree a
nothing = Leaf
just :: a -> MaybeTree a
just a = Branch a Empty
または
TreeTree
type TreeTree a = TreeG Tree a
treetree :: TreeTree Int
treetree = Branch 3 (Branch Leaf (Pair Leaf Leaf))
これが現れるもう一つの場所は、"ファンクタの代数"です。もし、抽象化のレイヤーをいくつか落とすと、これは次のようなフォールドとして考えた方が良いかもしれません。
sum :: [Int] -> Int
. 代数のパラメータは
ファンクタ
と
キャリア
. は
ファンクタ
は、種類
* -> *
を持ち、キャリアの種類は
*
ということで、全部で
data Alg f a = Alg (f a -> a)
は種類
(* -> *) -> * -> *
.
Alg
は、データ型やその上に構築された再帰的スキームとの関係から、有用です。
-- | The "single-layer of an expression" functor has kind `(* -> *)`
data ExpF x = Lit Int
| Add x x
| Sub x x
| Mult x x
-- | The fixed point of a functor has kind `(* -> *) -> *`
data Fix f = Fix (f (Fix f))
type Exp = Fix ExpF
exp :: Exp
exp = Fix (Add (Fix (Lit 3)) (Fix (Lit 4))) -- 3 + 4
fold :: Functor f => Alg f a -> Fix f -> a
fold (Alg phi) (Fix f) = phi (fmap (fold (Alg phi)) f)
最後に、理論的には可能ですが、私はこれまで
であっても
より高次の型コンストラクタを見たことがありません。そのような型の関数は時々見かけますが、例えば
mask :: ((forall a. IO a -> IO a) -> IO b) -> IO b
しかし、型の複雑さについては、型プロローグや依存型付けされた文献を調べないとわからないと思います。
関連
-
[解決済み] C++のPOD型とは何ですか?
-
[解決済み】type()とisinstance()の違いは何ですか?)
-
[解決済み】ScalaのHigher kinded typeとは何ですか?
-
[解決済み] 述語で配列を2つに分割するには?
-
[解決済み] Scalaのパターンマッチはなぜ変数で機能しないのですか?
-
[解決済み] Scalaの配列の初期化
-
[解決済み] 末尾再帰関数が最適化されるためのScalaアノテーションは何ですか?
-
[解決済み] Scalaでサブアレイを取得する正しい方法は何ですか?
-
[解決済み] Scalaのtraitでvalとdefの使い分けは?
-
[解決済み] 関数型プログラミング(特にScalaとScala API)におけるreduceとfoldLeft/foldの違いとは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] ネストした構造体をよりきれいに更新する方法
-
[解決済み] Scalaのforループは下降か減少か?
-
[解決済み] Scalaです。リスト[Future]からFuture[List]への変換は、失敗したFutureを無視する。
-
[解決済み] Scala の private と protected コンストラクタ
-
[解決済み] Scala の Case Classes のオーバーロード・コンストラクタ?
-
[解決済み] build.sbtとbuild.scalaの違いは何ですか?
-
[解決済み] 末尾再帰関数が最適化されるためのScalaアノテーションは何ですか?
-
[解決済み] sbtの依存関係ツリーを見るには?
-
[解決済み] Spark ScalaのDataFrameのカラム名のリネーム
-
[解決済み] に似た三項演算子。