FPの蚭蚈ずアヌキテクチャ。 パヌト3

プロパティず法埋。 シナリオ Haskellの制埡の反転。



かなりの理論


最埌の郚分では、蚭蚈が䞍十分なコヌドで混乱するこずが非垞に簡単であるこずを確認したした。 幞いなこずに、叀代から「分割統治」の原理が知られおいたす。これは、建築の構築や倧芏暡システムの蚭蚈に広く䜿甚されおいたす。 コンポヌネントぞの分離、モゞュヌル間の䟝存関係の削枛、盞互䜜甚むンタヌフェヌス、詳现からの抜象化、特定の蚀語の匷調など、この原則のさたざたな具䜓化を知っおいたす。 これは呜什型蚀語でうたく機胜し、実装の手段が異なるこずを陀いお、関数型蚀語で機胜するず想定する必芁がありたす。 どれ



Inversion of Controlの原理を考えおみおくださいこの原理の詳现な説明は、ネットワヌクで簡単に芋぀けるこずができたすたずえば、 ここずここ 。 実行の流れを逆にするこずにより、プログラムの郚分間の接続性を枛らすのに圹立ちたす。 文字通り、これはコヌドが別の堎所に埋め蟌たれ、い぀かそこに呌び出されるこずを意味したす。 この堎合、埋め蟌たれたコヌドは、抜象むンタヌフェヌスを備えたブラックボックスず芋なされたす。 どのような機胜的なコヌドでも、IoC属性の䞡方が組み合わされおいるこずを瀺したしょう。「コヌドむンゞェクション」ず「ブラックボックス」です。このために、簡単な䟋を考えたす。



進行op = 反埩  `op` 2 



geometricProgression 、 arithmeticalProgression :: æ•Žæ•° -> [ æ•Žæ•° ]

geometricProgression =進行 * 

算術進行=進行 + 



幟䜕孊、算術:: [ æ•Žæ•° ]

幟䜕孊= 10 $ geometricProgression 1を取る

算術= 10 $の算術進行1を取る


ここでは、他の関数*、+、 `op` 2が1぀の関数の入力反埩、進行に転送されたす。぀たり、いく぀かのコヌドが導入されおいたす。 たた、受信関数内では、このコヌドはブラックボックスず芋なされ、タむプのみがわかっおいたす。 たずえば、反埩の堎合、2番目の匕数はInteger-> Integer型でなければならず、デバむスがどれほど耇雑であっおもかたいたせん。 したがっお、制埡の反転は関数型プログラミングの基瀎です。 理論的には、高階関数を䜿甚するず、任意の倧芏暡なアプリケヌションを構築できたす。 問題が1぀だけありたす。このIoCの解釈はあたりにも玠朎であり、これはもちろん玠朎なコヌドに぀ながりたす。 すでに䞊蚘の䟋では、コヌドはモノリシックピラミッドであり、実際のアプリケヌションでは巚倧な比率になり、完党にサポヌトされなくなるこずがわかりたす。



IoCを反察偎、぀たり「おもおなし」のクラむアントコヌドから芋おみたしょう。 その䞭に、特定の目的に圹立぀䜕らかの倖郚成果物を取埗したす。 倖郚では、このアヌティファクトは別のものに眮き換えるこずができたすが、受信偎の堎合、眮換は目に芋えないはずです。 これは、いわゆるLisk眮換の原則です。 OOPの䞖界のガむドずしお機胜し、アヌティファクトには予枬可胜な動䜜があるこずを芏定しおいたす。 OOP蚀語でこのような保蚌を䞎えるこずは䞍可胜であるため、「芏定」ではなく「保蚌」ではなく、原則に違反するアヌティファクトに副䜜甚が突然珟れる可胜性がありたす。 この原則は関数型蚀語に適甚できたすか はい、もちろんです。 さらに、コヌドがクリヌンであれば、特に蚀語が厳密に静的型付けされおいる堎合、より匷力な保蚌が埗られたす。



蚘事の最埌に、HaskellのInversion of Controlのさたざたな実装の簡単な説明がありたす。 䞀郚のテンプレヌトは、呜什型の䞖界のテンプレヌトずほが完党に類䌌しおいたすたずえば、モナド状態の泚入は䟝存性泚入ですが、䞀郚はIoCにわずかに䌌おいたす。 しかし、それらはすべお良い蚭蚈のために等しく有甚です。



たくさんの緎習


良いコヌドを曞く時が来たした。 この蚘事では、 これずこのコミットによっお抂説される時代党䜓であるゲヌム「アメヌバの䞖界」のデザむンを匕き続き怜蚎したす。 時代は飜和した。 完党に曞き盎されたゲヌムロゞックに加えお、 レンズなどのツヌルが詊され、 QuickCheckを䜿甚したテストが導入され 、スクリプト蚀語が発明され、そのむンタヌプリタヌが䜜成され、䞖界グラフを怜玢するためのA *アルゎリズムが統合され、別の特定のアンチパタヌンが発芋され、この時代が終わりたした。 この蚘事では、䌚話はプロパティずシナリオのみに関係し、残りは次の郚分に残したす。



プロパティずオブゞェクト



過去の経隓から、オブゞェクトが実際に䜕であるか、それらが䜕で構成されおいるかが明らかになりたした。 この蚭蚈の背埌にある䞻なアむデアは次のずおりです。オブゞェクトは、いく぀かのプロパティで構成される゚ンティティです。 「Karyon」、「Plasma」、「Border」などのオブゞェクトが分析され、次のプロパティセットが取埗されたした。





现心の泚意を払った読者はここで䞍完党性を芋るこずができたす。たずえば、䜕らかの理由で「局」ず「堎所」は2぀のプロパティに分かれおいたすが、それらはほが同じように芋えたす。 そしお、この「衝突」ずはどのような財産ですか 工堎はどうですか そしお、「幎霢」ず「自己砎壊」はどうですか そしお、なぜ各オブゞェクトはメモリを浪費する文字列名を持っおいたすか 䞻匵は正圓化され、すでに次の時代に、リストは再び改蚂され、同じようにプロパティのプロパティを匷調衚瀺するこずによっお。 その結果、最も重芁な「ランタむム」ず「静的」の6぀だけが残り、残りは論理的に倖郚の効果ずアクションに倉わりたした...



たずえば、ゲヌムマップ䞊に存圚する可胜性のあるいく぀かの実際のオブゞェクトを口頭で説明したす。



カヌネル

名前= 「Karyon」

ロケヌション=  1、1、1 

レむダヌ=地球

所有者=プレヌダヌ1

匷床= 100/100

バッテリヌ= 300/2000

工堎=プラズマ、プレむダヌ1



プラズマ

名前= 「プラズマ」

ロケヌション=  2、1、1 

レむダヌ=地球

所有者=プレヌダヌ1

匷床= 30/40


プロパティの数には限りがあるため、それぞれにラッパヌ型を䜜成し、それらをすべお1぀の代数型 code の䞋に配眮するこずにしたした。



-Object.hs

dataプロパティ= PNamed Named

| PDurability リ゜ヌスの耐久性

| PBattery リ゜ヌス゚ネルギヌ

| 所有暩プレヌダヌ

| プレむレむダヌ

...

導出  Show 、 Read 、 Eq 


抜象オブゞェクトのタむプを定矩したす。



-Object.hs

タむプ PropertyKey = Int

PropertyMap = Mず入力したす。 Map PropertyKeyプロパティ



デヌタオブゞェクト=オブゞェクト{ propertyMap :: PropertyMap }

導出  Show 、 Read 、 Eq 


財産の圢で物firstいする最初の考えは、私たちが始めたずころ、぀たり神のADT問題に戻ったずいうこずです圓時はそれはアむテムタむプでした。 しかし、これはそうではありたせん。 倧きな違いは、Object型が提䟛する抜象化レベルです。 「組み合わせの自由」ず呌ぶこずができるものがありたす。少数のプロパティは、新しいオブゞェクトを配眮する可胜性の組み合わせの爆発をもたらしたす。 他のプロパティは蚈画されおいたせん-衚瀺される堎合、ドミノを通る波のように、倉曎はコヌドに沿っお䌝播したせん。 シナリオに぀いお説明するずき、これを確信したすが、今のずころは、これらの非垞に具䜓的なオブゞェクトを䜜成する方法を自問したす。



最も簡単な方法は、プロパティのリストに入力しおData.Mapに倉換するこずです 。



-Objects.hs

むンポヌトオブゞェクト



karyon =オブゞェクト$ M fromList [  1 、 PObjectId 1 

、  4 、 PNamed“ Karyon” 

、  2 、 PDurability リ゜ヌス100 100  

、  3 、 PBattery リ゜ヌス300 2000  

、  10 、 POwnership Player1 

、  5 、 PDislocation  Point 1 1 1  

、 ... ]


...しかし、停止 PObjectId、Dislocation、およびOwnershipをどのようなロゞックで芏定したすか 結局のずころ、マップ䞊のオブゞェクトに぀いおのみそれらに぀いお話すこずは理にかなっおいたす 䞀方、オブゞェクトのクラスを指定しお倉曎しない共通プロパティがありたす。PNamedずPLayer、PFabricずPPassRestriction移動犁止です。 Karyonでは、レむダヌはGroundのみであり、PNamed“ Plasma”プロパティはそれぞれプラズマにのみ属するこずができたす。 ここでは、マップ䞊に盎接配眮するずきにオブゞェクトを䜜成する必芁があるずいう問題に盎面しおいたすが、同時に初期デヌタを含むテンプレヌトが必芁です。 テンプレヌトずしお、いわゆる「 スマヌトコンストラクタヌ 」が適しおいたす。既補のパタヌンず小さな入力パラメヌタヌセットに埓っお、既補のオブゞェクトを䜜成する関数です。 よりスマヌトなカリオン関数は次のようになりたす。



-Objects.hs

むンポヌトオブゞェクト



karyon pId player point = Object $ M fromList [  1 、 PObjectId pId 

、  4 、 PNamed“ Karyon” 

、  2 、 PDurability リ゜ヌス100 100  

、  3 、 PBattery リ゜ヌス300 2000  

、  10 、所有暩プレむダヌ

、  5 、 PDislocationポむント

、 ... ]


この構文ぱレガントずは蚀い難く、「ノむズ」ず身䜓の動きが倚すぎたす。 Haskellは簡朔な蚀語であり、シンプルさず機胜的なミニマリズムを目指しお努力すれば、コヌドはより矎しく、理解しやすく、より䟿利になりたす。 ああ、䞊蚘のいく぀かのパラグラフで提瀺されたテンプレヌトの口頭での説明をコヌドに転送できればいいず思いたす... 䞍可胜はありたせん 



-Objects.hs

plasmaFabric ::プレヌダヌ->ポむント->ファブリック

plasmaFabric pl p = makeObject $ do

energyCost 。= 1

スキヌム。=プラズマpl p

プロデュヌス。= True

placementAlg 。= placeToNearestEmptyCell



karyon ::プレヌダヌ->ポむント->オブゞェクト

karyon pl p = makeObject $ do

namedA | = karyonName

layerA | =グラりンド

dislocationA | = p

batteryA | =  300 、ちょうど2000 

耐久性A | =  100 、ちょうど100 

ownerA | = pl

fabricA | = plasmaFabric pl p


コヌドのわかりやすさは、読者の知識ず思考が著者の知識ず思考ずどれだけ䞀臎しおいるかに䟝存したす。 このコヌドは明確ですか 圌が䜕をしおいるのかは明らかですが、圌はどのように働いおいたすか たずえば、挔算子「。=」ず「| =」はどういう意味ですか makeObject関数はどのように機胜したすか なぜ䞀郚の名前には文字「A」があり、䞀郚の名前にはないのですか そしお、それはモナドか䜕かですか..



これらの正しい質問に察する霧の答えはこれです。このコヌドはオブゞェクトのレむアりトに内郚蚀語を䜿甚したす。 その蚭蚈は、状態モナドず組み合わせたレンズの䜿甚に基づいおいたす。 「A」接尟蟞を持぀関数は、プロパティ自䜓のスマヌトコンストラクタヌ「アクセサ」であり、特定のプロパティのシリアル番号ず倀の怜蚌方法を知っおいたす。 「A」のない機胜はレンズです。 挔算子「。=」はレンズのラむブラリに属し、Stateモナド内で「拡倧䞭」の倀を蚭定できたす。 plasmaFabric関数はFabric ADTに入力し、karyon関数はPropertyMapずObjectに入力したす。 2番目の䟋では、アクセサヌずデヌタはカスタム挔算子| =に転送されたす。正確を期すために、これを「充填挔算子」ず呌びたす。 fillステヌトメントは、Stateモナド内で機胜したす。 圌は珟圚のPropertyMapを匕き出し、アクセサヌによっお怜蚌されたプロパティをその䞭に入れたす。



-Object.hs

makeObject ::デフォルトa =>状態a   -> a

makeObject = flip execState def



data PAccessor a = PAccessor { key :: PropertyKey

、 constr :: a- >プロパティ}



-オペレヌタヌ充填プロパティ

 | = アクセサv = do

小道具< -get

let oldPropMap = _ propertyMap props

let newPropMap = insertProperty  key accessor   constr accessor v  oldPropMap

put $ props { _ propertyMap = newPropMap }



-Namedプロパティのアクセサ

isNamedValid  Named n  = not 。 null $ n

namedValidator n | isNamedValid n = n

| それ以倖の堎合 = ゚ラヌ $ "無効な名前付きプロパティ" ++ nを衚瀺



namedA = PAccessor 0 $ PNamed 。 namedValidator


このデザむンは完璧ではありたせん。 実行時に゚ラヌが発生する可胜性があるため、プロパティの怜蚌は非垞に危険に芋えたす。 たた、セットにそのようなプロパティが既に存圚するかどうかも監芖したせん。その䞊に新しいプロパティを曞き蟌むだけです。 䞡方の欠陥は、EtherおよびStateモナドのスタックを䜜成し、安党な方法で䟋倖を凊理するこずで簡単に修正できたす。 この堎合、テンプレヌトObjects.hsを含むモゞュヌルのコヌドはわずかに倉曎されたす。 倚くの利点がありたすが、1぀の異論がありたす。オブゞェクトレむアりトの蚀語はテンプレヌトの䜜成にのみ䜿甚され、テストは可胜ですが、远加のロゞックは邪魔になりたす。 䞀方、このコヌドがスクリプティングに入るず、セキュリティが重芁になりたす。



オブゞェクトに関する最埌の質問は、Worldデヌタ型は今どのように芋えるかずいうこずです。 倧きな倉曎はありたせんでしたが、䞖界は䟝然ずしお䞀皮のマップです。



World = Mず入力したす。 マップポむントオブゞェクト


Data.Map構造はパフォヌマンスが䜎䞋したす。 ここでより適切な゜リュヌションは、2次元配列です。 Haskellには、 vectorやrepaなどの効率的なベクタヌ実装がありたす。 ゲヌムのパフォヌマンスが十分に高くないこずが明らかになった堎合、䞖界のリポゞトリに戻っお確認するこずが可胜になりたすが、珟時点では開発速床がより重芁です。



シナリオ



シナリオは䞖界の法則です。 シナリオは特定の珟象を説明したす。 䞖界の珟象は局所的です。 1぀の珟象では、必芁なプロパティのみがマップの特定のセクションに含たれたす。 たずえば、爆匟が爆発するずき、半埄Nのオブゞェクトの匷床に関心がありたす。これは、ダメヌゞの量だけ枛らす必芁があり、匷床が0未満に䜎䞋した堎合、マップからオブゞェクトを削陀する必芁がありたす。 工堎が圓瀟のために機胜する堎合、最初に工堎にリ゜ヌスを提䟛し、次に補品を入手しお近くのどこかに配眮する必芁がありたす。 匷床は重芁ではありたせんが、リ゜ヌス、工堎自䜓、補品の空きスペヌスが重芁です。



スクリプトは、基瀎ずなるプロパティに関連しお実行する必芁がありたす。 マップに「モヌション」プロパティを持぀オブゞェクトがある堎合、モヌションスクリプトを実行したす。 工堎が皌働しおいる堎合、軍事ナニットの生産シナリオを実行したす。 スクリプトは、珟圚の䞖界を倉えるこずはできたせん。 䞀床に1぀ず぀機胜し、結果をデヌタ構造党䜓に蓄積したす。 䞀郚のシナリオの䜜業は、完党にキャンセルされるたで、他のシナリオの䜜業に圱響する堎合があるこずに留意する必芁がありたす。



これを䟋で説明したす。 1ナニットのコストで1぀のタンクを生産する2぀の工堎を考えおみたしょう。 圚庫のリ゜ヌスは1ナニットのみです。 最初のシナリオは正垞に機胜したすが、2番目のシナリオではすべおのリ゜ヌスが䜿い果たされ、機胜を停止するこずがわかりたす。 たたは別の状況2぀のオブゞェクトが反察方向に移動したす。 それらの間に1぀のセルが残っおいる堎合、どうなりたすか 衝突たたはオブゞェクトのいずれかの動きの䞍可胜性 そのようなニュアンスはたくさんあるかもしれたせん。 スクリプトを完成させたいのですが、読み取りず曞き蟌みは非垞に簡単なたたです。



スクリプトサブシステムの芁件の抂芁を説明したす。



ゲヌム「The Amoeba World」では、シナリオDSL蚀語が蚭蚈され、そのむンタヌプリタヌコヌドが䜜成されたした。 Fabricプロパティコヌドのスクリプトは次のようになりたす。



-Scenario.hs

createProduct ::゚ネルギヌ->オブゞェクト->評䟡オブゞェクト

createProduct eCost sch = do

pl <-所有暩の読み取り

d <-転䜍の読み取り

withdrawEnergy pl eCost

return $ adjust sch [所有暩。〜pl 、転䜍。〜d ]



placeProduct prod plAlg = do

l < -withDefault ground $ getProperty layer prod

obj < -getActedObject

p < -evaluatePlacementAlg plAlg l obj

$ objectDislocationを保存したす。〜p $ prod



を生成するf = do

prodObj < -createProduct  f ^ 。energyCost   f ^ 。scheme 

placeProduct prodObj  f ^ 。placementAlg 

「正垞に䜜成されたした。」



producerScenario ::評䟡文字列

producerScenario = do

f <-ファブリックの読み取り

f ^。 生産

その埌 、f を生成する

それ以倖の堎合は、 「䞀時停止䞭」を 返し たす。


䞀連の蚘事の第2郚、぀たり「let-functions」セクションでは、コヌドが扱いにくく理解しにくいものであるこずがわかりたした。 これで、コヌドは軜く、ただ理解できたせんが、特定のシステムがすでに衚瀺されおいたす。 それを理解しおみたしょう。



シナリオDSLは、ゲヌムデヌタのリク゚ストの蚀語ずランタむムの2぀の郚分に分かれおいたす。 すべおの䞭心にあるのはEval型です。EitherモナドずStateモナドのスタックです。



-Evaluation.hs

タむプ EvalType ctx res = BothT EvalError  State ctx  res

タむプ Eval res = EvalType EvaluationContext res


State内郚モナドを䜿甚するず、実行コンテキストを保存および倉曎できたす。 珟圚の䞖界、運甚デヌタ、ランダムゞェネレヌタヌ-これらはすべお次のコンテキストにありたす。



data DataContext = DataContext { dataObjects ::評䟡オブゞェクト

、 dataObjectGraph :: Eval  NeighboursFunc- > ObjectGraph 

、 dataObjectAt :: Point- > Eval  倚分 Object  }



デヌタ EvaluationContext = EvaluationContext { ctxData :: DataContext

、 ctxTransactionMap :: TransactionMap

、 ctxActedObject ::オブゞェクトかもしれたせん

、 ctxNextRndNum :: Eval Int }


どちらの倖郚モナドでも、実行゚ラヌを安党に凊理できたす。 最も䞀般的な状況は、衝突が発生した堎合であり、䞀郚のシナリオは䜜業の途䞭で䞭断するはずです。 ゲヌムの状態を正しく維持するには、すべおの倉曎をロヌルバックする必芁がありたす。スクリプトが別のスクリプトから呌び出された堎合は、䜕らかの方法で問題に察応する必芁がありたす。 したがっお、倚くの関数はEval型であり、Eitherモナドを隠したす。 実際、Eval型の関数はすべおスクリプトです。 むンタプリタ関数evalTransact、getTransactionObjectsおよびク゚リ蚀語関数single、findでさえ、このタむプで動䜜し、実際にはスクリプトでもありたす。 蚀い換えれば、シナリオDSL蚀語はEval型によっお統䞀されおおり、これによりコヌドの䞀貫性ずモナド合成が可胜になりたす。



Evalタむプの関数はスクリプトであるため、それぞれを実行およびテストできたす。 スクリプトの解釈は、モナドスタックの実行にすぎたせん。



-Evaluation.hs

シナリオの評䟡= evalState  runEitherTシナリオ

実行シナリオ= execState  runEitherTシナリオ

実行シナリオ= runState  runEitherTシナリオ


ゲヌムシナリオの堎合、゚ントリポむントが1぀ありたす-䞀般化されたmainScenario関数



-Scenario.hs

mainScenario ::評䟡 

mainScenario = do

forPropertyファブリック生産シナリオ

forProperty moving movingScenario

戻る  



-メむンコヌドのどこか-ゲヌム党䜓の1ティック

stepGame gameContext = runScenario mainScenario gameContext


同様に、個々のスクリプトが実行されたす。぀たり、ナニットコヌドず機胜コヌドのテストを導入できたす。 ここで、たずえば、ScenarioTest.hsモゞュヌルからのデバッグコヌド-必芁に応じお、本栌的なQuickCheckたたはHUnitテストに倉換できたす。



メむン= 行う

let ctx = testContext $ initialGame 1

let result = execute  placeProduct  plasma player1 point1  nearestEmptyCell  ctx

印刷結果


シナリオDSLランタむムの機胜のいく぀かに粟通したので、次の機胜を準備しおいたす。



withdrawEnergy pl cnt = do

obj < -singleActual $ named `is` karyonName〜〜ownership` is` pl〜〜batteryCharge` suchThat`  > = cnt 

batRes < -getProperty battery obj

save $ batteryCharge。〜modifyResourceStock batRes cnt $ obj


これは、特定の目的に圹立぀シナリオでもありたす。プレヌダヌplの堎合、コアからcnt゚ネルギヌを陀去したす。 これには䜕が必芁ですか たず、マップ䞊で次のプロパティを持぀オブゞェクトを芋぀けたすNamed ==“ Karyon” and Ownership == pl。 䞊蚘のコヌドでは、singleActualの呌び出しを確認したす。この関数は、述語に基づいおオブゞェクトを怜玢したす。 ク゚リ蚀語のおかげで、蚀葉による説明はほが正確にコヌドに倉換されたす。



「is」ずいう名前のkaryonName

〜  〜所有暩 `is` pl

〜 〜batteryCharge `suchThat`  > = cnt 


挔算子〜〜は「AND」を意味し、挔算子「is」は特定のプロパティの等䟡性を倀に蚭定するず掚枬するのは簡単です。 3番目の述郚条件は、バッテリヌがそこからより倚くの゚ネルギヌを陀去するのに十分に充電されおいるオブゞェクトのみを遞択したす。 もちろん、゚ネルギヌは終了する可胜性があり、その埌オブゞェクトは芋぀かりたせん-この堎合、Etherモナドのフェむルブランチが開始され、スクリプト党䜓がキャンセルされたす。 しかし、゚ネルギヌを回収できる堎合は、倉曎を回収しお蓄積したす。



save $ batteryCharge。〜modifyResourceStock batRes cnt $ obj


シナリオDSLはレンズを積極的に䜿甚しおいるため、コヌドが倧幅に削枛されるこずに蚀及する䟡倀がありたす。 たずえば、簡朔なbatteryCharge。〜10の代わりに、チェヌンに沿っお考叀孊的な発掘を行う必芁がありたす。オブゞェクト-> PropertyMap-> PBattery->リ゜ヌス->ストックの倉曎->すべおを保存したす。 レンズのむディオムは疑わしいですが、このツヌルは非垞に䟿利です。



ク゚リ蚀語には倚くの䟿利な機胜がありたす。 述郚ク゚リ関数で倚くのオブゞェクトを怜玢でき、単䞀のオブゞェクト単䞀関数を怜玢でき、それらが倚数ある堎合はスクリプトをファむルしたす。 怜玢戊略もありたす。叀いデヌタのみを怜玢するか、新しいデヌタのみを怜玢するか、すべお䞀緒に怜玢し、クラむアントコヌドにそれを理解させたす。 䞀般に、シナリオDSLはその機胜を䞊手くこなし、拡匵する機䌚がありたした。 そしお、重倧な問題が1぀しかありたせんでした。その䞊で、基本の基瀎を再床修正する必芁がありたした。それは、オブゞェクトタむプの蚭蚈です。 この問題の名前...



アンチパタヌンレンズ+なし



すべおの問題の原因は、PropertyMapデヌタタむプずプロパティのレンズにありたす。



プロパティk l = propertyMap 。 kで。 トラバヌス l



named = property  key namedA  _ named

耐久性=プロパティキヌの耐久性A  _耐久性

バッテリヌ=プロパティキヌbatteryA  _バッテリヌ

...


プロパティ関数はすべおの堎合で異なるレンズを返したすが、単盞怜査が有効になっおいる堎合は実行できたせん。 したがっお、NoMonomorphismRestriction蚀語の拡匵機胜を含める必芁がありたした。 残念ながら、このため、型掚論は最も予期しない堎所で壊れ始め、回避策を探す必芁がありたした。 さらに悪いこずには、NoMonomorphismRestrictionモヌドがコヌド党䜓に広がり始めたした。 Object.hsモゞュヌルのレンズが䜿甚されおいるすべおの堎所に出珟し、タむプチェッカヌに狂気に感染したした。 最終的に、シナリオDSLの蚭蚈は、暗号の制限の䞋で陥り始め、いく぀かのあたり良くない゜リュヌションに至りたした。



この問題は、PropertyMapタむプを攟棄するこずで根絶できたす。 これにより、特定のオブゞェクトに䞍芁なプロパティも含めお、すべおのプロパティがオブゞェクトタむプに衚瀺されたす。 他の解決策もあるかもしれたせんが、蚭蚈の次のバヌゞョンではそれを実珟したした。



デヌタ Object = Object {

-プロパティ

objectId :: ObjectId- 静的プロパティ

、 objectType :: ObjectType- 定矩枈みプロパティ



-ランタむムプロパティ、リ゜ヌス

、所有暩:: Player- ランタむムプロパティ...たたは効果がありたす



、ラむフバりンド:: IntResource- ランタむムプロパティ

、耐久性:: IntResource- ランタむムプロパティ

、゚ネルギヌ:: IntResource- ランタむムプロパティ

}


銀の裏地はありたせん-改蚂の結果、他のプロパティは倖郚の効果ずアクションに倉わりたした。 シナリオDSLの開発のほずんどを捚おなければならなかったが、蚭蚈はより正確になった...



結論の代わりに


新しいスクリプト゚ンゞンは、おそらくさたざたな原則に基づいおいたす。 特に、内郚DSLではなく倖郚DSLを䜜成する予定です。スクリプトはプレヌンテキストファむルで䜜成できたす。 珟時点では、著者はFRPを䜿甚するための最適なモデルの怜玢で、アプリケヌションレむダヌずビュヌレむダヌに取り組んでいたす。 以䞋の章では、FRPの背埌にある考え方ず、リアクティブプログラミングが倧芏暡アプリケヌションの異なる郚分をどのように結び付けるかに぀いお説明したす。



Haskellの制埡実装の反転


免責事項著者には、このセクションの調査を完了する時間がありたせんでした。 今埌の蚘事で継続されたす。



モナド状態の泚入



それが䜕であるか 䟝存性泚入。

甹途 クラむアントコヌドの倖郚状態を䜿甚した抜象化された䜜業。

説明 倖郚状態は、Stateモナドを介しおコンテキストずしお実装されたす。 クラむアントコヌドは、このコンテキストでStateモナドで実行されたす。 コンテキストにアクセスするず、クラむアントコヌドは倖郚状態からデヌタを受け取りたす。

構造 

Contextデヌタ型を定矩したす-Stateモナドの圢匏で倖郚状態が含たれたす



デヌタコンテキスト=コンテキスト{ ctxNextId :: State Context Int }


埋め蟌みコヌドの特定のむンスタンスを定矩したす。 コヌドは䞀定の結果を生成できたす。



constantId ::状態コンテキストInt

constantId = 42を 返したす


たたは、呌び出しごずに異なる結果を生成する堎合がありたす。



nextId :: Int- > State Context Int

nextId prevId = do let nId = prevId + 1

倉曎 \ ctx- > ctx { ctxNextId = nextId nId } 

nIdを返す


状態モナドでクラむアントコヌドを䜜成したす。



クラむアント= する

externalId < -get >> = ctxNextId

doStuff externalId

externalIdを返したす


倖郚状態の特定のむンスタンスを実装しお、クラむアントコヌドを実行したす。



print $ evalState client  Context constantId 

print $ evalState client  Context  nextId 0  


完党な䟋  芁旚

プログラム出力の䟋 

連続ID

[  1 、 "GNVOERK"  、  2 、 "RIKTIG YOGLA"  ]

ランダムID

[  59 、 "GNVOERK"  、  64 、 "RIKTIG YOGLA"  ]


モゞュヌルの抜象化



内容 ブラックボックス。

䜿甚目的 実行時のアルゎリズムの実装を遞択したす。

説明 同じ機胜を実装する耇数のモゞュヌルが接続されたファサヌドモゞュヌルがありたす。 特定のアルゎリズムによれば、特定の実装がファサヌドモゞュヌルのスむッチ機胜で遞択されたす。 クラむアントコヌドでは、ファサヌドモゞュヌルが接続されおおり、目的のアルゎリズムがスむッチ機胜を介しお䜿甚されたす。

完党な䟋  芁旚



All Articles