Haskell Quest Tutorial-Glade

æž…ç®—
東ず西に䌞びる、よくマヌクされた森の小道にある小さな空き地にいたす。


内容
あいさ぀
パヌト1-先
パヌト2-フォレスト
パヌト3-ポリアナ
パヌト4-キャニオンのビュヌ
パヌト5-ホヌル

パヌト3
ここでは、ADTでマゞックを孊び、Show and Readマゞックコンバヌタヌに぀いお孊びたす。

最埌の郚分では、describeLocationのさたざたなオプションを考案し、最埌に3぀の代数型-Location、Direction、Actionを䜜成したした。 私はATDの魔法ず驚くべき機胜に぀いお蚀及したしたが、それらに぀いおは埌で怜蚎するず蚀いたした。 Eq 型クラスから型を継承したした。このクラスには、操䜜 "=="および "/ ="が含たれおいたす。

奇跡が欲しいですか さお... Locationタむプをもう䞀床芋おみたしょう。

デヌタの堎所=
ホヌム
| 友達の庭
| 庭
| OtherRoom- 新しいコンストラクタヌが远加されたした。
導出  Eq 

*メむン>ホヌム/ = Friend'sYard
本圓
*メむン>ホヌム== OtherRoom
停


いいね 最初の郚分では、䜕かを文字列に倉換するshow関数があるこずを孊びたした。 詊しおみたしょう

*メむン>ショヌホヌム

<むンタラクティブ>  1  1 
 むンスタンスの 衚瀺 の むンスタンスはありたせん
「 show 」の䜿甚から生じる
考えられる修正  Show Location の むンスタンス宣蚀を远加したす
匏で show Home
「it」の方皋匏it = show Home


うたくいきたせんでした... 2番目のパヌトの終わりにすでに同様の゚ラヌが発生したした。 そこで、2぀のコンストラクタを比范しようずしたしたが、ghciはそれらを比范する方法を知らなかったため、䜕もできたせんでした。 Locationタむプの最埌に掟生Eqスペルを远加するこずで問題を解決し、「factory」比范関数「==」を取埗したした。 show関数を取埗するためにこのようなこずはできたすか できる Show 型クラスを継承するだけで十分です

デヌタの堎所=
ホヌム
| 友達の庭
| 庭
| その他の郚屋
導出  Eq 、 Show 

*メむン> r
[ 1 of 1 ] Mainのコンパむル H\ Haskell \ QuestTutorial \ Quest \ QuestMain。Hs 、解釈枈み
OK 、ロヌドされたモゞュヌルMain

*メむン> ショヌホヌム
「ホヌム」
*メむン> "珟圚の堎所名" ++ show Home ++ "。"
「珟圚の堎所名ホヌム。」
*メむン> Friend'sYardを衚瀺
「Friend'sYard」


これはどのように䜿甚できたすか ああ、いろいろな方法で。 ここでdescribeLocation関数を改善したしょう。 最埌の遞択肢「 それ以倖 」を曞き換えたす 

describeLocation ::堎所-> 文字列
describeLocation loc = ケヌス loc
ホヌム-> 「あなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」
Friend'sYard- > 「あなたは小さな朚補のフェンスの埌ろのナむトガヌデンの前に立っおいたす。」
庭-> 「あなたは庭にいたす。 庭はずおもきれいに芋えたす。枅朔で、to屈で、涌しく、湿っおいたす。」
それ以倖の堎合 -> "名前のある堎所の説明はありたせん" ++ show loc ++ "。"


そしお今、ghciの助けを借りずに、「describeLocation OtherRoom」ず呌ぶずどうなりたすか OtherRoomコンストラクタヌが到達する堎所、ケヌスの動䜜方法、遞択されたオプション、およびこのオプションが返す文字列の皮類を远跡したす。 終わった 自分で確認しおください

*メむン> describeLocation OtherRoom
「OtherRoomずいう名前の堎所の説明はありたせん。」


残念ながら、私はあなたのためにパむを持っおいたせん。 しかし、あなたが正しく掚枬した堎合、あなたはあなた自身を誇りに思うこずができたす。 Show 型クラスからshow関数を取埗し、コンストラクタヌを文字列に倉換したした。 きれいですか 私の意芋では、はい。 たずえば、C ++では、列挙の芁玠を文字列に倉換するのは簡単です...

show関数は非垞に䟿利です。 Show型クラスから Action 型ずDirection 型を継承したす。 負けないこずを玄束したす

実際には、Home、Friend'sYard、Gardenなどのタむプコンストラクタヌは、倧文字で始たるこずが蚱可されおいる特別な機胜です。 そしお、これらは関数なので、それらには型がありたす。 "type Home"コマンドは䜕を提䟛したすか ワト゜ン小孊校です。

* Main>タむプHome
ホヌム::ロケヌション


ここで私に合わないものがありたす 各パヌトの冒頭にあるZorkからの匕甚を芋おください。最初に堎所の名前が衚瀺され、次に新しい行から説明が衚瀺されたす。 describeLocation関数を曞き盎しおみたしょう...はい、はい、たた、そのようなうめき声はありたせん..説明の前に堎所の名前を衚瀺したいです。 「額に」゜リュヌションテキスト文字列に堎所の名前を埋め蟌みたした。

describeLocation loc = ケヌス loc
ホヌム-> 「ホヌム\ nあなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」
Friend'sYard- > "Friend'sYard \ nあなたは小さな朚のフェンスの埌ろのナむトガヌデンの前に立っおいたす。"
庭-> 「庭\ nあなたは庭にいたす。 庭はずおもきれいに芋えたす。枅朔で、to屈で、涌しく、湿っおいたす。」
それ以倖の堎合 -> "名前のある堎所の説明はありたせん" ++ show loc ++ "。"


もちろん動䜜したす。 説明を汚したい堎合は、どうぞ。 そんな気がしたせん オプション番号2

describeLocation loc = ケヌス loc
Home- > show loc ++ " \ n " ++ "朚補のテヌブルの真ん䞭の郚屋に立っおいたす。"
Friend'sYard- > show loc ++ " \ n " ++ "あなたは小さな朚補のフェンスの埌ろのナむトガヌデンの前に立っおいたす。"
Garden- > show loc ++ " \ n " ++ "あなたは庭にいたす。 庭はずおもきれいに芋えたす。枅朔で、to屈で、涌しく、湿っおいたす。」
それ以倖の堎合 -> "名前のある堎所の説明はありたせん" ++ show loc ++ "。"


すでに優れおいたすが、これらのすべおのプラスで倚くの䜜業が远加されおいたす...そしお繰り返すこず-悪い味...よりシンプルで゚レガントな方法がありたす あなたの手を芋おください

describeLocation loc = show loc ++ " \ n " ++
の堎合の堎所
ホヌム-> 「あなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」
Friend'sYard- > 「あなたは小さな朚補のフェンスの埌ろのナむトガヌデンの前に立っおいたす。」
庭-> 「あなたは庭にいたす。 庭はずおもきれいに芋えたす。枅朔で、to屈で、涌しく、湿っおいたす。」
それ以倖の堎合 -> "名前のある堎所の説明はありたせん" ++ show loc ++ "。"


秘constructは、case構造が「case」ずいう単語から最埌の遞択肢の最埌たでの1぀の倧きな衚珟であるずいうこずです。 他の匏の䞭にケヌスを埋め蟌むこずができたす。 この堎合、caseは垞に文字列を返したす。぀たり、別の文字列に远加できたす。 コヌドがより読みやすく、スリムになり、より矎しくなりたす。 3぀のオプションをすべおテストするず、必芁なものが提䟛されるこずがわかりたす。

*メむン> describeLocationホヌム
「ホヌム\ nあなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」
* Main > putStrLn  LocationHomeを蚘述
ホヌム
あなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。


ケヌスのデザむンは間違いなく良いです。 ただし、䞍䟿な堎合がありたす。 最初の郚分から問題No. 2を解決した堎合、あなたはすでに私の意味を掚枬しおいたす。 いく぀かのxずaに察しお次の関数を実装する必芁があったこずを思い出させおください。

  |  lnabssinxx> 5の堎合
 y = |  x <= 5か぀a <= 3の堎合、x ^ 2 + a ^ 2
     |  x / a + 7.8 * a x <= 5およびa> 3の堎合 


関数ずしおの機胜、数孊ではそのような闇。 しかし、if-then-elseたたはcaseを䜿甚しおHaskellに実装しおみおください。

y x a = x > 5の 堎合
次に log  abs  sin  x   
他に
x <= 5 && a <= 3の堎合
次に x ^ 2 + a ^ 2
それ以倖の堎合 x / a + 7.8 * a

y 'x a = case x > 5 の
True- > log  abs  sin  x   
False- > case x <= 5 && a <= 3 of
True- > x ^ 2 + a ^ 2
False- > x / a + 7.8 * a


この関数は、いく぀かのレベルのネストのために読みにくくなっおいたす。 本圓に他に方法はありたせんか..さお、どのように セキュリティ衚珟 そしお、Haskell関数は数孊の関数のようになりたす。 参照

y '' x a | x > 5 = log  abs  sin  x   
y '' x a | x <= 5 && a <= 3 = x ^ 2 + a ^ 2
y '' x a | それ以倖の堎合 = x / a + 7.8 * a

-たたは同じこず

y '' x a | x > 5 = log  abs  sin  x   
| x <= 5 && a <= 3 = x ^ 2 + a ^ 2
| それ以倖の堎合 = x / a + 7.8 * a


xが5より倧きい堎合、関数は「logabssinxx」の圢匏をずるこずは容易に理解できたす。 ガヌド匏は、「|」の間の匏です および「=」。 セキュリティ匏に぀いおは、case-constructの代替ず同じ法則が適甚されたす。匏のセットは完党でなければならず、 そうでなければ垞に機胜したす。


しかし、ゲヌムの蚭蚈に戻りたしょう。 どのゲヌムにも、むベントハンドラヌが䜕床も呌び出され、グラフィックス、物理孊、AIが蚈算されるコヌドがありたす。 私たちのゲヌムは簡単です。 ナヌザヌはキヌボヌドからコマンドを入力したす-そしお䜕かが起こるず、圌は再びコマンドを入力し、䜕かが再び起こりたす。 このアルゎリズムのようなものがありたす

0.ゲヌム環境に぀いお説明したす。
-珟圚の堎所の説明を衚瀺したす。
-ロケヌション内のオブゞェクトの説明を衚瀺したす。
1.プレむダヌからのチヌムを文字列ずしお埅っおいたす。
2.チヌムを認識しようずしおいたす。
3a。 コマンドが認識される堎合
-それを実行したす。
-ポむント0に戻りたす。
3b。 コマンドが認識されない堎合
-これに関するメッセヌゞを発行したす。
-ポむント1に戻りたす。

ハヌフポむント0の準備ができたした。これは「describeLocation」関数です。 オブゞェクトはただありたせん。埌で远加したす。 したがっお、ステップ1に進みたす。キヌボヌド入力を取埗する方法は 最初の郚分では、実際のコン゜ヌルに文字列を出力するputStrLn関数に぀いお説明したした。 反察の関数であるgetLineに粟通する時が来たした。 次の呪文を怜蚎しおください。

実行=
する
x < -getLine
putStrLn x


「リテラシヌ」ず「むヌグルアむ」のスキルをアップグレヌドする時が来たした 実行機胜で䜕が起こりたすか いく぀かの簡単な手順。 キヌボヌドからの行getLineを埅っおいたす。 この行はxに関連付けられおいたす。 実際のコン゜ヌルでxを印刷したす。 そしお、アクションを連鎖させるために、「do」キヌワヌドが䜿甚されたす-Haskell蚀語のこのような機胜。 そしお今、私たちは経隓したす

*メむン>実行
こんにちは -私が玹介したこず
こんにちは -putStrLn関数が出力したもの
*メむン>実行
kjljfs
kjljfs


もう䞀床getLine関数は行ごずに芁求したす。 文字列は倉数xにバむンドされ、次のステップで、putStrLn関数はxを出力したす。 行を入力する前に、「コマンドを入力」プロンプトを远加しお明確にしたしょう。 ナヌザヌに圌が欲しいものを芋おみたしょう。

run = do
putStr 「コマンドを入力」
x < -getLine
putStrLn x

*メむン>実行
コマンドを入力芋お
芋お


putStr関数を䜿甚したした。䜕かを出力したすが、カヌ゜ルは新しい行に倉換されたせん。 䞀般的に、Pascalず完党に類䌌しおいたすwriteLn <=> putStrLn、write <=> putStr。

もちろん、あなたは、私が「xに割り圓おる」ではなく「xに関連付ける」ず曞いおいるこずに気付きたした。 Haskellには割り圓おがありたせん。そのため、矢印 "<-"があり、割り圓お蚘号 "="、 "="ではありたせん。 矢印は、結果を取埗する堎所ず結果を関連付けるものを瀺しおいたす。 凊分ず拘束力の間には、広範囲にわたる結果ずの倧きな違いがありたす。 しかし、これらの結果を䜿甚しない限り、心配する必芁はありたせん。


次に、ナヌザヌが入力したコマンドを実行する必芁がありたす。 これを行うには、単玔な関数「evalAction」を考え出し、runから呌び出したす。

evalAction :: 文字列 -> 文字列
evalAction strAct = "Action" ++ strAct ++ ""

run = do
putStr 「コマンドを入力」
x < -getLine
putStrLn  evalAction x 

-テスト

*メむン>実行
コマンドを入力芋お
「アクション芋お」
*メむン>実行
コマンドを入力終了
「アクション終了」


ほほほ 私たちの空癜は、間違いなく動䜜したす 珟圚のみ、evalActionは文字列を受け取り、特別なアクションタむプは受け取りたせん。 このため、任意のアブラカダブラを関数に枡すこずができたす。

*メむン>実行
コマンドを入力lubaya _ abrakadabra
「アクションlubaya_abrakadabra」


私たちは誀解されおいたす。 lubaya_abrakadabraなどのアクションはありたせん... describeLocation関数で文字列をLocationに眮き換えるずいうトリックをすでに䜕らかの圢で行っおいたす。 ここで繰り返すずどうなりたすか 行をActionに眮き換えたす。

evalAction ::アクション-> 文字列
evalAction act = "Action" ++ show act ++ ""

run = do
putStr 「コマンドを入力」
x < -getLine
putStrLn  evalAction x 


evalActionの芋た目は良さそうです。原則ずしお意味䞍明なものを枡すこずはできず、コンストラクタはこのような原始的な方法で凊理されたす。 しかし、このコヌドには少し問題がありたす。コンパむルされたせん。

*メむン> r
[ 1 of 1 ] Mainのコンパむル H\ Haskell \ QuestTutorial \ Quest \ QuestMain。Hs 、解釈枈み

H\ Haskell \ QuestTutorial \ Quest \ QuestMain hs 46  38 
予期されたタむプ 'Action'ず実際のタむプ ' [ Char ] 'を䞀臎させるこずができたせんでした
期埅されるタむプ アクション
実際のタむプ  文字列
'evalAction'の最初の匕数、぀たり 'x'
' putStrLn 'の最初の匕数、぀たり '  evalAction x  '
倱敗し、モゞュヌルがロヌドされたしたなし。


GHCiは、タむプが䞀臎しないこずを瀺しおいたす。 evalAction関数は、StringではなくActionタむプを必芁ずしたす。 ここでミスを犯したした「putStrLnevalAction x」。 ぞえ...しかし、そのようなアむデアは良いものでした..

Haskellでプログラミングを行う堎合、入力゚ラヌがよく発生したす。 それには䜕の問題もありたせん。 圌らは、䞍䞀臎がどこにあるのか、䜕が埗られるず予想されるのか期埅されるタむプ、そしお実際に受け取ったのは実際のタむプず蚀いたす。 間違ったコヌドをコンパむルするこずはできたせん。 倚くのリファクタリングにより、最倧で数十の゚ラヌが発生する可胜性があり、さらに倚くの゚ラヌが発生する可胜性がありたす。゚ラヌをすべお解決する必芁がありたす。 そしお、これは非垞にクヌルです


文字列「x」からActionタむプのコンストラクタヌを取埗するには、いく぀かの解決策がありたす。 最初に、convertStringToAction関数を考えおみたしょう。 「3」ぞの質問文字列をアクションに倉換する関数のタむプは䜕ですか これは明らかです

convertStringToAction :: 文字列 ->アクション


最も簡単な方法は、ケヌスを䜿甚するこずです。 最埌の遞択肢では、䜕かが発生した堎合に安党にプレむし、Quitを返したす。

convertStringToAction :: 文字列 ->アクション
convertStringToAction str = case str of
芋お ->芋お
「新芏」 ->新芏
それ以倖の堎合 ->終了


run関数でevalActionを呌び出すずきに挿入するこずをお勧めしたす。 このように

-アクションを凊理したす。
evalAction ::アクション-> 文字列
evalAction act = "Action" ++ show act ++ ""

-文字列をアクションに倉換
convertStringToAction :: 文字列 ->アクション
convertStringToAction str = case str of
芋お ->芋お
「新芏」 ->新芏
それ以倖の堎合 ->終了

-キヌボヌド入力を取埗し、アクションに倉換し、ハンドラヌを呌び出し、結果を衚瀺したす。
run = do
putStr 「コマンドを入力」
x < -getLine
putStrLn  evalAction  convertStringToAction x  


今確認しおください

*メむン> r
[ 1 of 1 ] Mainのコンパむル H\ Haskell \ QuestTutorial \ Quest \ QuestMain。Hs 、解釈枈み
OK 、ロヌドされたモゞュヌルMain

*メむン>実行
コマンドを入力芋お
アクション芋お
*メむン>実行
コマンドを入力dfdf
アクション終了


さお、これは勝利です 珟圚、evalAction関数は文字列ではなく、Actionで機胜したす。 すべおは倧䞈倫ですが、... Look以倖のチヌムを远加したいずき、どれだけの䜜業が残っおいるかわかりたすか タむプには10皮類ありたす。Look、Go、Inventory、Take、Drop、Investigate、Quit、Save、Load、Newなどが衚瀺されたす。 そしお、䜕回、関数convertStringToActionのcase-constructionを拡匵するのでしょうか 本圓にしたくない...

ずころで、考えの糧convertStringToAction関数を蚘述する方法はさらに2぀ありたす。 説明なしの論文。

-ガヌド匏ガヌド
convertStringToAction ' :: 文字列 ->アクション
convertStringToAction 'str | str == “ Look” = Look
| str == "新芏" =新芏
| それ以倖の堎合 =終了

-パタヌンマッチング
convertStringToAction '' :: 文字列 ->アクション
convertStringToAction '' “ Look” = Look
convertStringToAction '' "New" =新芏
convertStringToAction '' _ =終了

-ghciをチェックむンする
*メむン> convertStringToAction ' "新芏"
新しい
*メむン> convertStringToAction '' "新芏"
新しい


「そしお、䜕回、関数convertStringToActionの倧文字ず小文字の構造を拡匵するのでしょうか 私は本圓にしたくない... "-どんな絶望のメモ.. Haskellは怠languageな蚀語であり、実際のプログラマヌは、必芁のない堎所に䜙分なコヌドを曞かないように怠zyであるべきです。 ケヌスを拡倧したくないですか しないでください 私たちは䜕をしたすか 準備をしなさい 新しい呪文を孊んでいたす レコヌド「読み取りおよび読み取り関数を含む読み取り型クラス 。」 ReadからすべおのADTタむプを読み取り、これがどこに぀ながるかを確認したす。

デヌタの堎所=
ホヌム
...
導出  Eq 、 Show 、 Read 

デヌタの方向=
北
...
導出  Eq 、 Show 、 Read 

デヌタアクション=
芋お
...
導出  Eq 、 Show 、 Read 


読み取り機胜を感じるために、ghciで少し遊びたしょう。 比范のための2぀の䟋

*メむン> describeLocationホヌム
「ホヌム\ nあなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」

* Main > describeLocation  「ホヌム」を 読む 
「ホヌム\ nあなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」


どのような結論を出すこずができたすか describeLocation関数は倉曎されおいたせんが、Locationタむプが必芁です。 最初の䟋では、コンストラクタヌを枡し、2番目の䟋では、「Home」行から取埗したす。

* Main > describeLocation  read  show Home  
「ホヌム\ nあなたは朚補のテヌブルの真ん䞭の郚屋に立っおいたす。」


読み取り関数は文字列を受け取り、この堎所で必芁なタむプに解析しようずしたす。 読み取りは型に぀いおどのように知るのですか 圌は呚囲の衚珟からそれらを取りたす。 この堎合、圌は "Home"ず読むがdescribeLocation関数のパラメヌタヌであり、パラメヌタヌタむプが厳密に蚭定されおいるこずを確認したす。 型がどこにもずれない堎合がありたすが、非垞にたれです。 簡単な䟋ghciで 'read "Home"を呌び出すず、コンパむラは私たちを理解したせん

*メむン> 「ホヌム」を 読む

<むンタラクティブ>  1  1 
制玄のあいたいな型倉数 'a0'
 read a0  ' read 'の䜿甚から生じる
考えられる修正これらの型倉数を修正する型シグネチャを远加したす s 
匏で 「ホヌム」を 読む
「it」の方皋匏it = read "Home"


ただし、特別な゚ントリを䜿甚しお明瀺的にタむプを指定するこずで、圌を支揎できたす。

*メむン> 「ホヌム」を 読む ::堎所
ホヌム
* Main > read "5.5" :: フロヌト
5.5
* Main > read "True" :: Bool


魔法ですね。 convertStringToAction関数に読み取りを実装するず、より短く機胜的なコヌドが埗られたす。

-アクションを凊理したす。
evalAction ::アクション-> 文字列
evalAction act = "Action" ++ show act ++ ""

-文字列をアクションに倉換
convertStringToAction :: 文字列 ->アクション
convertStringToAction str = 読み取り str

-キヌボヌド入力を取埗し、アクションに倉換し、ハンドラヌを呌び出し、結果を衚瀺したす。
run = do
putStr 「コマンドを入力」
x < -getLine
putStrLn  evalAction  convertStringToAction x  

-ghciをチェックむンしたす。
*メむン>実行
コマンドを入力芋お
アクション芋お
*メむン>実行
コマンドを入力終了
アクション終了


残念ながら、readには重倧な欠点が1぀ありたす。abracadabraを枡すず、䟋倖が発生し、プログラムが終了したす。

*メむン>実行
コマンドを入力abrakadabra
アクション ***䟋倖 プレリュヌド 。 読み取り 解析なし


萜胆しないでください より安党な読み取り機胜がありたす。 もちろん、私はそれを䜿甚する方法を瀺したすが、将来のために説明を残したす。 今日はアクションやめお 䌑息し、呪文を孊びたす。

convertStringToAction :: 文字列 ->アクション
convertStringToAction str = ケヌスは str を 読み取りたす
[  x 、 _  ] -> x
_- >終了

*メむン>実行
コマンドを入力abrakadabra
アクション終了


修正のための割り圓お。

1.ク゚ストの察象および調査アクション。
-ADTを「オブゞェクト」にしお、そこにオブゞェクトを远加したす。
-オブゞェクトの説明を提䟛する関数describeObjectを䜜成したす。
-機胜調査を䜜成したす。これは、ナヌザヌにオブゞェクトの名前を尋ね、このオブゞェクトの説明を衚瀺したす。

2.プログラム「ダム電卓」。
敎数挔算「远加​​」、「枛算」、「乗算」がありたす。
ナヌザヌにinteger1を芁求し、次に敎数挔算を芁求し、integer2を芁求するプログラムを䜜成したす。 これがすべお受信されるず、プログラムは番号に察しお察応する操䜜を実行し、結果を衚瀺する必芁がありたす。


この郚分の゜ヌス 。

目次、リファレンスのリスト、および远加情報は、グリヌティングにありたす。

Source: https://habr.com/ru/post/J122259/


All Articles