Learn You a Haskellの本を読んで、モナドやJust aなどを紹介しています。これらは私にとって非常に直観に反しているので、それを学ぼうとするのをあきらめたいだけです。
しかし、私は本当に試してみたいです。
少なくともしばらくは高度な概念を避けて、言語の他の部分を使い始めて、Haskellのより基本的な部分、つまり関数、標準IO、ファイル処理、データベースのインターフェースなど。
これはHaskellの使用方法を学ぶための合理的なアプローチですか?
Learn You a Haskellの本を読んで、モナドやJust aなどを紹介しています。これらは私にとって非常に直観に反しているので、それを学ぼうとするのをあきらめたいだけです。
しかし、私は本当に試してみたいです。
少なくともしばらくは高度な概念を避けて、言語の他の部分を使い始めて、Haskellのより基本的な部分、つまり関数、標準IO、ファイル処理、データベースのインターフェースなど。
これはHaskellの使用方法を学ぶための合理的なアプローチですか?
回答:
最初に、抽象概念の学習とそれらの特定の例の学習を区別しましょう。
それらが完全に遍在しているという単純な理由のために、すべての特定の例を無視することはあまりありません。実際、抽象化の大部分は、特定の例で実行することを統一するために存在します。
一方、抽象化自体は確かに有用ですが、すぐに必要なわけではありません。抽象化を完全に無視して、さまざまなタイプを直接使用するだけでかなり遠くまで到達できます。最終的にそれらを理解する必要がありますが、後でいつでも戻ってくることができます。実際、それを行うと、戻ったときに額を平手打ちし、なぜ便利な汎用ツールを使用するのではなく、なぜすべての時間を苦労して費やしたのか疑問に思うでしょう。
Maybe a
例として取り上げます。これは単なるデータ型です。
data Maybe a = Just a | Nothing
それはすべて自己文書化です。これはオプションの値です。タイプの何かを「ただ」持っているかa
、何もありません。ある種のルックアップ関数があるとします。これは、存在しない可能性のMaybe String
あるString
値のルックアップを表すために戻ります。したがって、値をパターンマッチして、それがどれであるかを確認します。
case lookupFunc key of
Just val -> ...
Nothing -> ...
それで全部です!
本当に、他に必要なものは何もありません。Functor
sまたはMonad
sまたはその他のものはありません。これらはMaybe a
値を使用する一般的な方法を表します...しかし、それらはただのイディオム、「デザインパターン」、あなたがそれを呼びたいかもしれません。
あなたが本当にそれを完全に避けることのできない一つの場所はであるがIO
、それはとにかく不思議なブラックボックスなので、それが何を意味するのかを理解しようとする価値はないMonad
。
実際、ここであなたが本当に知る必要があるすべてのチートシートがありますIO
:
何かにtypeがある場合IO a
、それは何かを実行してa
値を吐き出す手続きであることを意味します。
do
表記法を使用したコードブロックがある場合、次のように記述します。
do -- ...
inp <- getLine
-- etc...
...は、の右側にあるプロシージャを実行<-
し、左側の名前に結果を割り当てることを意味します。
一方、次のようなものがある場合:
do -- ...
let x = [foo, bar]
-- etc...
...これは、(式ではなく)プレーン式の値を=
、左側の名前の右側に割り当てることを意味します。
次のように、値を割り当てずにそこに何かを置くと:
do putStrLn "blah blah, fishcakes"
...プロシージャを実行し、それが返すものをすべて無視することを意味します。いくつかの手順では、タイプしていIO ()
--the ()
タイプがソートだけで手続きが何かを意味し、値を返さないように、何も言っていないプレースホルダのですが。void
他の言語の関数のようなもの。
同じ手順を複数回実行すると、異なる結果が得られる場合があります。それは一種のアイデアです。これがIO
、値から「削除」する方法がない理由です。なぜなら、中の何かIO
は値ではなく、値を取得するための手順だからです。
do
ブロックの最後の行は、割り当てのない単純なプロシージャである必要があります。そのプロシージャの戻り値は、ブロック全体の戻り値になります。既に割り当てられている値を戻り値に使用する場合、return
関数は単純な値を取り、その値を返す操作なしの手順を提供します。
それ以外、特別なことは何もありませんIO
。これらのプロシージャ自体は実際には単純な値であり、それらを渡したり、さまざまな方法で組み合わせたりすることができます。do
どこかで呼ばれたブロックで実行された場合にのみ、main
何もしません。
したがって、このまったくつまらない、典型的なプログラム例のようなものでは:
hello = do putStrLn "What's your name?"
name <- getLine
let msg = "Hi, " ++ name ++ "!"
putStrLn msg
return name
...命令型プログラムのようにそれを読むことができます。という名前のプロシージャを定義していますhello
。実行されると、まずプロシージャを実行して、名前を尋ねるメッセージを出力します。次に、入力行を読み取り、結果をname
;に割り当てるプロシージャを実行します。次に、名前に式を割り当てmsg
ます。その後、メッセージを出力します。次に、ブロック全体の結果としてユーザーの名前を返します。ためname
でありString
、この手段は、そのhello
返す手続きであるString
、それは型を持つように、IO String
。そして、このプロシージャを実行するように、他の場所でこのプロシージャを実行できますgetLine
。
Pfff、モナド。誰が必要ですか?
ほとんどの日常的なプログラミング作業において、モナドや応用ファンクターなどのHaskellの高度なコンセプトはどれほど重要ですか?
それらは不可欠です。それらがなければ、Haskellを単なる別の命令型言語として使用するのは非常に簡単です。SimonPeyton Jonesはかつて「世界最高の命令型プログラミング言語」と呼ばれるHaskellでしたが、依然として最良の部分を逃しています。
モナド、モナド変換、モノイド、ファンクター、適用ファンクター、反変ファンクター、矢印、カテゴリーなどが設計パターンです。作成した特定のものをそれらの1つに適合させると、抽象的に記述された膨大な機能を利用することができます。これらのタイプクラスは、単に混乱させるためだけに存在するのではなく、あなたの人生をより簡単にし、生産性を高めるために存在します。私の意見では、これらが良いHaskellコードの簡潔さの最大の理由です。
何かを実行したいだけなら絶対に必要ですか?番号。
美しい慣用的なHaskellプログラムを書きたい場合は必要ですか?絶対に。
Haskellでプログラミングする場合、次の2つのことを念頭に置くと役立ちます。
型システムはあなたを助けるためにあります。非常に多態的なtypeclass-heavyコードからプログラムを作成すると、たいていの場合、必要な関数のタイプが(1つの!)正しい実装に導かれるという素晴らしい状況に陥ります。
利用可能なさまざまなライブラリは、原則#1を使用して開発されました。
そのため、Haskellでプログラムを作成するときは、型を作成することから始めます。次に、最初からやり直して、より一般的な型を書き留めます(既存の型クラスのインスタンスにできる場合は、それでもなお良いです)。次に、必要な型の値を取得する関数をいくつか作成します。(それから私はそれらで遊んでghci
、おそらくいくつかのquickCheckテストを書きます。)そして最後にすべてを一緒に接着しmain
ます。
何かを実行するだけのいHaskellを書くことは可能です。しかし、その段階に到達したら、学ぶべきことがたくさんあります。
幸運を!