私は Haskell を学んでいますが、Haskell は非常にエレガントで強力です。しかし、OOP を使用して非常に単純に見えることを行う方法をイメージするのはまだ困難です。たとえば、zope3/grok/pyramid Web プラットフォームを取り上げます。それらには、コンテンツとビューを一致させてページをレンダリングすることに基づく美しい哲学があります。
Zope では、異端のコンテンツ タイプのツリーがあります。URL を要求すると、traverse
そのツリーへのパスを使用してcontext
オブジェクトを取得します。パスの最後の部分は「ビュー名」です。View
オブジェクトのタイプとビュー名に基づいて取得します。はView
特定のコンテキスト タイプからオブジェクトRequest
への関数です。Response
したがって、URL http://example.com/aFolder/aFaq/aQuestion/index.htmlにアクセスすると、zope はツリーのルートから開始されます。という名前のノードを検索し、aFolder
このオブジェクト内で別の という名前のノードを検索し、その内部でaFaq
という名前のノードを検索しますaQuestion
。したがって、traverse
関数は任意の型のオブジェクトを返すことができます。
ここは問題ありません。Traversable
ツリーをトラバースしているだけなので、 Haskell で という名前の新しいラッパー タイプまたはクラスを作成できTree Traversable
ますtraverse :: Tree Traversable -> [string] -> Traversable
。
しかし、問題index.html
は、ビューの名前です。簡単に説明すると [*] Zope はペア (コンテキストの型、ビュー名) を探し、大まかに言えば型の関数を返します{type of the context} -> Request -> Response
。traversable の型をチェックする function を書くことはできますrender :: Traversable -> String -> Response
が、誰かが新しいコンテンツ タイプまたは新しいビューを追加するたびに、その関数を更新する必要があります。ビュー関数 (またはサブ関数) は、そのデータを使用するためにコンテキストのタイプを知る必要があります。
では、ベテランの haskeller はこの種の問題にどのように対処するのでしょうか? しばらく GADT で考えましたが、それが役立つかどうか、またはもっと簡単な代替手段があるかどうかはわかりません。
ありがとう!
編集:明確にするための疑似コード
def traverse(node, path):
# returns the context and the view name
itemname = path[0]
if hasattr(node, itemname):
# The next element in the path is a subnode of the node, let's visit it
return traverse(node[itemname], path[1:])
else:
# We can't go down the tree anymore, we found our context and view name
viewname = itemname
return node, viewname
def render(tree, request):
path = somehow_get_path_from_request(request)
context, viewname = traverse(tree, path)
# We get the view from a registry which is a map/dictionary
view = registry[(context, viewname)]
# here comes the problem:
# view is an object that knows exactly the type of context
# A view for a Question object can use its 'question' and 'answer' fields
# A View for a Folder can use its 'items' fields, a view for Image can use
# its 'img' field.
#
return view.render(context, request)
これは、haskell で行う方法がわからないことです。Haskell f にはツリーがあり、同種のオブジェクトでなければなりません。そのため、ラッパー タイプ Traversable を定義する必要があります。しかし、誰かが新しい型を追加したい場合は、私のコードを変更する必要があります。または、Haskell クラス Traversable を作成することもできます。このようにして、将来の型をツリーに追加できます。しかし、(context, viewname) から不明なコンテキストの関数にマップするにはどうすればよいでしょうか?
[*] 真実はもう少し複雑です。zope では、オブジェクトまたはそのクラスは実行時に任意のマークを付けることができますinterfaces
(python にはインターフェースの概念がありません。これは完全に zope の構築です)。インターフェイスはツリーを形成します。ビューをペア (インターフェース、名前) に関連付けます。(コンテキスト、名前) のビューを要求すると、最も具体的なインターフェイスに関連付けられたビューが返されます。アイデアは、コードを変更せずに、インターフェイスのレジストリを変更してビューを変更できるということです。