diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml index de22af42..bbf452a3 100644 --- a/.github/workflows/mdbook.yml +++ b/.github/workflows/mdbook.yml @@ -4,7 +4,7 @@ on: push: branches: [ja] # branches: [master] - pull_request: + # pull_request: jobs: deploy: diff --git a/.po4a-version b/.po4a-version index 710dfe7d..a5f31293 100644 --- a/.po4a-version +++ b/.po4a-version @@ -1,4 +1,4 @@ -po4a version 0.68. +po4a version 0.69. Written by Martin Quinson and Denis Barbier. Copyright © 2002-2022 Software in the Public Interest, Inc. diff --git a/.textlintrc.json b/.textlintrc.json index 62a53392..f71270f5 100644 --- a/.textlintrc.json +++ b/.textlintrc.json @@ -5,10 +5,15 @@ }, "preset-ja-technical-writing": { "ja-no-mixed-period": { - "allowPeriodMarks": ["、", "…"] + "allowPeriodMarks": [ + "、", + "…" + ] }, "ja-no-successive-word": { - "allow": ["…"] + "allow": [ + "…" + ] }, "ja-no-weak-phrase": false, "max-kanji-continuous-len": { @@ -34,7 +39,8 @@ "配列内包表記", "配列型構築子", "関数合成演算子", - "領域特化言語" + "領域特化言語", + "可変参照領域" ] }, "no-doubled-joshi": false, @@ -42,7 +48,17 @@ "allowHalfWidthExclamation": true, "allowFullWidthExclamation": true }, - "sentence-length": false + "sentence-length": false, + "ja-no-redundant-expression": { + "dictOptions": { + "dict6": { + "allows": [ + "動作を実行", + "プログラムを実行" + ] + } + } + } } } } diff --git a/CONTRIBUTING.ja.md b/CONTRIBUTING.ja.md new file mode 100644 index 00000000..1f1b55b1 --- /dev/null +++ b/CONTRIBUTING.ja.md @@ -0,0 +1,15 @@ +# 貢献 + +本書で何かしら改善になるものを見付けたらPRやイシューを開いてください。 + +フィードバックに感謝します。 + +## 章のテキストを編集する + +テキストの変更をローカルで見てみるには、[mdbook](https://github.com/rust-lang/mdBook)をインストールし、以下のコマンドをリポジトリのルートで走らせます。 + +```sh +mdbook serve -o +``` + +readmeファイルへの変更毎に描画されたwebページが自動的に再読み込みされます。 diff --git a/manifest.scm b/manifest.scm index 27fd07e1..adbbe998 100644 --- a/manifest.scm +++ b/manifest.scm @@ -1,5 +1,4 @@ (use-modules (gnu packages node) - (gnu packages gettext) - (gemmaro packages mdbook)) + (gnu packages gettext)) -(packages->manifest (list node-lts po4a mdbook)) +(packages->manifest (list node-lts po4a)) diff --git a/po4a.cfg b/po4a.cfg index 2e602bc2..44f1b5bd 100644 --- a/po4a.cfg +++ b/po4a.cfg @@ -56,3 +56,6 @@ [type:text] text/chapter9.md \ $lang:text-ja/chapter9.md + +[type:text] CONTRIBUTING.md \ + $lang:CONTRIBUTING.ja.md diff --git a/text-ja/chapter1.md b/text-ja/chapter1.md index d1c29a4a..632284a6 100644 --- a/text-ja/chapter1.md +++ b/text-ja/chapter1.md @@ -35,29 +35,33 @@ - [React](https://reactjs.org)や[virtual-dom](https://github.com/Matt-Esch/virtual-dom)などのライブラリは、アプリケーションの状態についての純粋な関数としてその外観をモデル化しています -関数は単純な抽象化を可能にし、優れた生産性をもたらしてくれます。 +関数は大幅な生産性の向上をもたらしうる単純な抽象化を可能にします。 しかし、JavaScriptでの関数型プログラミングには欠点があります。 -JavaScriptは冗長で、型付けされず、強力な抽象化を欠いているのです。 -また、無秩序に書かれたJavaScriptコードでは、等式推論がとても困難です。 +JavaScriptは冗長で、型付けされず、強力な抽象化の形式を欠いているのです。 +また、野放図なJavaScriptコードは等式推論がとても困難です。 -PureScriptはこのような問題を解決すべく作られたプログラミング言語です。 -PureScriptは、とても表現力豊かでありながらわかりやすく読みやすいコードを書けるようにする、軽量な構文を備えています。 -強力な抽象化を提供する豊かな型システムも採用しています。 +PureScriptはこうした課題への対処を目指すプログラミング言語です。 +PureScriptは軽量な構文を備えていますが、この構文によりとても表現力豊かでありながら分かりやすく読みやすいコードが書けるのです。 +強力な抽象化を支援する豊かな型システムも採用しています。 また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに重要な、高速で理解しやすいコードを生成します。 -PureScriptを一言で言えば、純粋関数型プログラミングの理論的な強力さと、JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語だということを理解して頂けたらと思います。 +概してPureScriptとは、純粋関数型プログラミングの理論的な強力さと、JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語だということを理解して頂けたらと思います。 + +> なお、PureScriptはJavaScriptのみならず他のバックエンドを対象にできますが、本書ではwebブラウザとnode環境に焦点を絞ります。 ## 型と型推論 -動的型付けの言語と静的型付けの言語をめぐる議論についてはよく知られています。PureScriptは*静的型付け*の言語、つまり正しいプログラムはコンパイラによってその動作を示すような*型*を与えられる言語です。逆にいえば、型を与えることができないプログラムは -_誤ったプログラム_ -であり、コンパイラによって拒否されます。動的型付けの言語とは異なり、PureScriptでは型は*コンパイル時*のみに存在し、実行時には型の表現はありません。 +動的型付けの言語と静的型付けの言語をめぐる議論については充分に文書化されています。 +PureScriptは*静的型付け*の言語、つまり正しいプログラムはコンパイラによって*型*を与えられる言語です。 +またこの型は、その動作を示すものです。 +逆に言えば、型を与えることができないプログラムは*誤ったプログラム*であり、コンパイラによって拒否されます。 +動的型付けの言語とは異なり、PureScriptでは型は*コンパイル時*にのみ存在し、実行時には一切その表現がありません。 -PureScriptの型は、これまでJavaやC#のような他の言語で見たような型とは、いろいろな意味で異なっていることにも注意することが大切です。 -おおまかに言えばPureScriptの型はJavaやC#と同じ目的を持っているものの、PureScriptの型はMLやHaskellのような言語に影響を受けています。 -開発者がプログラムについての強い主張を表明できるので、PureScriptの型は表現力豊かなのです。 -最も重要なのは、PureScriptの型システムは*型推論*に対応していることです。 -型推論があれば他の言語より遥かに少ない型注釈で済み、型システムを厄介者ではなく*道具*にしてくれます。 -簡単な例を示すと、次のコードは*数*を定義していますが、それが `Number`型だという注釈はコードのどこにもありません。 +多くの点で、PureScriptの型とこれまでJavaやC#のような他の言語で見てきたであろう型が異なっていることにも、注意することが大切です。 +大まかに言えばPureScriptの型はJavaやC#と同じ目的を持っているものの、PureScriptの型はMLやHaskellのような言語に影響を受けています。 +PureScriptの型は表現力豊かであり、開発者はプログラムについての強い主張を表明できます。 +最も重要なのはPureScriptの型システムが*型推論*に対応していることです。 +型推論があれば他の言語より明示的な型注釈が遥かに少なく済み、型システムを厄介者ではなく*道具*にしてくれます。 +単純な一例として、次のコードは*数*を定義していますが、`Number`型への言及はコードのどこにもありません。 ```haskell iAmANumber = @@ -65,8 +69,8 @@ iAmANumber = in square 42.0 ``` -次のもっと複雑な例では、 _コンパイラにとって未知_ -の型が存在しているときでさえも、型注釈なしで型の正しさを確かめることができるということが示されています。 +より込み入った次の例では、*コンパイラにとって未知*の型が存在します。 +それでも、型注釈なく型の正しさを確かめられていることを示しています。 ```haskell iterate f 0 x = x @@ -78,20 +82,21 @@ iterate f n x = iterate f (n - 1) (f x) 本書で納得していただきたい(または既にお持ちの信条に寄り添って改めて断言したい)ことは、静的型が単にプログラムの正しさに自信を持つためだけのものではなく、それ自体の正しさによって開発の手助けになるものでもあるということです。JavaScriptではごく単純な抽象化を施すのでも大規模なコードのリファクタリングをすることは難しいですが、型検証器のある表現力豊かな型システムは、リファクタリングさえ楽しく対話的な体験にしてくれます。 -加えて、型システムによって提供されるこの安全網は、より高度な抽象化をも可能にします。 -実際に、関数型プログラミング言語Haskellによって知られるようになった、型駆動の強力な抽象化の形式である『型クラス』をPureScriptは備えています。 +加えて、型システムによって提供されるこの安全網は、より高度な抽象化を可能にします。 +実際に、根本的に型駆動な抽象化の強力な形式である型クラスをPureScriptは提供しています。 +この型クラスとは、関数型プログラミング言語Haskellによって有名になりました。 -## 多言語Webプログラミング +## 多言語webプログラミング -関数型プログラミングは既に多くの成功を収めています。 -枚挙に暇がありませんが、特に成功している応用例を幾つか挙げると、データ解析、構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理などがあります。 +関数型プログラミングは成功を収めてきました。 +特に成功している応用例を挙げると、データ解析、構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理といった具合に、枚挙に暇がありません。 PureScriptのような関数型言語でアプリケーション開発の最初から最後までを実施できるでしょう。 値や関数の型を提供することで既存のJavaScriptコードをインポートし、通常のPureScriptコードからこれらの関数を使用する機能をPureScriptは提供しています。 この手法については本書の後半で見ていくことになります。 しかし、PureScriptの強みの1つは、JavaScriptを対象とする他の言語との相互運用性にあります。 -アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分を記述するのに他の言語を使用するという方法もあります。 +アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分を記述するのに1つ以上の他の言語を使用するという方法もあります。 幾つかの例を示します。 @@ -99,17 +104,18 @@ PureScriptのような関数型言語でアプリケーション開発の最初 - JavaScriptや、他のJavaScriptにコンパイルする言語でアプリケーションを書き、PureScriptでそのテストを書く - 既存のアプリケーションのユーザインターフェースのテストを自動化するためにPureScriptを使用する -この本では小規模な課題をPureScriptで解決することに焦点を当てます。 +本書では小規模な課題をPureScriptで解決することに焦点を当てます。 ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、JavaScriptからPureScriptコードを呼び出す方法、及びその逆についても見ていきます。 ## ソフトウェア要件 -この本でのソフトウェア要件は最小限です。 +本書のソフトウェア要件は最小限です。 第1章では開発環境の構築を一から案内します。 これから使用するツールは、ほとんどの現代のオペレーティングシステムの標準リポジトリで使用できるものです。 -PureScriptコンパイラ自体はバイナリ形式でもダウンロードできますし、最新のHaskellコンパイラが動くシステム上でソースからもビルドできます。 -次の章ではこの手順を説明していきます。 +PureScriptコンパイラ自体はバイナリの配布物としてもダウンロードできますし、最新のGHC +Haskellコンパイラが動く任意のシステム上でソースからのビルドもできます。 +次の章ではこの手順を進めていきます。 本書のこのバージョンのコードは`0.15.*`バージョンのPureScriptコンパイラと互換性があります。 @@ -119,23 +125,26 @@ PureScriptコンパイラ自体はバイナリ形式でもダウンロードで 既にNPMやBowerのようなJavaScriptのエコシステムでの経験があれば、自身の好みに応じて標準設定をカスタマイズしたい場合などに役に立ちます。 ですがそのような知識は必要ありません。 -関数型プログラミングの予備知識は必要ありませんが、あっても害にはならないでしょう。 -新しい考えかたは実例とともに登場するので、これから使う関数型プログラミングからこうした概念に対する直感的な理解を得ることができるはずです。 +関数型プログラミングの事前知識は必要ありませんが、あっても決して害にはならないでしょう。 +新しい考えかたは実例と共に登場するため、これから使っていく関数型プログラミングからこうした概念に対する直感が形成されることでしょう。 -PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通じている読者はこの本の中で提示された概念や構文の多くに見覚えがあるでしょう。 -しかし、読者はPureScriptとHaskellの間には幾らか重要な違いがあることも理解しておかなければなりません。 +PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通じている読者は本書で提示された概念や構文の多くに見覚えがあるでしょう。 +しかし、PureScriptとHaskellの間には数多くの重要な違いがあることも理解しておくと良いでしょう。 ここで紹介する概念の多くはHaskellでも同じように解釈できるとはいえ、どちらかの言語での考え方を他方の言語でそのまま応用しようとすることは、必ずしも適切ではありません。 ## 本書の読み進めかた -本書の各章は、概ね章ごとに完結しています。 -しかし、多少の関数型プログラミングの経験がある初心者でも、まずは各章を順番に進めていくことをお勧めします。 -最初の数章では、本書の後半の内容を理解するために必要な基礎知識を養います。 +本書のほとんどの章が各章毎に完結しています。 +しかし、関数型プログラミングの経験がほとんどない初心者の方は、各章を順番に進めていくのが賢明です。 +最初の数章は本書の後半の内容を理解するのに必要な下地作りです。 関数型プログラミングの考え方に充分通じた読者(特にMLやHaskellのような強く型付けされた言語での経験を持つ読者)なら、本書の前半の章を読まなくても、後半の章のコードの大まかな理解を得ることが恐らく可能でしょう。 -各章ではそれぞれ1つの実用的な例に焦点をあて、新しい考え方を導入するための動機付けとして用います。各章のコードは本書の[GitHubのリポジトリ](https://github.com/purescript-contrib/purescript-book)から入手できます。ソースコードから抜粋したコード片が掲載されている章もありますが、完全に理解するためには本書に掲載されたコードと平行してリポジトリのソースコードを読む必要があります。対話式環境PSCiで実行し理解を確かめられるように、長めの節には短いコード片が掲載されていることがあります。 +各章では1つの実用的な例に焦点を当て、新しい考え方を導入するための動機を与えます。 +各章のコードは本書の[GitHubのリポジトリ](https://github.com/purescript-contrib/purescript-book)から入手できます。 +該当の章のソースコードから抜粋したコード片が含まれる章もありますが、本書の内容に沿ってリポジトリのソースコードを読まれると良いでしょう。 +長めの節には、理解を確かめられるように対話式モードのPSCiで実行できる短めのコード片が含まれます。 -コード例は次のように等幅フォントで示されています。 +コード例は次のように等幅フォントで示されます。 ```haskell module Example where @@ -151,8 +160,9 @@ main = log "Hello, World!" $ spago build ``` -通常、これらのコマンドはLinuxやMac -OSの利用者ならそのまま適用できますが、Windowsの利用者はファイル区切り文字を変更する、シェルの組み込み機能をWindowsの相当するものに置き換えるなどの小さな変更を加える必要があるかもしれません。 +通常、これらのコマンドはLinuxやMac OSの利用者に合わせたものになっています。 +そのためWindowsの利用者は小さな変更を加える必要があるかもしれません。 +ファイル区切り文字を変更したり、シェルの組み込み機能をWindowsの相当するものに置き換えるなどです。 PSCi対話式モードプロンプトに入力するコマンドは、行の先頭に山括弧が付けられています。 @@ -161,54 +171,61 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 3 ``` -各章には演習が付いており、それぞれ難易度も示されています。各章の内容を完全に理解するために、演習に取り組むことを強くお勧めします。 +各章には演習が含まれており、難易度も示されています。 +内容を完全に理解するために、各章の演習に取り組むことを強くお勧めします。 -この本は初心者にPureScriptへの導入を提供することを目的としており、問題についてのお決まりの解決策の一覧を提供するような種類の本ではありません。初心者にとってこの本を読むのは楽しい挑戦になるはずですし、本書の内容を読み演習に挑戦すればだいたいの利益を得られるでしょうが、なにより重要なのは、あなたが自分自身のコードを書いてみることです。 +本書は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。 +初心者にとっては楽しい挑戦になるはずです。 +内容を読んで演習に挑戦すれば得るものがあることでしょう。 +そして何よりも大切なのは、自分自身でコードを書いてみることです。 ## 困ったときには もしどこかでつまずいたときには、PureScriptを学べるオンラインで利用可能な資料が沢山あります。 - [PureScriptのDiscordサーバ](https://discord.gg/vKn9up84bp)は抱えている問題についてチャットするのに良い場所です。 - サーバはPureScriptについてのチャット専用です。 -- [PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくある問題への解決策を探すのに良い場所です。メッセージ履歴が約2週間しか保たないSlackとは違い、ここで質問した内容は将来の読者の助けとして使えるでしょう。 + こちらのサーバはPureScriptについてのチャット専用です。 +- [PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくある問題への解決策を探すのに良い場所です。 - [PureScript: Jordan's Reference](https://github.com/jordanmartinez/purescript-jordans-reference)は別のかなり深く踏み込んだ学習資料です。 - この本の中のある概念が理解しにくかったら、そちらの参考書の対応する節を読むとよいでしょう。 + 本書中の概念で理解しにくいものがあったら、そちらの参考書の対応する節を読むとよいでしょう。 - [Pursuit](https://pursuit.purescript.org)はPureScriptの型と関数を検索できるデータベースです。 Pursuitのヘルプページを読むと[どのような種類の検索ができるのかがわかります](https://pursuit.purescript.org/help/users)。 - 非公式の[PureScript Cookbook](https://github.com/JordanMartinez/purescript-cookbook)は「Xするにはどうするの」といった類の質問にコードを混じえて答えを提供します。 - [PureScriptドキュメントリポジトリ](https://github.com/purescript/documentation)には、PureScriptの開発者や利用者が書いた幅広い話題の記事と例が集まっています。 -- [PureScriptのWebサイト](https://www.purescript.org)には、コード例、映像、他の初心者向け資料を含む幾つかの学習資料へのリンクがあります。 +- [PureScriptのwebサイト](https://www.purescript.org)には幾つかの学習資料へのリンクがあります。 + コード例、映像、他の初心者向け資料などです。 - [Try - PureScript!](https://try.purescript.org)は利用者がWebブラウザでPureScriptのコードをコンパイルできるWebサイトです。 - 幾つかの簡単なコードの例があります。 + PureScript!](https://try.purescript.org)は利用者がwebブラウザでPureScriptのコードをコンパイルできるwebサイトです。 + 幾つかの簡単なコードの例もあります。 -もし例を読んで学ぶ方が好きでしたら、GitHubの -`purescript`組織、`purescript-node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。 +もし例を読んで学ぶ方が好きでしたら、GitHubの[purescript](https://github.com/purescript)、[purescript-node](https://github.com/purescript-node)、[purescript-contrib](https://github.com/purescript-contrib)組織にはPureScriptコードの例が沢山あります。 ## 著者について -私はPureScriptコンパイラの最初の開発者です。私はカリフォルニア州ロサンゼルスを拠点にしており、8ビットパーソナルコンピュータ、Amstrad +私はPureScriptコンパイラの最初の開発者です。 +カリフォルニア州ロサンゼルスを拠点にしており、8ビットパーソナルコンピュータであるAmstrad CPC上のBASICでまだ幼い時にプログラミングを始めました。 -それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そしてPureScript)で業務に携わってきました。 +それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そしてPureScript)で専門的に業務に携わってきました。 プロとしての経歴が始まって間もなく、私は関数型プログラミングと数学の関係を理解するようになり、そしてプログラミング言語Haskellを使って関数型の概念の学習を楽しみました。 JavaScriptでの経験をもとに、私はPureScriptコンパイラの開発を始めることにしました。 気が付くとHaskellのような言語から取り上げた関数型プログラミングの手法を使っていましたが、それを応用するためのもっと理に適った環境を求めていました。 そのとき検討した案のなかには、Haskellからその意味論を維持しながらJavaScriptへとコンパイルするいろいろな試み(Fay、Haste、GHCJS)もありました。 -しかし私が興味を持っていたのはこの問題への別の切り口からのアプローチ、すなわちHaskellのような言語の構文と型システムを楽しみながらJavaScriptの意味論も維持するということが、どのようにすれば可能になるのかでした。 +しかし私が興味を持っていたのは、この問題へ別の切り口からアプローチすると、どの程度うまくいくのかということでした。 +そのアプローチとは、JavaScriptの意味論を維持しつつ、Haskellのような言語の構文と型システムを楽しむことなのです。 私は[ブログ](http://blog.functorial.com)を運営しており、[Twitterで連絡をとる](http://twitter.com/paf31)こともできます。 ## 謝辞 -現在の状態に到達するまでPureScriptを手伝ってくれた多くの協力者に感謝したいと思います。コンパイラやツール、ライブラリ、ドキュメント、テストでの組織的で弛まぬ努力がなかったら、プロジェクトは間違いなく失敗していたことでしょう。 +現在に至るまでPureScriptに手を貸してくださった多くの協力者に感謝したいと思います。 +コンパイラ、ツール、ライブラリ、ドキュメント、テストでの、巨大で組織的な尽力なくしては、プロジェクトは間違いなく失敗していたことでしょう。 -この本の表紙に表示されたPureScriptのロゴはGareth Hughesによって作成されたもので、[Creative Commons +本書の表紙に示されたPureScriptのロゴはGareth Hughesによって作成されたもので、[Creative Commons Attribution 4.0 license](https://creativecommons.org/licenses/by/4.0/)の条件の下で再利用させて頂いています 。 -最後に、この本の内容に関する反応や訂正をくださった全ての方に、心より感謝したいと思います。 +最後に、本書の内容に関する反応や訂正をくださった全ての方に、心より感謝したいと思います。 diff --git a/text-ja/chapter10.md b/text-ja/chapter10.md index 78f319ff..c4dc8cb1 100644 --- a/text-ja/chapter10.md +++ b/text-ja/chapter10.md @@ -2,9 +2,9 @@ ## この章の目標 -この章でPureScriptの _外部関数インターフェース_ (foreign function interface; _FFI_) を紹介します。 +本章ではPureScriptの*外部関数インターフェース* (foreign function interface; *FFI*) を紹介します。 これによりPureScriptコードからJavaScriptコードへの呼び出し、及びその逆が可能になります。 -これから扱うのは次のようなものです。 +以下の方法を押さえていきます。 - 純粋で、作用のある、非同期なJavaScript関数をPureScriptから呼び出す。 - 型付けされていないデータを扱う。 @@ -16,15 +16,16 @@ - 利用者にポップアップ通知で警告する。 - フォームのデータを直列化してブラウザのローカルストレージに保存し、アプリケーションが再起動したときにそれを再読み込みする -さらに一般にはそこまで重用されない幾つかの話題を押さえた補遺もあります。 -ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本の残りを読み進める妨げにならないようにしてください。 +さらに一般にはそこまで重用されない幾つかの追加の話題を押さえた補遺もあります。 +ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本書の残りを読み進める妨げにならないようにしてください。 - 実行時のPureScriptの値の表現を理解する。 - JavaScriptからPureScriptを呼び出す。 ## プロジェクトの準備 -このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれています。 +このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。 +そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれています。 この章は`argonaut`ライブラリを依存関係として導入しています。 このライブラリはJSONにエンコードしたりJSONをデコードしたりするために使います。 @@ -37,14 +38,14 @@ test`を走らせることによって`test/Main.purs`中の単体試験につ ## 免責事項 -JavaScriptを扱う作業をできる限り簡単にするため、PureScriptは直感的な外部関数インターフェースを提供しています。 -しかし、FFIはPureScriptの*応用的な*機能であることには留意していただきたいと思います。 -FFIを安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現についてよく理解していなければなりません。 +JavaScriptの扱いをできる限り単純にするため、PureScriptは直感的な外部関数インターフェースを提供しています。 +しかし、FFIはこの言語の*応用的な*機能であることには心に留めておかれると良いでしょう。 +安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現について理解していなければなりません。 この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝授することを目指します。 PureScriptのFFIはとても柔軟に設計されています。 -実際には、外部関数に最低限の型だけを与えるか、それとも型システムを利用して外部のコードの誤った使い方を防ぐようにするか、開発者が選べるということを意味しています。 -標準ライブラリのコードは、後者の手法を好む傾向にあります。 +実際には、外部関数にとても単純な型を与えるか、型システムを利用して外部のコードの誤った使い方を防ぐようにするか、開発者が選べるようになっています。 +標準ライブラリのコードは、後者の手法を採る傾向にあります。 簡単な例としては、JavaScriptの関数で戻り値が `null`にならないことは保証できません。 実のところ、JavaScriptらしさのあるコードはかなり頻繁に `null`を返します。 @@ -68,7 +69,8 @@ node> encodeURIComponent('Hello World') 'Hello%20World' ``` -`null`でない文字列から `null`でない文字列への関数であり、副作用を持っていないので、この関数は型 `String -> String`について適切な実行時表現を持っています。 +この関数は関数の型`String -> String`について適切な実行時表現を持っています。 +`null`でない文字列を取って`null`でない文字列にするもので、副作用を持たないからです。 次のような外部インポート宣言を使うと、この関数に型を割り当てることができます。 @@ -135,8 +137,8 @@ $ spago repl {{#include ../exercises/chapter10/test/Examples.purs:diagonal}} ``` -PureScriptの関数は _カリー化_ されていることを思い出してください。 -`diagonal`は`Number`を取って _関数_ を返す関数です。 +PureScriptの関数は*カリー化*されていることを思い出してください。 +`diagonal`は`Number`を取って*関数*を返す関数です。 そして返された関数は`Number`を取って`Number`を返します。 ```js @@ -189,10 +191,11 @@ Type -> Type -> Type -> Type ``` `Fn2`は3つの型引数を取ります。 -`Fn2 a b c`は、型 `a`と `b`の2つの引数、返り値の型 `c`をもつカリー化されていない関数の型を表現しています。 +`Fn2 a b c`は、型`a`と`b`の2つの引数、返り値の型`c`を持つカリー化されていない関数の型を表現しています。 これを使って外部モジュールから`diagonalUncurried`をインポートしました。 -カリー化されていない関数と引数を取る`runFn2`で呼び出すことができます。 +そうして`runFn2`を使って呼び出せます。 +これはカリー化されていない関数と引数を取るものです。 ```text $ spago repl @@ -207,7 +210,10 @@ $ spago repl ## カリー化されていない関数についての補足 -PureScriptのカリー化された関数にはもちろん利点があります。部分的に関数を適用でき、関数型に型クラスインスタンスを与えられます。しかし効率上の代償も付いてくるのです。効率性が決定的に重要なコードでは多変数を受け付けるカリー化されていないJavaScript関数を定義する必要が時々あります。 +PureScriptのカリー化された関数には勿論利点があります。 +部分的に関数を適用でき、関数型に型クラスインスタンスを与えられるのです。 +しかし効率上の代償も付いてきます。 +効率性が決定的に重要なコードでは時々、多変数を受け付けるカリー化されていないJavaScript関数を定義する必要があります。 PureScriptでカリー化されていない関数を作ることもできます。 2引数の関数については`mkFn2`関数が使えます。 @@ -255,12 +261,12 @@ var curriedSum = curriedAdd(3)(10); ## 現代的なJavaScriptの構文についての補足 前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しすればIE11)と互換性がありません。 -執筆時点でWebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことができないと推計](https://caniuse.com/#feat=arrow-functions)されています。 +執筆時点でwebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことができないと推計](https://caniuse.com/#feat=arrow-functions)されています。 ほとんどの利用者にとって互換性があるようにするため、PureScriptコンパイラによって生成されるJavaScriptコードは矢印関数を使っていません。 また、同じ理由で**公開するライブラリでも矢印関数を避ける**ことが推奨されます。 -それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程でES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/babel#intro)などのツールを含めるべきです。 +それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程でES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/babel#intro)などのツールを含めると良いでしょう。 ES6の矢印関数がより読みやすく感じたら[Lebab](https://github.com/lebab/lebab)のようなツールを使ってコンパイラの`output`ディレクトリにJavaScriptのコードを変換できます。 @@ -299,7 +305,8 @@ Record | Object `String`と`Number`という原始型の例は既に見てきました。 ここから`Array`や`Record`(JavaScriptでは`Object`)といった構造的な型を眺めていきます。 -`Array`の受け渡しを実演するために、以下に`Int`の`Array`を取って別の配列として累計の和を返すJavaScriptの関数の呼び出し方を示します。前にありましたが、JavaScriptは`Int`のための分離した型を持たないため、PureScriptでの`Int`と`Number`はJavaScriptでの`Number`に翻訳されます。 +`Array`を渡すところを実演するために、以下に`Int`の`Array`を取って別の配列として累計の和を返すJavaScriptの関数の呼び出し方を示します。 +前にありましたが、JavaScriptは`Int`のための分離した型を持たないため、PureScriptでの`Int`と`Number`は両方共JavaScriptでの`Number`に翻訳されます。 ```hs foreign import cumulativeSums :: Array Int -> Array Int @@ -325,7 +332,7 @@ $ spago repl [1,3,6] ``` -`Record`の受け渡しを実演するために、以下に2つの`Complex`な数をレコードとして取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。 +`Record`を渡すところを実演するために、以下に2つの`Complex`な数をレコードとして取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。 PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意してください。 ```hs @@ -354,7 +361,10 @@ $ spago repl { imag: 6.0, real: 4.0 } ``` -なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要があります。PureScriptはJavaScriptのコードに型検査を適用できないからです。この型安全性の配慮について後のJSONの節でより詳しく記述していきます。型の不整合から身を守る手法についても押さえます。 +なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要があります。 +PureScriptはJavaScriptのコードに型検査を適用できないからです。 +この型安全性の配慮について後のJSONの節でより詳しく解説していきます。 +型の不整合から身を守る手法についても押さえます。 ## 演習 @@ -430,23 +440,26 @@ forall a. (forall x. x -> Maybe x) -> (forall x. Maybe x) -> Array a -> Maybe a 以下ではないことに注意です。 ```hs -forall a. ( a -> Maybe a) -> Maybe a -> Array a -> Maybe a +forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a ``` -どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に侵されやすくなります。例えばより脆弱な場合では以下のようにして呼ぶことができます。 +どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に対してより脆弱です。 + +例えば、比較的脆い方では、以下のように呼び出せるでしょう。 ```hs maybeHeadImpl (\_ -> Just 1000) (Just 1000) [1,2,3] ``` -これはいかなる配列についても`Just 1000`を返します。 -この脆弱性は`a`が`Int`のときに(これは入力の配列に基づきます)`(\_ -> Just 1000)`と`Just 1000`がシグネチャ`(a -> Maybe a)`と`Maybe a`にそれぞれ合致しているために許されているのです。 +これは如何なる配列の入力に対しても`Just 1000`を返します。 + +この脆弱性では、`a`が`Int`のときに(これは入力の配列に基づきます)`(\_ -> Just 1000)`と`Just 1000`がシグネチャ`(a -> Maybe a)`と`Maybe a`にそれぞれ照合するために許容されてしまっています。 より安全な型シグネチャでは、入力の配列に基づいて`a`が`Int`に決定されたとしても、`forall x`に絡むシグネチャに合致する妥当な関数を提供する必要があります。`(forall x. Maybe x)`の *唯一* の選択肢は`Nothing`ですが、それは`Just`値が`x`の型を前提にしてしまうと、もはや全ての`x`については妥当でなくなってしまうからです。`(forall x. x -> Maybe x)`の唯一の選択肢は`Just`(望まれている引数)と`(\_ -> Nothing)`であり、後者は唯一残っている脆弱性になるのです。 ## 外部型の定義 -`Maybe a`を返す代わりに実は`arr[0]`を返したいのだとしましょう。 +`Maybe a`を返す代わりに`arr[0]`を返したいのだとしましょう。 型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する型がほしいです。 この型を`Undefined a`と呼びましょう。 @@ -462,7 +475,7 @@ foreign import data Undefined :: Type -> Type この場合は`Undefined`の種が `Type -> Type`であると宣言しています。 言い換えれば`Undefined`は型構築子です。 -これで元の`head`の定義を単に再利用できます。 +これで元の`head`の定義を再利用できます。 ```javascript export const undefinedHead = arr => @@ -478,7 +491,7 @@ foreign import undefinedHead :: forall a. Array a -> Undefined a `undefinedHead`関数の本体は`undefined`かもしれない`arr[0]`を返します。 そしてこの型シグネチャはその事実を正しく反映しています。 -この関数はその型の適切な実行時表現を持っていますが、型 `Undefined a`の値を使用する方法がないので、全く役に立ちません。 +この関数はその型の適切な実行時表現を持っていますが、型`Undefined a`の値を使用する方法がないので、全く役に立ちません。 いや、言い過ぎました。 別のFFIでこの型を使えますからね。 @@ -502,7 +515,7 @@ isEmpty :: forall a. Array a -> Boolean isEmpty = isUndefined <<< undefinedHead ``` -このように、定義したこの外部関数はとても簡単です。 +このように、定義したこの外部関数はとても単純です。 つまりPureScriptの型検査器を使うことによる利益が最大限得られるのです。 一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理はPureScriptコードへ移動しておくことをお勧めします。 @@ -583,7 +596,7 @@ bold :: forall a. Show a => a -> String bold x = boldImpl show x ``` -代わりにポイントフリー形式だとこうです。 +代えてポイントフリー形式だとこうです。 ```hs bold :: forall a. Show a => a -> String @@ -744,7 +757,7 @@ done waiting ``` REPLでの非同期ログ出力はブロック全体が実行を終了するまで印字を待機する点に注意しましょう。 -このコードを`spago test`で走らせた場合、印字の _合間に_ 僅かな遅延があり、より予測に近い挙動をします。 +このコードを`spago test`で走らせた場合、印字の*合間に*僅かな遅延があり、より予測に近い挙動をします。 他にプロミスから値を返す例を見てみましょう。 この関数は`async`と`await`を使って書かれていますが、これはプロミスの糖衣構文に過ぎません。 @@ -792,9 +805,9 @@ unit ## JSON アプリケーションでJSONを使うことには多くの理由があります。 -例えばWebのAPIと疎通するよくある手段であるためです。 +例えばwebのAPIと疎通するよくある手段であるためです。 この節では他の用例についてもお話ししましょう。 -構造的なデータをFFI越しに渡すことで型安全性を向上させる手法から始めます。 +構造的なデータをFFI越しに渡す場合に型安全性を向上させる手法から始めます。 少し前のFFI関数`cumulativeSums`と`addComplex`を再訪し、それぞれに1つバグを混入させてみましょう。 @@ -864,7 +877,7 @@ PureScriptのコードにバグ一匹通さないようにするため、JavaScr `argonaut`ライブラリにはこのために必要なJSONのデコードとエンコードの機能が備わっています。 このライブラリには素晴らしい[ドキュメント](https://github.com/purescript-contrib/purescript-argonaut#documentation)があるので、本書では基本的な用法だけを押さえます。 -返る型を`Json`として定義するようにして、代わりとなる外部インポートをつくるとこうなります。 +返る型を`Json`として定義するようにして、代わりとなる外部インポートを作るとこうなります。 ```hs foreign import cumulativeSumsJson :: Array Int -> Json @@ -981,11 +994,11 @@ Map String Int 1. (簡単)より広い種類のマップに関して動作するよう、前のJavaScriptの関数の新しい梱包を書いてください。 シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either JsonDecodeError (Set v)`です。 - なお`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。 + なお、`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。 コンパイラが導いてくれます。 -1. (普通)少し前の`quadraticRoots`を書き換えて`quadraticRootSet`としてください。 +1. (普通)少し前の`quadraticRoots`関数を書き換えて`quadraticRootSet`としてください。 この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返します。 -1. (難しい)少し前の`quadraticRoots`を書き換えて`quadraticRootsSafe`としてください。 +1. (難しい)少し前の`quadraticRoots`関数を書き換えて`quadraticRootsSafe`としてください。 この関数はJSONを使って`Complex`の根の`Pair`をFFI越しに渡します。 JavaScriptでは`Pair`構築子を使わないでください。 その代わり、デコーダーに互換性のある形式で対を返すだけにしてください。 @@ -1029,7 +1042,7 @@ Map String Int フォームのフィールドにはこの文書の内容を入れます。 - フォームの状態を保存したり読み込んだりするのに問題があればポップアップの警告を出します。 -`Effect.Storage`モジュールに以下のWebストレージAPIのためのFFIの梱包をつくることから始めていきます。 +`Effect.Storage`モジュールに以下のwebストレージAPIのためのFFIの梱包を作ることから始めていきます。 - `setItem`はキーと値(両方とも文字列)を受け取り、指定されたキーでローカルストレージに値を格納する計算を返します。 - `getItem`はキーを取り、ローカルストレージから関連付けられたバリューの取得を試みます。 @@ -1081,7 +1094,7 @@ validateAndSave = do log "Saved" ``` -なおこの段階でコンパイルしようとすると以下のエラーに遭遇します。 +なお、この段階でコンパイルしようとすると以下のエラーに遭遇します。 ```text No type class instance was found for @@ -1089,8 +1102,8 @@ validateAndSave = do ``` これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンスを必要としているからです。 -単純に汎用のエンコードインスタンスとデコードインスタンスを導出すれば完了です。 -この仕組みについて、より詳しくはargonautのドキュメントで見られます。 +また、ついでに汎用のエンコードインスタンスとデコードインスタンスを導出していきます。 +この仕組みについての詳細情報はargonautのドキュメントにあります。 ```hs {{#include ../exercises/chapter10/src/Data/AddressBook.purs:import}} @@ -1108,10 +1121,10 @@ validateAndSave = do item <- getItem "person" ``` -そうしてローカルストレージから、文字列から`Person`レコードへの変換を扱う補助関数をつくります。 -なおこのストレージ中の文字列は`null`かもしれないので、うまく`String`としてデコードされるまでは外部の`Json`として表現します。 +そうしてローカルストレージ由来の文字列から`Person`レコードへ変換する補助関数を作ります。 +なお、このストレージ中の文字列は`null`かもしれないので、正常に`String`としてデコードされるまでは外部の`Json`として表現します。 道中には他にも多くの変換工程があり、それぞれで`Either`の値を返します。 -そのためこれらを`do`ブロックの中に纏めるのは理に適っています。 +そのためこれらをまとめて`do`ブロックの中に纏めるのは理に適っています。 ```hs processItem :: Json -> Either String Person @@ -1149,7 +1162,7 @@ mkAddressBookApp = Tuple person setPerson <- useState props.initialPerson ``` -仕上げとして、それぞれの`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向上させます。 +仕上げとして、各`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向上させます。 ```hs processItem :: Json -> Either String Person @@ -1160,16 +1173,16 @@ processItem item = do ``` 最初のエラーのみがこのアプリの通常の操作内で起こります。 -他のエラーはWebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。 -どのようにJSON文字列を変更したかが、どのエラーの引き金になるかを決定します。 -それぞれのエラーを引き起こせるかどうかやってみてください。 +他のエラーはwebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。 +どのようにJSON文字列を変更したかが、どのエラーを引き起こすかを決定します。 +各エラーを引き起こせるかご確認ください。 これでローカルストレージについては押さえました。 -次に`alert`アクションを実装していきます。 -このアクションは`Effect.Console`モジュールの`log`アクションによく似ています。 -唯一の相違点は`alert`アクションが`window.alert`メソッドを使うことで、対して`log`アクションは`console.log`メソッドを使っています。 +次に`alert`動作を実装していきます。 +この動作は`Effect.Console`モジュールの`log`動作に似ています。 +唯一の相違点は`alert`動作が`window.alert`メソッドを使うことで、対して`log`動作は`console.log`メソッドを使っています。 そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができます。 -例えばWebブラウザなどです。 +webブラウザなどです。 ```hs foreign import alert :: String -> Effect Unit @@ -1205,14 +1218,15 @@ alert $ "Error: " <> err <> ". Loading examplePerson" ## まとめ -この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。また、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。 +この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。 +また、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。 - 外部関数が正しい表現を持っていることを確かめる重要性を見てきました。 - 外部型や`Json`データ型を使用することによって、null値やJavaScriptの他の型のデータのような特殊な場合に対処する方法を学びました。 - 安全にJSONデータを直列化・直列化復元する方法を見ました。 -より多くの例については、Githubの `purescript`組織、`purescript-contrib`組織および -`purescript-node`組織が、FFIを使用するライブラリの例を多数提供しています。残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾つか見ていきます。 +より多くの例については、GitHubの`purescript`組織、`purescript-contrib`組織、及び`purescript-node`組織が、FFIを使用するライブラリの例を多数提供しています。 +残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾つか見ていきます。 ## 補遺 @@ -1230,7 +1244,7 @@ gcd 0 m = m gcd n 0 = n gcd n m | n > m = gcd (n - m) m - | otherwise = gcd (m - n) n + | otherwise = gcd (m – n) n ``` この関数は、減算を繰り返すことによって2つの数の最大公約数を見つけます。 @@ -1244,9 +1258,9 @@ import Test from 'Test.js'; Test.gcd(15)(20); ``` -ここでは、コードがPureScriptモジュールをESモジュールにコンパイルする `spago -build`でコンパイルされていると仮定しています。そのため、 `import`を使って `Test`モジュールをインポートした後、 -`Test`オブジェクトの `gcd`関数を参照できました。 +ここでは`spago build`でコンパイルされていることを前提としています。 +SpagoはPureScriptモジュールをESモジュールにコンパイルするものです。 +そのため、`import`を使って`Test`モジュールをインポートした後、`Test`オブジェクトの`gcd`関数を参照できました。 `spago bundle-app`や`spago bundle-module`コマンドを使って生成されたJavaScriptを単一のファイルにまとめることもできます。 @@ -1254,7 +1268,9 @@ bundle-module`コマンドを使って生成されたJavaScriptを単一のフ ### 名前の生成を理解する -PureScriptはコード生成時にできるだけ名前を保存することを目的としています。具体的には、少なくともトップレベルで宣言される名前については、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存されます。 +PureScriptはコード生成時にできるだけ名前を保持することを目指します。 +とりわけ、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存されることが期待できます。 +少なくとも最上位で宣言される名前についてはそうです。 識別子としてJavaScriptのキーワードを使う場合は、名前は2重のドル記号でエスケープされます。 例えば次のPureScriptコードを考えてみます。 @@ -1282,15 +1298,15 @@ example' = 100 var example$prime = 100; ``` -コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めします。 -ユーザ定義演算子がPureScriptコードでの使用のために提供される場合でも、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。 +コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptのキーワードを避けることをお勧めします。 +ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。 ### 実行時のデータ表現 -型はプログラムがある意味で「正しい」ことをコンパイル時に判断できるようにします。 +型はプログラムがある意味で「正しい」ことをコンパイル時に論証できるようにします。 つまり、その点については壊れることがありません。 しかし、これは何を意味するのでしょうか。 -PureScriptでは式の型は実行時の表現と互換性がなければならないことを意味します。 +PureScriptでは、式の型は実行時の表現と互換性があることを意味します。 そのため、PureScriptとJavaScriptコードを一緒に効率的に使用できるように、実行時のデータ表現について理解することが重要です。 これはつまり、与えられた任意のPureScriptの式について、その値が実行時にどのように評価されるかという挙動を理解できるべきだということです。 @@ -1303,38 +1319,38 @@ PureScriptでは式の型は実行時の表現と互換性がなければなら つまり、型 `Boolean`の式は `true`もしくは `false`のどちらか一方の(JavaScriptの)値へと評価されます。 特に`null`や `undefined`に評価される型`Boolean`なPureScriptの式はありません。 -`Int`や`Number`や`String`の型の式についても同様のことが成り立ちます。 -`Int`や`Number`型の式は `null`でないJavaScriptの数へと評価されますし、 `String`型の式は -`null`でないJavaScriptの文字列へと評価されます。 +`Int`や`Number`や`String`の型の式についても似た法則が成り立ちます。 +`Int`や`Number`型の式はnullでないJavaScriptの数へと評価されますし、`String`型の式はnullでないJavaScriptの文字列へと評価されます。 `typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式は実行時に整数に評価されます。 `Unit`についてはどうでしょうか。 `Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何で表現されるかは重要ではありません。 古いコードは`{}`を使って表現する傾向がありました。 しかし比較的新しいコードでは`undefined`を使う傾向にあります。 -なので、`Unit`を表現するのに使うものは本当に何でも問題にならないのですが、`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を返します)。 +なので、`Unit`を表現するのに使うものは何であれ差し支えありませんが、`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を返します)。 もっと複雑な型についてはどうでしょうか。 既に見てきたように、PureScriptの関数は引数が1つのJavaScriptの関数に対応しています。 厳密に言えばこうなります。 -任意の型`a`と`b`について、式`f`の型が`a -> b`で、式`x`が型`a`についての適切な実行時表現の値へと評価されるとします。 -このとき`f`はJavaScriptの関数へと評価され、`x`を評価した結果に`f`を適用すると型`b`の適切な実行時表現を持ちます。 -簡単な例としては、 `String -> String`型の式は、 `null`でないJavaScript文字列から `null`でないJavaScript文字列への関数へと評価されます。 +ある型`a`と`b`について、式`f`の型が`a -> b`で、式`x`が型`a`についての適切な実行時表現の値へと評価されるとします。 +このとき`f`はJavaScriptの関数へと評価されますが、この関数は`x`を評価した結果に`f`を適用すると型`b`の適切な実行時表現を持ちます。 +単純な例としては、`String -> String`型の式は、nullでないJavaScript文字列からnullでないJavaScript文字列への関数へと評価されます。 ご想像の通り、PureScriptの配列はJavaScriptの配列に対応しています。 しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っていることは覚えておいてください。 -具体的には、もしPureScriptの式 `e`が何らかの型 `a`について型 `Array a`を持つなら、 -`e`は全ての要素が(`null`でない)型 `a`の適切な実行時表現を持ったJavaScript配列へと評価されます。 +具体的には、もしPureScriptの式`e`が何らかの型`a`について型`Array +a`を持つなら、`e`は(nullでない)JavaScript配列へと評価されます。 +この配列の全ての要素は型`a`の適切な実行時表現を持ちます。 PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てきました。 -ちょうど関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールドのデータの実行時の表現についても推論できます。 -もちろん、レコードのそれぞれのフィールドは、同じ型である必要はありません。 +関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールド中のデータの実行時の表現について論証できます。 +勿論、レコードのフィールドは、同じ型である必要はありません。 ### ADTの表現 -PureScriptコンパイラは、代数的データ型の全ての構築子についてそれぞれを関数として定義し、新たなJavaScriptオブジェクト型を作成します。 -これらの構築子は雛形に基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。 +代数的データ型の全ての構築子について、PureScriptコンパイラは関数を定義することで新たなJavaScriptオブジェクト型を作成します。 +これらの構築子はプロトタイプに基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。 例えば次のような単純なADTを考えてみましょう。 @@ -1359,18 +1375,18 @@ function Zero() { Zero.value = new Zero(); ``` -ここで2つのJavaScriptオブジェクト型 `Zero`と `One`を見てください。 -JavaScriptのキーワード`new`を使用すると、それぞれの型の値を作成できます。 -引数を持つ構築子については、コンパイラは `value0`、 `value1`などという名前のフィールドに、対応するデータを格納します。 +ここで2つのJavaScriptオブジェクト型`Zero`と`One`を見てください。 +JavaScriptのキーワード`new`を使用すると、各型の値を作成できます。 +引数を持つ構築子については、コンパイラは`value0`、`value1`などという名前のフィールドに、対応するデータを格納します。 PureScriptコンパイラは補助関数も生成します。 引数のない構築子については、コンパイラは構築子が使われるたびに `new`演算子を使うのではなく、データを再利用できるように `value`プロパティを生成します。 1つ以上の引数を持つ構築子では、コンパイラは適切な表現を持つ引数を取り適切な構築子を適用する `create`関数を生成します。 -2引数以上の構築子についてはどうでしょうか。 +1引数より多く取る構築子についてはどうでしょうか。 その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成します。 -ここでは補助関数は2引数のカリー化された関数なのです。 +ただしこの場合、補助関数は2引数のカリー化された関数です。 例えば次のような代数的データ型を考えます。 ```haskell @@ -1392,20 +1408,19 @@ Two.create = function (value0) { }; ``` -ここで、オブジェクト型 `Two`の値はキーワード`new`または `Two.create`関数を使用すると作成できます。 +ここで、オブジェクト型`Two`の値はキーワード`new`または`Two.create`関数を使用すると作成できます。 newtypeの場合はまた少し異なります。 -newtypeは単一の引数を取る単一の構築子を持つよう制限された代数的データ型であることを思い出してください。 -この場合、実際のnewtypeの実行時表現は、その引数の型と同じになります。 +newtypeは代数的データ型のようなもので、単一の引数を取る単一の構築子を持つよう制限されていたことを思い出してください。 +この場合、newtypeの実行時表現は、その引数の型と同じになります。 -例えば、電話番号を表す次のようなnewtypeを考えます。 +例えば、以下の電話番号を表すnewtypeは実行時にJavaScriptの文字列として表現されます。 ```haskell newtype PhoneNumber = PhoneNumber String ``` -これは実行時にJavaScriptの文字列として表されます。 -newtypeは更なる型安全性のための層を提供しますが、実行時の関数呼び出しのオーバーヘッドがないので、ライブラリを設計するのに役に立ちます。 +newtypeは、関数呼び出しによる実行時のオーバーヘッドなく更なる型安全性のための層を提供するため、ライブラリを設計するのに便利です。 ### 量化された型の表現 @@ -1435,10 +1450,10 @@ identity a = a 量化された型 `forall a. t`の実行時表現はどうなっているのでしょうか。さて、この型の実行時表現を持つ任意の式は、型 `a`をどのように選んでも型 `t`の適切な実行時表現を持っていなければなりません。上の例では、型 `forall a. a -> a`の関数は、 `String -> String`、 `Number -> Number`、 `Array Boolean -> Array Boolean`などといった型について、適切な実行時表現を持っていなければなりません。 これらは、文字列から文字列、数から数の関数でなくてはなりません。 しかし、それだけでは充分ではありません。 -量化された型の実行時表現は、これよりも更に厳しくなります。 -任意の式が*パラメトリック多相的*でなければなりません。 +量化された型の実行時表現は、これよりも更に厳しいものです。 +任意の式が*パラメトリック多相的*であることを要求しています。 つまり、その実装において、引数の型についてのどんな情報も使うことができないのです。 -この追加の条件は、考えられる多相型のうち、以下のJavaScriptの関数のような問題のある実装を防止します。 +この追加の条件は、以下のJavaScriptの関数のような問題のある実装が多相型に現住することを防止します。 ```javascript function invalid(a) { @@ -1450,10 +1465,12 @@ function invalid(a) { } ``` -確かにこの関数は文字列から文字列、数から数へというような関数ではありますが、追加条件を満たしていません。 -引数の実行時の型を調べており、したがって、この関数は型 `forall a. a -> a`の正しい実装だとはいえないのです。 +確かにこの関数は文字列を取って文字列を返し、数を取って数を返す、といったものです。 +しかしこの関数は追加条件を満たしていません。 +引数の実行時の型を調べており、型`forall a. a -> a`の正しい現住にはならないからです。 -関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけであり、したがって `id`はたしかに `forall a. a -> a`の唯一の実装なのです。 +関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけです。 +したがって`id`は確かに`forall a. a -> a`の唯一の現住なのです。 *パラメトリック多相*と*パラメトリック性*についての詳しい議論は本書の範囲を超えています。 ただ、PureScriptの型は実行時に*消去*されており、PureScriptの多相関数は(FFIを使わない限り)引数の実行時表現を検査*できない*ため、この多相的なデータの表現が適切になっているという点にはご留意ください。 @@ -1464,7 +1481,7 @@ function invalid(a) { 関数の挙動はコンパイラによって選ばれた型クラスのインスタンスに依存する可能性があるため、関数には*型クラス辞書*と呼ばれる追加の引数が与えられます。 この辞書には選ばれたインスタンスから提供される型クラスの関数の実装が含まれます。 -例えば、 `Show`型クラスを使った制約のある型を持つ、次のような単純なPureScript関数について考えます。 +例えば以下は、`Show`型クラスを使う制約付きの型を持つ、単純なPureScript関数です。 ```haskell shout :: forall a. Show a => a -> String @@ -1509,9 +1526,9 @@ shout(showNumber)(42); ### 副作用の表現 `Effect`モナドも外部型として定義されています。 -その実行時表現はとても簡単です。 -型 `Effect a`の式は**引数なしの**JavaScript関数へと評価されます。 -この関数はあらゆる副作用を実行し型 `a`の適切な実行時表現で値を返します。 +その実行時表現はとても単純です。 +型`Effect a`の式は**引数なしの**JavaScript関数へと評価されます。 +この関数はあらゆる副作用を実行し、型`a`の適切な実行時表現を持つ値を返します。 `Effect`型構築子の定義は、 `Effect`モジュールで次のように与えられています。 @@ -1532,8 +1549,8 @@ export const random = Math.random; ``` `random`関数は実行時には引数なしの関数として表現されていることに注目してください。 -この関数は乱数生成という副作用を実行して返しますが、返り値は `Number`型の実行時表現と一致します。 -`Number`型は`null`でないJavaScriptの数です。 +この関数は乱数生成という副作用を実行して返しますが、返り値は`Number`型の実行時表現と一致します。 +`Number`型はnullでないJavaScriptの数です。 もう少し興味深い例として、`console`パッケージ中の`Effect.Console`モジュールで定義された `log`関数を考えてみましょう。 `log`関数は次の型を持っています。 @@ -1552,8 +1569,8 @@ export const log = function (s) { }; ``` -実行時の -`log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返します。内側の関数はコンソールにメッセージを書き込むという副作用を実行します。 +実行時の `log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返します。 +内側の関数はコンソールに文言を書き込むという副作用を実行します。 `Effect a`型の式は、通常のJavaScriptのメソッドのようにJavaScriptから呼び出すことができます。例えば、この `main`関数は何らかの型`a`について`Effect a`という型でなければならないので、次のように実行できます。 @@ -1564,5 +1581,5 @@ import { main } from 'Main' main(); ``` -`spago bundle-app --to`または `spago run`を使用するときは、`Main`モジュールが定義されている場合は常に、この -`main`の呼び出しを自動的に生成できます。 +`spago bundle-app --to`または`spago +run`を使用する場合、`Main`モジュールが定義されている場合は常に、この`main`の呼び出しを自動的に生成できます。 diff --git a/text-ja/chapter11.md b/text-ja/chapter11.md index 1eaa8b27..4815b67a 100644 --- a/text-ja/chapter11.md +++ b/text-ja/chapter11.md @@ -4,8 +4,8 @@ この章の目標は*モナド変換子*について学ぶことです。 モナド変換子は異なるモナドから提供された副作用を合成する方法を提供します。 -NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームを題材として扱います。 -ゲームの様々な副作用(ロギング、状態、及び設定)が全てモナド変換子スタックによって提供されます。 +動機付けとする例は、NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームです。 +ゲームの様々な副作用(ロギング、状態、及び構成)が全てモナド変換子スタックによって提供されます。 ## プロジェクトの準備 @@ -14,13 +14,13 @@ NodeJSのコンソール上で遊ぶことができるテキストアドベン - `ordered-collections` は不変のマップと集合のためのデータ型を提供します - `transformers` は標準的なモナド変換子の実装を提供します - `node-readline`はNodeJSが提供する[`readline`](http://nodejs.org/api/readline.html)インターフェイスへのFFIバインディングを提供します -- `optparse` はコマンドライン引数を処理するアプリカティブ構文解析器を提供します +- `optparse`はコマンドライン引数を処理するアプリカティブ構文解析器を提供します ## ゲームの遊びかた プロジェクトを走らせるには`spago run`を使います。 -既定では使い方が表示されます。 +既定では使い方の文言が表示されます。 ```text Monadic Adventures! A game to learn monad transformers @@ -35,8 +35,10 @@ Available options: -h,--help Show this help text ``` -コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-a`オプション付きで`spago run`を呼び出すか、`spago bundle-app`とすればよいです。 +コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-a`オプション付きで`spago run`を呼び出すか、`spago +bundle-app`とすればよいです。 2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。 + 例えば`-p`オプションを使ってプレイヤー名を与えるには次のようにします。 ```text @@ -50,14 +52,12 @@ $ node index.js -p Phil > ``` -プロンプトからは、 `look`、 `inventory`、 `take`、 `use`、 `north`、`south`、 `east`、 -`west`などのコマンドを入力できます。 -`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合に、ゲームの状態を出力するのに使えます。 +プロンプトからは、`look`、`inventory`、`take`、`use`、`north`、`south`、`east`、`west`などのコマンドを入力できます。 +`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合に、ゲームの状態を出力できます。 -ゲームは2次元の碁盤の目の上が舞台で、コマンド `north`、 `south`、`east`、 -`west`を発行することによってプレイヤーが移動します。 -ゲームにはアイテムの集まりがあり、プレイヤーの所持アイテム一覧を表したり、ゲーム盤上のその位置にあるアイテムの一覧を表すのに使われます。 -`take`コマンドを使うと、プレイヤーの位置にあるアイテムを拾い上げることができます。 +ゲームは2次元の碁盤の目の上が舞台で、コマンド`north`、`south`、`east`、`west`を発行することによってプレイヤーが移動します。 +ゲームにはアイテムの集まりがあり、プレイヤーの所有物であったり、ゲームの盤上の特定の位置にあったりします。 +`take`コマンドを使うと、プレイヤーはアイテムを拾い上げられます。 参考までに、このゲームのひと通りの流れは次のようになります。 @@ -91,8 +91,7 @@ Congratulations, Phil! You win! ``` -このゲームはとても単純ですが、この章の目的は -`transformers`パッケージを使用してこのようなゲームを素早く開発できるようにするライブラリを構築することです。 +このゲームはとても単純ですが、この章の目的は`transformers`パッケージを使用してこのような種類のゲームを素早く開発できるようにするライブラリを構築することです。 ## Stateモナド @@ -103,8 +102,8 @@ You win! 既に`Effect`モナドによって提供される変更可能状態の手法について見てきました。 `State`はその代替を提供します。 -`State`型構築子は、状態の型 `s`、及び返り値の型 `a`という2種類の引数を取ります。 -「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのインスタンスが任意の型`s`についての `State +`State`型構築子は、状態の型`s`、及び返り値の型`a`という2種類の引数を取ります。 +「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのインスタンスが任意の型`s`についての`State s`型構築子に対して提供されています。 `Control.Monad.State`モジュールは以下のAPIを提供しています。 @@ -117,14 +116,13 @@ modify :: forall s. (s -> s) -> State s s modify_ :: forall s. (s -> s) -> State s Unit ``` -なおここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式で表されています。 +なお、ここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式で表されています。 実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきます。 ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないでください。 例を見てみましょう。 -`State`モナドの使いかたの1つとしては、整数の配列中の値を現在の状態に加えるものが考えられます。 -状態の型`s`として`Int`を選択し、配列の走査に `traverse_`を使って、配列の要素それぞれについて -`modify`を呼び出すと、これを実現できます。 +`State`モナドの使い方の1つとしては、整数の配列中の値を現在の状態に加えるものが考えられます。 +状態の型`s`として`Int`を選択し、配列の走査に`traverse_`を使い、配列の各要素について`modify`を呼び出すと、これを実現できます。 ```haskell import Data.Foldable (traverse_) @@ -143,8 +141,8 @@ execState :: forall s a. State s a -> s -> s runState :: forall s a. State s a -> s -> Tuple a s ``` -3つの関数はそれぞれ型`s`の初期状態と型`State s a`の計算を引数にとります。 -`evalState`は返り値だけを返し、 `execState`は最終的な状態だけを返し、 `runState`は `Tuple a +3つの各関数は型`s`の初期状態と型`State s a`の計算を引数に取ります。 +`evalState`は返り値だけを返し、`execState`は最終的な状態だけを返し、`runState`は`Tuple a s`型の値として表現された両方を返します。 先ほどの `sumArray`関数が与えられているとき、PSCiで `execState`を使うと次のように複数の配列内の数字を合計できます。 @@ -162,8 +160,7 @@ s`型の値として表現された両方を返します。 ## 演習 1. (簡単)上の例で、`execState`を`runState`や`evalState`で置き換えると結果はどうなるでしょうか。 -1. (普通)括弧からなる文字列について、次の何れかであれば*平衡している*とします。 - 1つは0個以上のより短い平衡した文字列を連結したもので、もう1つはより短い平衡した文字列を一対の括弧で囲んだものです。 + 1. (普通)括弧からなる文字列が*平衡している*のは、0個以上のより短い平衡した文字列を連結したものか、より短い平衡した文字列を一対の括弧で囲んだものかの何れかです。 `State`モナドと `traverse_`関数を使用して、次のような関数を書いてください。 @@ -171,9 +168,8 @@ s`型の値として表現された両方を返します。 testParens :: String -> Boolean ``` - これは `String`が括弧の対応が正しく付けられているかどうかを調べる関数です。 - 調べるにはまだ閉じられていない開括弧の数を把握しておきます。 - この関数は次のように動作しなくてはなりません。 + これは、まだ閉じられていない開括弧の数を把握することで、括弧の`String`が平衡しているかどうかを調べる関数です。 + この関数は次のように動作します。 ```text > testParens "" @@ -206,7 +202,7 @@ ask :: forall r. Reader r r local :: forall r a. (r -> r) -> Reader r a -> Reader r a ``` -`ask`アクションは現在の設定を読み取るために使い、 `local`アクションは変更された設定で計算するために使います。 +`ask`動作は現在の設定を読み取るために使い、`local`動作は変更された設定で計算するために使います。 例えば、権限で制御するアプリケーションを開発しており、現在の利用者の権限オブジェクトを保持するのに `Reader`モナドを使いたいとしましょう。 型 `r`を次のようなAPIを備えた型 `Permission`として選択できます。 @@ -228,7 +224,7 @@ createUser = do else pure Nothing ``` -`local`アクションを使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユーザーの権限を昇格させることもできます。 +`local`動作を使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユーザーの権限を昇格させることもできます。 ```haskell runAsAdmin :: forall a. Reader Permissions a -> Reader Permissions a @@ -259,8 +255,8 @@ type Level = Int type Doc = Reader Level String ``` - 1. (簡単)現在の字下げの深さで文字列を出力する関数 `line`を書いてください。 - 関数は以下の型を持つ必要があります。 + 1. (簡単)現在の字下げの深さで関数を書き出す関数`line`を書いてください。 + 関数は以下の型を持ちます。 ```haskell line :: String -> Doc @@ -290,7 +286,7 @@ type Doc = Reader Level String この関数は文書を文字列として出力します。 - これで、このライブラリを次のように使うと、簡単な文書を書くことができるでしょう。 + これでライブラリを使って以下のような単純な文書を書けるようになりました。 ```haskell render $ cat @@ -305,14 +301,15 @@ type Doc = Reader Level String ## Writerモナド -`Writer`モナドは、計算の返り値に加えて、もう1つの値を累積していく機能を提供します。 +`Writer`モナドでは、計算の返り値に加えてもう1つの値を累算できます。 -よくある使い方としては型 `String`もしくは `Array String`でログを累積していくというものなどがありますが、 -`Writer`モナドはこれよりもっと一般的なものです。 -累積するのに任意のモノイドの値を使うことができ、`Additive Int`モノイドを使って、合計を追跡し続けるのに使ったり、 `Disj -Boolean`モノイドを使って途中の `Boolean`値の何れかが真であるかどうかを追跡するのに使うことができます。 +よくある使い方としては型`String`もしくは`Array +String`でログを累算していくというものなどがありますが、`Writer`モナドはこれよりもっと一般的なものです。 +累算するのに任意のモノイドの値を使うことができるので、`Additive Int`モノイドを使って整数の合計を追跡するのに使ったり、`Disj +Boolean`モノイドを使って途中の`Boolean`値の何れかが真であるかどうかを追跡するのに使えます。 -`Writer`型の構築子は、 `Monoid`型クラスのインスタンスである型 `w`、および返り値の型 `a`という2つの型引数を取ります。 +`Writer`型構築子は2つの型引数を取ります。 +`Monoid`型クラスのインスタンスである型`w`と返り値の型`a`です。 `Writer`のAPIで重要なのは `tell`関数です。 @@ -320,9 +317,10 @@ Boolean`モノイドを使って途中の `Boolean`値の何れかが真であ tell :: forall w a. Monoid w => w -> Writer w Unit ``` -`tell`アクションは、与えられた値を現在の累積結果に付け加えます。 +`tell`動作は与えられた値を現在の累算結果に付け加えます。 -例として、 `Array String`モノイドを使用して、既存の関数にログ機能を追加してみましょう。 _最大公約数_ 関数の以前の実装を考えてみます。 +例として、`Array String`モノイドを使用して、既存の関数にログを追加してみましょう。 +*最大公約数*関数の以前の実装を考えてみます。 ```haskell gcd :: Int -> Int -> Int @@ -361,8 +359,8 @@ execWriter :: forall w a. Writer w a -> w runWriter :: forall w a. Writer w a -> Tuple a w ``` -ちょうど `State`モナドの場合と同じように、 `execWriter`が累積されたログだけを返すのに対して、 -`runWriter`は累積されたログと結果の両方を返します。 +ちょうど `State`モナドの場合と同じように、 `execWriter`が累算されたログだけを返すのに対して、 +`runWriter`は累算されたログと結果の両方を返します。 PSCiで改変した関数を試してみましょう。 @@ -378,8 +376,8 @@ Tuple 3 ["gcdLog 21 15","gcdLog 6 15","gcdLog 6 9","gcdLog 6 3","gcdLog 3 3"] 1. (普通)`Writer`モナドと `monoid`パッケージの `Additive Int`モノイドを使うように、上の `sumArray`関数を書き換えてください。 - 1. (普通)*コラッツ関数*は、自然数 `n`が偶数なら `n / 2`、 `n`が奇数なら `3 * n + 1`であると定義されています。 - 例えば`10`で始まるコラッツ数列は次のようになります。 + 1. (普通)*コラッツ*関数は自然数`n`上で定義され、`n`が偶数なら`n / 2`、`n`が奇数なら`3 * n + 1`です。 + 例えば`10`で始まるコラッツ数列は以下です。 ```text 10, 5, 16, 8, 4, 2, 1, ... @@ -387,14 +385,14 @@ Tuple 3 ["gcdLog 21 15","gcdLog 6 15","gcdLog 6 9","gcdLog 6 3","gcdLog 3 3"] コラッツ関数の有限回の適用を繰り返すと、コラッツ数列は必ず最終的に `1`になるということが予想されています。 - 数列が `1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する再帰的な関数を書いてください。 + 再帰を使い、数列が`1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する関数を書いてください。 - `Writer`モナドを使用してコラッツ関数のそれぞれの適用の経過を記録するように、関数を変更してください。 + `Writer`モナドを使用してコラッツ関数の各適用の経過を記録するように、関数を変更してください。 ## モナド変換子 上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*の例となっています。 -対応するモナド変換子はそれぞれ `StateT`、 `ReaderT`、 `WriterT`と呼ばれています。 +対応する各モナド変換子はそれぞれ`StateT`、`ReaderT`、`WriterT`という名前です。 モナド変換子とは何でしょうか。 さて、これまで見てきたように、モナドはPureScriptのコードを何らかの種類の副作用で拡張するものでした。 @@ -405,10 +403,11 @@ Tuple 3 ["gcdLog 21 15","gcdLog 6 15","gcdLog 6 9","gcdLog 6 3","gcdLog 3 3"] もしくは、 `Either`モナドの純粋なエラー追跡機能と、 `State`モナドが提供する変更可能な状態が同時に欲しくなるかもしれません。 この問題を解決するのが*モナド変換子*です。 -ただし`Effect`モナドがこの問題に対する部分的な解決策を提供していたことは既に見てきました。 -モナド変換子はまた違った解決策を提供しますが、これらの手法にはそれぞれ利点と制約があります。 +ただし`Effect`モナドがこの問題を部分的に解決することは既に見ました。 +モナド変換子はまた違った解決策を提供しますが、これらの各手法には利点と制約があります。 -モナド変換子は型だけでなく別の型構築子もパラメータに取る型構築子です。モナド変換子はモナドを1つ取り、独自のいろいろな副作用を追加した別のモナドへと変換します。 +モナド変換子は型と別の型構築子を引数に取る型構築子です。 +モナドを1つ取り、独自の様々な副作用を追加した別のモナドへと変換します。 例を見てみましょう。`State`のモナド変換子版は`Control.Monad.State.Trans`モジュールで定義されている`StateT`です。 PSCiを使って `StateT`の種を見てみましょう。 @@ -446,30 +445,29 @@ Type -> Type Type ``` -最後に、種 `Type`の何かが残りましたが、これはつまりこの型の値を探してみることができるということです。 +最後に種`Type`の何かが残りました。 +つまりこの型の値を探してみることができます。 -構築したモナド `StateT String (Either -String)`は、エラーで失敗する可能性があり、変更可能な状態を使える計算を表しています。 +構築したモナド`StateT String (Either String)`は、エラーで失敗する可能性があり、変更可能な状態を使える計算を表しています。 -外側の `StateT String (Either -String)`モナドのアクション(`get`、`put`、`modify`)は直接使うことができますが、梱包されている内側のモナド (`Either -String`) の作用を使うためには、これらの関数をモナド変換子まで「持ち上げ」なくてはいけません。 -`Control.MonadTrans`モジュールでは、モナド変換子であるような型構築子を捉える`MonadTrans`型クラスを次のように定義しています。 +外側の`StateT String`モナドの動作(`get`、`put`、`modify`)は直接使えますが、梱包されているモナド (`Either +String`) の作用を使うためには、これらの関数をモナド変換子まで「持ち上げ」る必要があります。 +`Control.Monad.Trans`モジュールは`MonadTrans`型クラスを定義しています。 +これはモナド変換子であるそうした型構築子を捕捉します。 ```haskell class MonadTrans t where lift :: forall m a. Monad m => m a -> t m a ``` -このクラスは、基礎となる任意のモナド `m`の計算をとり、それを梱包されたモナド `t m`へと持ち上げる、 -`lift`という1つの関数だけを持っています。 -今回の場合、型構築子 `t`は `StateT String`で、 `m`は `Either String`モナドとなり、 `lift`は型 -`Either String a`の計算を、型 `State String (Either String) -a`の計算へと持ち上げる方法を提供することになります。 -これは、型 `Either String a`の計算を使うときは、 `lift`を使えばいつでも作用 `StateT String`と `Either -String`を一緒に使うことができることを意味します。 +このクラスは単一のメンバー`lift`を含みます。 +これは通底する任意のモナド`m`の計算を取り、梱包されたモナド`t m`へと持ち上げるものです。 +今回の場合、型構築子`t`は`StateT String`で、`m`は`Either String`モナドとなるので、`lift`は型`Either +String a`の計算を、型`StateT String (Either String) a`の計算へと持ち上げる方法を提供することになります。 +つまり、型`Either String a`の計算を使う場合に毎回`lift`を使うのであれば、`StateT String`と`Either +String`の作用を使えます。 -例えば、次の計算は `StateT`モナド変換子で導入されている状態を読み込み、状態が空の文字列である場合はエラーを投げます。 +例えば、次の計算は通底する状態を読み、状態が空文字列であればエラーを投げます。 ```haskell import Data.String (drop, take) @@ -484,7 +482,7 @@ split = do pure (take 1 s) ``` -状態が空でなければ、この計算は `put`を使って状態を `drop 1 s`(最初の文字を取り除いた `s`)へと更新し、 `take 1 +状態が空でなければ、この計算は`put`を使って状態を`drop 1 s`(つまり`s`から最初の文字を取り除いたもの)へと更新し、`take 1 s`(`s`の最初の文字)を返します。 それではPSCiでこれを試してみましょう。 @@ -497,22 +495,24 @@ Right (Tuple "t" "est") Left "Empty string" ``` -これは `StateT`を使わなくても実装できるので、さほど驚くようなことはありません。 -しかし、モナドとして扱っているので、do記法やアプリカティブコンビネータを使って、小さな計算から大きな計算を構築していくことができます。 -例えば、2回 `split`を適用すると、文字列から最初の2文字を読むことができます。 +これは`StateT`を使わなくても実装できるので、さほど驚くようなことはありません。 +しかし、モナドの中で扱っているので、do記法やアプリカティブコンビネータを使って、小さな計算から大きな計算を構築できます。 +例えば、2回`split`を適用すると、文字列から最初の2文字を読めます。 ```text > runStateT ((<>) <$> split <*> split) "test" (Right (Tuple "te" "st")) ``` -他にもアクションを沢山用意すれば、 `split`関数を使って、基本的な構文解析ライブラリを構築できます。これは実際に -`parsing`ライブラリで採用されている手法です。これがモナド変換子の力なのです。必要な副作用を選択して、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。 +`split`関数とその他沢山の動作を使えば基本的な構文解析ライブラリを構築できます。 +実際、これは`parsing`ライブラリで採用されている手法です。 +これがモナド変換子の力なのです。 +必要な副作用を選択し、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。 ## ExceptTモナド変換子 -`transformers`パッケージでは、 `Either e`モナドに対応する変換子である`ExceptT e`モナド変換子も定義されています。 -これは次のAPIを提供します。 +`transformers`パッケージでは`ExceptT e`モナド変換子も定義されています。 +これは`Either e`モナドに対応するもので、以下のAPIを提供します。 ```haskell class MonadError e m where @@ -524,10 +524,10 @@ instance Monad m => MonadError e (ExceptT e m) runExceptT :: forall e m a. ExceptT e m a -> m (Either e a) ``` -`MonadError`クラスは `e`型のエラーを投げたりキャッチに対応したりするモナドを取得し、 `ExceptT +`MonadError`クラスは`e`型のエラーを投げたり捕えたりに対応するモナドを捕捉し、`ExceptT e`モナド変換子のインスタンスが提供されます。 -`Either e`モナドの `Left`と同じように、 `throwError`アクションは失敗を示すために使われます。 -`catchError`アクションを使うと、 `throwError`でエラーが投げられたあとでも処理を継続できるようになります。 +`Either e`モナドの`Left`と同じように、`throwError`動作では失敗を示せます。 +`catchError`動作では`throwError`を使ってエラーが投げられた後に処理を継続できます。 `runExceptT`制御子を使うと、型 `ExceptT e m a`を計算できます。 @@ -538,9 +538,8 @@ e`モナド変換子のインスタンスが提供されます。 - `Exception`作用がJavaScriptの`Error`型という1つの例外の型だけを扱うのに対して、`ExceptT`は`Error`型クラスのどんな型のエラーでも扱います。つまり、 `ExceptT`では新たなエラー型を自由に定義できます。 -試しに `ExceptT`を使って `Writer`モナドを包んでみましょう。 -ここでもモナド変換子 `ExceptT e`のアクションを直接使うことも自由にできますが、`Writer`モナドの計算は -`lift`を使って持ちあげるべきです。 +試しに`ExceptT`を使って`Writer`モナドを包んでみましょう。 +ここでもモナド変換子`ExceptT e`の動作を直接使うことも自由にできますが、`Writer`モナドの計算は`lift`を使って持ち上げるべきです。 ```haskell import Control.Monad.Except @@ -564,22 +563,22 @@ String)`の結果を残します。 Tuple (Left "Error!") ["Before the error"] ``` -実際に追加されるログは、エラーが投げられる前に書かれたログメッセージだけであることにも注目してください。 +なお、エラーが投げられる前に書き出されるログ文言だけがログに追記されます。 ## モナド変換子スタック -これまで見てきたように、モナド変換子を使うと既存のモナドを土台に新しいモナドを構築できます。 -任意のモナド変換子 `t1`と任意のモナド`m`について、その適用 `t1 m`もまたモナドになります。 -これは*2つめの*モナド変換子 `t2`を先ほどの結果 `t1 m`に適用すると、3つ目のモナド `t2 (t1 m)`を作れることを意味しています。 -このように、構成するモナドによって提供された副作用を組み合わせる、モナド変換子の*スタック*を構築できます。 +これまで見てきたように、モナド変換子を使って既存のモナドを土台に新しいモナドを構築できます。 +何かのモナド変換子`t1`とモナド`m`について、その適用`t1 m`もまたモナドになります。 +つまり、*2つめの*モナド変換子`t2`を結果`t1 m`に適用すると、3つ目のモナド`t2 (t1 m)`を作れます。 +このようにしてモナド変換子の*スタック*を構築できます。 +これは構成されるモナドによって提供される副作用を組み合わせるものです。 -実際には、基本となるモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さもなくば -`Data.Identity`モジュールで定義されている`Identity`モナドになります。 +実際には、通底するモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さもなくば`Data.Identity`モジュールで定義されている`Identity`モナドになります。 `Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換はモナド変換子の作用だけを提供します。 -実際に、`State`モナドと`Reader`モナドと`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`と`ReaderT`と`WriterT`で変換することによって実装されています。 +`State`、`Reader`、`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`、`ReaderT`、`WriterT`で変換することによって実装されています。 -それでは3つの副作用が組み合わされている例を見てみましょう。 -`Identity`モナドをスタックの底にして、 `StateT`作用、 `WriterT`作用、`ExceptT`作用を使います。 +3つの副作用が組み合わっている例を見てみましょう。 +`Identity`モナドをスタックの底にして、`StateT`、`WriterT`、`ExceptT`作用を使います。 このモナド変換子スタックは、可変状態、ログの蓄積、そして純粋なエラーの副作用を提供します。 このモナド変換子スタックを使うと、ロギングの機能が追加された `split`アクションに作り変えられます。 @@ -604,10 +603,9 @@ split = do この計算をPSCiで試してみると、 `split`が実行されるたびに状態がログに追加されることがわかります。 -モナド変換子スタックに現れる順序に従って、副作用を取り除いていかなければならないことに注意してください。 -最初に `StateT`型構築子を取り除くために `runStateT`を使い、それから -`runtWriteT`を使い、その後`runExceptT`を使います。 -最後に `unwrap`を使用して `Identity`モナドを演算します。 +なお、モナド変換子スタックに現れる順序で副作用を取り除いていかなければなりません。 +最初に`StateT`型構築子を取り除くために`runStateT`を、それから`runtWriteT`、`runExceptT`を使います。 +最後に`unwrap`を使用して`Identity`モナド中で計算します。 ```text > runParser p s = unwrap $ runExceptT $ runWriterT $ runStateT p s @@ -626,14 +624,13 @@ split = do (Left ["Empty string"]) ``` -これは、 `ExceptT`モナド変換子が提供する副作用が、 `WriterT`モナド変換子が提供する副作用と干渉するためです。 -これはモナド変換子スタックが構成されている順序を変更することで解決できます。 -スタックの最上部に `ExceptT`変換子を移動すると、先ほど `Writer`を -`ExceptT`に変換したときと同じように、最初のエラーまでに書かれた全てのメッセージが含まれるようになります。 +これは、`ExceptT`モナド変換子が提供する副作用と`WriterT`モナド変換子が提供する副作用との関係によるものです。 +これはモナド変換子スタックが構成されている順序を変更することで対処できます。 +スタックの最上部に`ExceptT`変換子を移動すると、先ほど`Writer`を`ExceptT`に変換したときに見たように、最初のエラーまでに書かれた全ての文言がログに含まれるようになります。 -このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、 `lift`関数を複数回使わなければならないということです。 -例えば`throwError`の呼び出しは、1回目は `WriteT`へ、2回目は `StateT`へと、2回持ちあげなければなりません。 -小さなモナド変換子スタックならなんとかなりますが、そのうち不便だと感じるようになるでしょう。 +このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、`lift`関数を複数回使わなければならないということです。 +例えば`throwError`の呼び出しは、1回目は`WriteT`へ、2回目は`StateT`へ、と2回持ちあげなければなりません。 +小さなモナド変換子スタックならなんとかなりますが、そのうちすぐに不便になるでしょう。 幸いなことに、これから見るような型クラス推論によって提供されるコードの自動生成を使うと、ほとんどの「重労働」を任せられます。 @@ -648,7 +645,7 @@ split = do string :: String -> Parser String ``` - これは現在の状態が接頭辞に適合するか、もしくはエラーメッセージとともに失敗します。 + これは現在の状態が接頭辞に照合するか、もしくはエラー文言とともに失敗します。 この構文解析器は次のように動作します。 @@ -657,16 +654,17 @@ split = do (Right (Tuple (Tuple "abc" "def") ["The state is abcdef"])) ``` - *手掛かり*:出発点として`split`の実装を使うといいでしょう。 - `stripPrefix`関数も役に立ちます。 -1. (難しい)以前 `Reader`モナドを使用して書いた文書表示ライブラリを、`ReaderT`と `WriterT`モナド変換子を使用して再実装してください。 + *手掛かり*:出発点として`split`の実装が使えます。 + `stripPrefix`関数も役に立つかもしれません。 +1. (難しい)文書表示ライブラリを、`ReaderT`と`WriterT`モナド変換子を使用して再実装してください。 + 以前`Reader`モナドを使用して書いたものです。 文字列を出力する `line`や文字列を連結する `cat`を使うのではなく、`WriteT`モナド変換子と一緒に `Array String`モノイドを使い、結果へ行を追加するのに `tell`を使ってください。 アポストロフィ (`'`) を付ける以外は元の実装と同じ名前を使ってください。 ## 型クラスが助けに来たぞっ -本章の最初で扱った `State`モナドを見てみると、 `State`モナドのアクションには次のような型が与えられていました。 +本章の最初で扱った `State`モナドを見てみると、 `State`モナドの動作には次のような型が与えられていました。 ```haskell get :: forall s. State s s @@ -687,32 +685,29 @@ modify :: forall m s. MonadState s m => (s -> s) -> m Unit 予想できると思いますが、 `State s`型構築子は `MonadState s`型クラスのインスタンスになっており、このクラスには他にも興味深いインスタンスが数多くあります。 -特に、 `transformers`パッケージではモナド変換子 `WriterT`、 `ReaderT`、`ExceptT`についての -`MonadState`のインスタンスが提供されています。 -通底する`Monad`が`MonadState`インスタンスを持っていれば常に、これらのモナド変換子にもインスタンスがあります。 -実践的には、 `StateT`がモナド変換子スタックの*どこか*に現れ、 `StateT`より上の全てが -`MonadState`のインスタンスであれば、 `get`、 `put`、 `modify`を直接自由に使用できます。 +特に、`transformers`パッケージではモナド変換子`WriterT`、`ReaderT`、`ExceptT`についての`MonadState`のインスタンスがあります。 +通底する`Monad`が`MonadState`インスタンスを持つなら常に、これらもインスタンスを持ちます。 +つまり実際には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく`get`や`put`や`modify`を直接自由に使用できます。 -当然ですが、これまで扱ってきた `ReaderT`、 `WriterT`、 -`ExceptT`変換子についても、同じことが成り立っています。`transformers`では主な変換子それぞれについての型クラスが定義されています。これによりそれらの操作に対応するモナドの上に抽象化できるのです。 +当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが言えます。 +`transformers`では主な各変換子について型クラスが定義されています。 +これによりそれらの操作に対応するモナドの上に抽象化できるのです。 -上の `split`関数の場合、構築されたこのモナドスタックは型クラス`MonadState`、 `MonadWriter`、 -`MonadError`それぞれのインスタンスです。 -これはつまり、`lift`は全く呼び出す必要がないのです。 -まるでモナドスタック自体に定義されていたかのように、アクション `get`、`put`、 `tell`、 -`throwError`をそのまま使用できます。 +上の`split`関数の場合、構築したモナドスタックは各型クラス`MonadState`、`MonadWriter`、`MonadError`のインスタンスです。 +つまり`lift`は全く呼び出す必要がないのです。 +まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、`tell`、`throwError`をそのまま使用できます。 ```haskell {{#include ../exercises/chapter11/src/Split.purs:split}} ``` -この計算はまるで、可変状態、ロギング、エラー処理という3つの副作用に対応した、独自のプログラミング言語を拡張したかのようにみえます。 -しかし、内部的には全てはあくまで純粋な関数と普通のデータを使って実装されているのです。 +この計算は、独自のプログラミング言語を拡張し、可変状態、ロギング、エラー処理という3つの新しい副作用に対応したように見えます。 +しかし、内部的には全てはあくまで純粋な関数と不変のデータを使って実装されているのです。 ## 代替 -`control`パッケージでは失敗しうる計算を制御するための抽象化が幾つか定義されています。 -その1つは `Alternative`型クラスです。 +`control`パッケージでは失敗しうる計算を扱う抽象化が数多く定義されています。 +その1つは`Alternative`型クラスです。 ```haskell class Functor f <= Alt f where @@ -737,8 +732,8 @@ some :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a) `Data.List`にも等価な`many`と`some`があります。 -`many`コンビネータは計算を _ゼロ回以上_ 繰り返し実行するために`Alternative`型クラスを使用しています。 -`some`コンビネータも似ていますが、成功するために少なくとも1回の計算を必要とします。 +`many`コンビネータは計算を*ゼロ回以上*繰り返し実行するために`Alternative`型クラスを使います。 +`some`コンビネータも似ていますが、最低1回は計算が成功する必要があります。 `Parser`モナド変換子スタックの場合は、`ExceptT`コンポーネントによる`Alternative`のインスタンスがあります。 このコンポーネントでは異なる分枝のエラーに`Monoid`インスタンスを使って組み合わせることによって対応しています(だから`Errors`型に`Array @@ -771,23 +766,24 @@ class (Monad m, Alternative m) <= MonadPlus m 実際、`Parser`モナドは `MonadPlus`のインスタンスです。 -以前本書中で配列内包表記を扱ったとき、不要な結果を除いて絞り込むために使われる`guard`関数を導入しました。 -実際には`guard`関数はもっと一般的で、 `MonadPlus`のインスタンスである全てのモナドに対して使うことができます。 +以前本書中で配列内包表記を押さえたとき、`guard`関数を導入しました。 +これは欲しくない結果を取り除けるのに使えました。 +実際には`guard`関数はもっと一般的で、`MonadPlus`のインスタンスである任意のモナドに対して使えます。 ```haskell guard :: forall m. Alternative m => Boolean -> m Unit ``` `<|>`演算子は失敗時にバックトラッキングできるようにします。 -これがどのように役立つかを見るために、大文字だけに適合する `split`コンビネータの亜種を定義してみましょう。 +これがどのように役立つかを見るために、大文字だけに照合する`split`コンビネータの亜種を定義してみましょう。 ```haskell {{#include ../exercises/chapter11/src/Split.purs:upper}} ``` -ここで、文字列が大文字でない場合に失敗するよう -`guard`を使用しています。このコードは前に見た配列内包表記とよく似ていることに注目してください。このように`MonadPlus`を使うことは、 -_モナド内包表記_ (monad comprehensions) の構築と呼ばれることがあります。 +ここで、文字列が大文字でない場合に失敗するよう、`guard`を使用しています。 +なお、このコードは前に見た配列内包表記とよく似ています。 +このように`MonadPlus`を使うことは、*モナド内包表記*の構築と呼ばれることがあります。 ## バックトラッキング @@ -798,13 +794,13 @@ _モナド内包表記_ (monad comprehensions) の構築と呼ばれることが {{#include ../exercises/chapter11/src/Split.purs:lower}} ``` -これにより、まずもし最初の文字が大文字なら複数の大文字に適合し、さもなくばもし最初の文字が小文字なら複数の小文字に適合する、という構文解析器を定義できます。 +これにより、まずもし最初の文字が大文字なら複数の大文字に照合し、さもなくばもし最初の文字が小文字なら複数の小文字に照合する、という構文解析器を定義できます。 ```text > upperOrLower = some upper <|> some lower ``` -この構文解析器は、大文字と小文字が切り替わるまで、文字に適合し続けます。 +この構文解析器は、大文字と小文字が切り替わるまで、文字に照合し続けます。 ```text > runParser upperOrLower "abcDEF" @@ -833,17 +829,17 @@ _モナド内包表記_ (monad comprehensions) の構築と呼ばれることが ])) ``` -繰り返しになりますが、これはモナド変換子がもたらす再利用性の威力を示しています。 +繰り返しになりますが、これはモナド変換子が齎す再利用性の威力を示しています。 標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器を、ほんの数行のコードで書くことができました。 ## 演習 - 1. (簡単)`string`構文解析器の実装から `lift`関数の呼び出しを取り除いてください。 - 新しい実装の型が整合していることを確認し、なぜそのようになるのかをよく納得しておきましょう。 - 1. (普通)`string`構文解析器と `many`コンビネータを使って、文字列`"a"`の連続と、それに続く文字列 - `"b"`の連続からなる文字列を認識する構文解析器`asFollowedByBs`を書いてください。 - 1. (普通)`<|>`演算子を使って、文字 `a`と文字 - `b`が任意の順序で現れるような文字列を認識する構文解析器`asOrBs`を書いてください。 + 1. (簡単)`string`構文解析器の実装から`lift`関数の呼び出しを取り除いてください。 + 新しい実装の型検査が通ることを確認し、そうなることを納得するまで確かめましょう。 + 1. (普通)`string`構文解析器と`some`コンビネータを使って構文解析器`asFollowedByBs`を書いてください。 + これは文字列`"a"`の連続と、それに続く文字列`"b"`の連続からなる文字列を認識するものです。 + 1. (普通)`<|>`演算子を使って構文解析器`asOrBs`を書いてください。 + これは文字`a`と文字`b`が任意の順序で現れる文字列を認識します。 1. (難しい)`Parser`モナドを次のようにも定義できます。 ```haskell @@ -855,9 +851,8 @@ _モナド内包表記_ (monad comprehensions) の構築と呼ばれることが ## RWSモナド モナド変換子のとある特定の組み合わせは頻出なので、`transformers`パッケージ内の単一のモナド変換子として提供されています。 -`Reader`、 -`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わさり、より単純に`RWS`モナドともされます。 -このモナドは `RWST`モナド変換子と呼ばれる、対応するモナド変換子を持っています。 +`Reader`、`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わさり、より単純に`RWS`モナドともされます。 +このモナドは`RWST`モナド変換子という名前の、対応するモナド変換子を持ちます。 ここでは `RWS`モナドを使ってテキストアドベンチャーゲームの処理を設計していきます。 @@ -867,10 +862,12 @@ _モナド内包表記_ (monad comprehensions) の構築と呼ばれることが type RWS r w s = RWST r w s Identity ``` -ここで、副作用を提供しない`Identity`を基底のモナドに設定することで、 `RWS`モナドが独自のモナド変換子を用いて定義されています。 +なお、`RWS`モナドは基底のモナドを`Identity`に設定することで独自のモナド変換子として定義されています。 +`Identity`は副作用を提供しないのでした。 -第1型引数 `r`は大域的な設定の型を表します。 -第2型引数 `w`はログを蓄積するために使用するモノイド、第3型引数 `s`は可変状態の型を表しています。 +最初の型引数`r`は大域的な構成の型を表します。 +2つ目の`w`はログを蓄積するために使用するモノイドを表します。 +3つ目の`s`は可変状態の型です。 このゲームの場合には、大域的な設定は `Data.GameEnvironment`モジュールの`GameEnvironment`という名前の型で定義されています。 @@ -880,7 +877,7 @@ type RWS r w s = RWST r w s Identity ``` プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義されています。 -これらのオプションは、モナド変換子を実行するときにコマンドラインから設定されます。 +モナド変換子を実行するとなると、これらのオプションがコマンドラインから設定されます。 可変状態は `Data.GameState`モジュールの `GameState`と呼ばれる型で定義されています。 @@ -898,13 +895,13 @@ type RWS r w s = RWST r w s Identity `GameState`型は2つの新しいデータ構造を使っています。 `Map`と`Set`はそれぞれ整列されたマップと整列された集合を表します。 -`items`属性は、そのゲーム平面上の座標からゲームアイテムの集合への対応付けになっています。 -`player`属性はプレイヤーの現在の座標を格納しており、 `inventory`属性は現在プレイヤーが保有するゲームアイテムの集合です。 +`items`属性は、ゲーム平面上の座標からその位置にあるゲームアイテムの集合への対応付けです。 +`player`属性はプレイヤーの現在の座標を格納し、`inventory`属性は現在プレイヤーが保有するゲームアイテムの集合を格納します。 -`Map`と `Set`のデータ構造はキーによって整列され、 -`Ord`型クラスの任意の型をキーとして使用できます。これは今回のデータ構造のキーが完全に順序付けできることを意味します。 +`Map`と`Set`のデータ構造はキーによって整列され、このキーには`Ord`型クラスの任意の型を使えます。 +つまりデータ構造中のキーは完全に順序付けされます。 -ゲームのアクションを書く上で`Map`と `Set`構造をどのように使っていくのかを見ていきます。 +ゲームの動作を書く上で`Map`と`Set`構造をどのように使っていくのかを見ていきます。 ログとしては `List String`モノイドを使います。 `Game`モナド用の型同義語を定義し、`RWS`を使って実装できます。 @@ -915,23 +912,23 @@ type RWS r w s = RWST r w s Identity ## ゲームロジックの実装 -今回は`Reader`モナドと`Writer`モナドと`State`モナドのアクションを再利用し、`Game`モナドで定義されている単純なアクションを組み合わせてゲームを構築していきます。 -このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドはコンソールにテキストを出力するような観測可能な副作用へと結果を変換するために使っています。 +`Reader`、`Writer`、`State`モナドの動作を再利用することで、`Game`モナドで定義されている単純な動作を組み合わせてゲームを構築していきます。 +このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドは結果からコンソールにテキストを出力するような観測可能な副作用へと変換するために使っています。 -このゲームで最も簡単なアクションの1つは -`has`アクションです。このアクションはプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調べます。これは次のように定義されます。 +このゲームで最も簡単な動作の1つは `has`動作です。 +この動作はプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調べます。 +これは次のように定義されます。 ```haskell {{#include ../exercises/chapter11/src/Game.purs:has}} ``` -この関数は、現在のゲームの状態を読み取るために `MonadState`型クラスで定義されている `get`アクションを使っています。 -またそれから指定した`GameItem`が持ち物アイテムの`Set`に出現するかどうかを調べるために`Data.Set`で定義されている -`member`関数を使っています。 +この関数は、現在のゲームの状態を読み取るために`MonadState`型クラスで定義されている`get`動作を使っています。 +それから指定した`GameItem`が持ち物のアイテムの`Set`に出現するかどうかを調べるために`Data.Set`で定義されている`member`関数を使っています。 -他にも `pickUp`アクションがあります。 +他にも`pickUp`動作があります。 現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加します。 -これには`MonadWriter`と `MonadState`型クラスのアクションを使っています。 +これには`MonadWriter`と`MonadState`型クラスの動作を使っています。 一番最初に現在のゲームの状態を読み取ります。 ```haskell @@ -945,8 +942,9 @@ type RWS r w s = RWST r w s Identity {{#include ../exercises/chapter11/src/Game.purs:pickup_case}} ``` -`lookup`関数は `Maybe`型構築子で示されたオプショナルな結果を返します。 -`lookup`関数は、キーがマップにない場合は `Nothing`を返し、それ以外の場合は `Just`構築子で対応する値を返します。 +`lookup`関数は`Maybe`型構築子で示される省略可能な結果を返します。 +`lookup`関数は、キーがマップにない場合は`Nothing`を返します。 +それ以外の場合は`Just`構築子で対応する値を返します。 関心があるのは、指定されたゲームアイテムが対応するアイテムの集合に含まれている場合です。 ここでも`member`関数を使うとこれを調べることができます。 @@ -955,21 +953,21 @@ type RWS r w s = RWST r w s Identity {{#include ../exercises/chapter11/src/Game.purs:pickup_Just}} ``` -この場合、 `put`を使ってゲームの状態を更新し、 `tell`を使ってログにメッセージを追加できます。 +この場合、`put`を使ってゲームの状態を更新し、`tell`を使ってログに文言を追加できます。 ```haskell {{#include ../exercises/chapter11/src/Game.purs:pickup_body}} ``` ここで2つの計算のどちらも`lift`が必要ないことに注意してください。 -なぜなら`MonadState`と `MonadWriter`の両方について `Game`モナド変換子スタック用の適切なインスタンスが存在するからです。 +なぜなら`MonadState`と`MonadWriter`の両方について`Game`モナド変換子スタック用の適切なインスタンスが存在するからです。 -`put`への引数では、レコード更新を使ってゲームの状態の `items`と`inventory`フィールドを変更しています。 -また、特定のキーの値を変更する`Data.Map`の `update`関数を使っています。 -このとき、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`関数を使って指定したアイテムを集合から取り除いています。 -`insert`を使って新しいアイテムをプレイヤーの持ち物集合に加えるときにも、`inventory`は更新されます。 +`put`への引数では、レコード更新を使ってゲームの状態の`items`及び`inventory`フィールドを変更しています。 +また、特定のキーの値を変更する`Data.Map`の`update`関数を使っています。 +今回の場合、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`関数を使って指定したアイテムを集合から取り除いています。 +`insert`を使って新しいアイテムをプレイヤーの持ち物の集合に加えるときにも、`inventory`は更新されます。 -最後に、`pickUp`関数は `tell`を使ってユーザに次のように通知することにより、残りの場合を処理します。 +最後に、`pickUp`関数は`tell`を使ってユーザに通知することにより、残りの場合を処理します。 ```haskell {{#include ../exercises/chapter11/src/Game.purs:pickup_err}} @@ -982,18 +980,18 @@ type RWS r w s = RWST r w s Identity {{#include ../exercises/chapter11/src/Game.purs:debug}} ``` -ここでは、ゲームの設定を読み込むために `ask`アクションを使用しています。 -繰り返しますが、どの計算でも`lift`は必要がなく、同じdo記法ブロック内で`MonadState`、 `MonadReader`、 -`MonadWriter`型クラスで定義されているアクションを使うことができることに注意してください。 +ここでは、ゲームの構成を読み込むために`ask`動作を使用しています。 +繰り返しますが、どの計算でも`lift`する必要がなく、同じdo記法ブロック内で`MonadState`、`MonadReader`、`MonadWriter`型クラスで定義されている動作を使える点に注意してください。 -`debugMode`フラグが設定されている場合、 `tell`アクションを使うとログに状態が追加されます。 -そうでなければ、エラーメッセージが追加されます。 +`debugMode`フラグが設定されている場合、`tell`動作を使うとログに状態が書き込まれます。 +そうでなければ、エラー文言が追加されます。 -`Game.purs`モジュールの残りの部分では、`MonadState`型クラスと`MonadReader`型クラスと`MonadWriter`型クラスでそれぞれ定義されたアクションだけを使い、同様のアクションが定義されています。 +`Game`モジュールの残りの部分では同様の動作の集合が定義されています。 +各動作は`MonadState`、`MonadReader`、`MonadWriter`型クラスにより定義された動作のみを使っています。 ## 計算の実行 -このゲームロジックは `RWS`モナドで動くため、ユーザのコマンドに応答するためには計算する必要があります。 +このゲームロジックは`RWS`モナドで動くため、ユーザのコマンドに応答するために計算する必要があります。 このゲームのフロントエンドは2つのパッケージで構成されています。 アプリカティブなコマンドライン構文解析を提供する`optparse`と、対話的なコンソールベースのアプリケーションを書くことを可能にする、NodeJSの @@ -1005,7 +1003,7 @@ type RWS r w s = RWST r w s Identity {{#include ../exercises/chapter11/src/Game.purs:game_sig}} ``` -これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してから、 `runRWS`を使って `RWS`の計算結果を実行します。 +これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してから、`runRWS`を使って結果の`RWS`を計算します。 ```haskell data RWSResult state result writer = RWSResult state result writer @@ -1013,8 +1011,8 @@ data RWSResult state result writer = RWSResult state result writer runRWS :: forall r w s a. RWS r w s a -> r -> s -> RWSResult s a w ``` -`runRWS`は `runReader`、 `runWriter`、 `runState`を組み合わせたように見えます。 -これは、引数として大域的な設定及び初期状態をとり、ログ、結果、最的な終状態を含むデータ構造を返します。 +`runRWS`は`runReader`、`runWriter`、`runState`を組み合わせたように見えます。 +引数として大域的な構成及び初期状態を取り、ログ、結果、最終的な状態を含むデータ構造を返します。 このアプリケーションのフロントエンドは、次の型シグネチャを持つ関数`runGame`によって定義されます。 @@ -1026,7 +1024,7 @@ runRWS :: forall r w s a. RWS r w s a -> r -> s -> RWSResult s a w `runGame`は関数の引数としてのゲームの設定を取ります。 `node-readline`パッケージでは`LineHandler`型が提供されています。 -これは端末からのユーザ入力を扱う `Effect`モナドのアクションを表します。 +これは端末からのユーザ入力を扱う`Effect`モナドの動作を表します。 対応するAPIは次の通りです。 ```haskell @@ -1039,8 +1037,8 @@ foreign import setLineHandler -> Effect Unit ``` -`Interface`型はコンソールの制御対象を表しており、コンソールとやり取りする関数への引数として渡されます。 -`createConsoleInterface`関数を使用すると `Interface`を作成できます。 +`Interface`型はコンソールの制御子を表しており、コンソールとやり取りする関数への引数として渡されます。 +`createConsoleInterface`関数を使用すると`Interface`を作成できます。 ```haskell {{#include ../exercises/chapter11/src/Main.purs:import_RL}} @@ -1067,14 +1065,14 @@ foreign import setLineHandler この制御子は追加の最初の引数としてゲームの状態を取ります。 ゲームのロジックを実行するために`runRWS`にゲームの状態を渡さなければならないので、これは必要となっています。 -このアクションが最初に行うことは、 `Data.String`モジュールの `split`関数を使用して、ユーザーの入力を単語に分割することです。 -それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`モナドで)`game`アクションを実行しています。 +この動作が最初に行うことは、`Data.String`モジュールの `split`関数を使用して、ユーザーの入力を単語に分割することです。 +それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`モナドで)`game`動作を実行しています。 -純粋な計算であるゲームロジックを実行するには、画面に全てのログメッセージを出力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。 -`for_`アクションが(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。 -最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`アクションを使ってプロンプトを再び表示しています。 +純粋な計算であるゲームロジックを実行するには、画面に全てのログ文言を出力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。 +`for_`動作が(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。 +最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`動作を使ってプロンプトを再び表示しています。 -`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付けて、最初のプロンプトを表示します。 +`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付けて、初期プロンプトを表示します。 ```haskell {{#include ../exercises/chapter11/src/Main.purs:runGame_attach_handler}} @@ -1084,12 +1082,12 @@ foreign import setLineHandler 1. (普通)ゲームの格子上にある全てのゲームアイテムをユーザの持ちものに移動する新しいコマンド `cheat`を実装してください。 関数`cheat :: Game Unit`を`Game`モジュールに作り、この関数を`game`から使ってください。 - 1. (難しい)`RWS`モナドの ` - Writer`コンポーネントは、エラーメッセージと情報メッセージの2つの種類のメッセージのために使われています。 + 1. (難しい)`RWS`モナドの ` Writer`コンポーネントは、エラー文言とお知らせ文言の2つの種類の文言のために使われています。 このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用しています。 - エラーメッセージを扱うのに `ExceptT`モナド変換子を使うようにし、情報メッセージを扱うのに`RWS`を使うようにするよう、コードをリファクタリングしてください。 - *補足*:この演習にはテストはありません。 + コードをリファクタリングしてください。 + エラー文言を扱うのに`ExceptT`モナド変換子を使い、お知らせ文言を扱うのに`RWS`を使います。 + *補足*:この演習にはテストがありません。 ## コマンドラインオプションの扱い @@ -1114,7 +1112,7 @@ customExecParser :: forall a. ParserPrefs → ParserInfo a → Effect a 最初の引数は`optparse`ライブラリを設定するために使用されます。 今回の場合、アプリケーションが引数なしで走らされたときは、(「missing argument」エラーを表示する代わりに)`OP.prefs -OP.showHelpOnEmpty`を使って使用方法のメッセージを表示するように設定していますが、`Options.Applicative.Builder`モジュールには他にも幾つかの選択肢を提供しています。 +OP.showHelpOnEmpty`を使って使用方法の文言を表示するように設定していますが、`Options.Applicative.Builder`モジュールには他にも幾つかの選択肢を提供しています。 2つ目の引数は解析プログラムの完全な説明です。 @@ -1124,9 +1122,9 @@ OP.showHelpOnEmpty`を使って使用方法のメッセージを表示するよ {{#include ../exercises/chapter11/src/Main.purs:parserOptions}} ``` -ここで`OP.info`は使用方法のメッセージの書式方法のオプションの集合と共に`Parser`を結合します。 +ここで`OP.info`は、`Parser`をヘルプ文言の書式方法のためのオプションの集合と組み合わせます。 `env <**> OP.helper`は`env`と名付けられた任意のコマンドライン引数`Parser`を取り、自動的に`--help`オプションを加えます。 -使用方法のメッセージ用のオプションは型が`InfoMod`であり、これはモノイドなので`fold`関数を使って複数のオプションを一緒に追加できます。 +ヘルプ文言用のオプションは型が`InfoMod`であり、これはモノイドなので、`fold`関数を使って複数のオプションを一緒に追加できます。 解析器の面白い部分は`GameEnvironment`の構築にあります。 @@ -1134,33 +1132,33 @@ OP.showHelpOnEmpty`を使って使用方法のメッセージを表示するよ {{#include ../exercises/chapter11/src/Main.purs:env}} ``` -`player`と`debug`は両方とも`Parser`なので、アプリカティブ演算子`<$>`と`<*>`を使って`gameEnvironment`関数を持ち上げることができます。 +`player`と`debug`は両方とも`Parser`なので、アプリカティブ演算子`<$>`と`<*>`を使って`gameEnvironment`関数を持ち上げられます。 この関数は`Parser`上で型`PlayerName -> Boolean -> GameEnvironment`を持ちます。 -`OP.strOption`は文字列値を期待するコマンドラインオプションを構築し、一緒に畳み込まれた`Mod`の集まりを介して設定されています。 +`OP.strOption`は文字列値を期待するコマンドラインオプションを構築し、一緒に畳み込まれた`Mod`の集まりを介して構成されています。 `OP.flag`は似たような動作をしますが、関連付けられた値は期待しません。 -`optparse`は多種多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。 +`optparse`は多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。 -アプリカティブ演算子による記法を使うことで、コマンドラインインターフェイスに対して簡潔で宣言的な仕様を与えることが可能になったことに注目です。 -また、`runGame`に新しい関数引数を追加し、`env`の定義中で`<*>`を使って追加の引数まで `runGame`を持ち上げるだけで、簡単に新しいコマンドライン引数を追加できます。 +アプリカティブ演算子により齎される記法を使うことで、コマンドラインインターフェイスの簡潔で宣言的な仕様を与えられた点に注目です。 +加えて、新しいコマンドライン引数を追加するのは単純で、`runGame`に新しい関数引数を追加し、`env`の定義中で`<*>`を使って追加の引数まで`runGame`を持ち上げるだけでできます。 ## 演習 1. (普通)`GameEnvironment`レコードに新しい真偽値のプロパティ`cheatMode`を追加してください。 - また、 `optparse`設定に、チートモードを有効にする新しいコマンドラインフラグ `-c`を追加してください。 - チートモードが有効になっていない場合、 `cheat`コマンドは禁止されなければなりません。 + また、`optparse`の構成に、チートモードを有効にする新しいコマンドラインフラグ`-c`を追加してください。 + チートモードが有効になっていない場合、前の演習の`cheat`コマンドは禁止されます。 ## まとめ この章ではこれまで学んできた技術を実践的に実演しました。 -モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロントエンドを構築するための `Effect`モナドがそれです。 +モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロントエンドを構築するための`Effect`モナドがそれです。 ユーザインターフェイスからの実装を分離したので、ゲームの別のフロントエンドも作成できるでしょう。 例えば、`Effect`モナドでCanvas APIやDOMを使用して、ブラウザでゲームを描画するようなことができるでしょう。 -モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見てきました。 +モナド変換子によって命令型のスタイルで安全なコードを書けることが分かりました。 このスタイルでは型システムによって作用が追跡されています。 -また、型クラスはモナドが提供するアクションへと抽象化する強力な方法を提供します。 -このモナドのお陰でコードの再利用が可能になりました。 +加えて、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供し、これによりコードの再利用が可能になりました。 標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のような標準的な抽象化を使用して、役に立つモナドを構築できました。 -モナド変換子は、高階多相や多変数型クラスなどの高度な型システムの機能を利用することによって記述でき、表現力の高いコードの優れた実演となっています。 +モナド変換子は表現力の高いコードの優れた実演となっています。 +これは高階多相や多変数型クラスなどの高度な型システムの機能を利用することによって記述できるものです。 diff --git a/text-ja/chapter12.md b/text-ja/chapter12.md index 650ea4e3..82baa434 100644 --- a/text-ja/chapter12.md +++ b/text-ja/chapter12.md @@ -12,23 +12,21 @@ - `canvas`はHTML5のCanvas APIメソッドの型を与えます。 - `refs`は _大域的な変更可能領域への参照_ を使うための副作用を提供します。 -この章のソースコードは、それぞれに `main`メソッドが定義されているモジュールの集合へと分割されています。 -この章のそれぞれの節の内容は個別のファイルで実装されており、それぞれの時点での適切なファイルの`main`メソッドを実行できるように、Spagoビルドコマンドを変更することで`Main`モジュールを合わせられるようになっています。 +この章の各ソースコードは、`main`メソッドが定義されているモジュールの集合へと分割されています。 +この章の各節の内容は個別のファイルで実装されており、各時点での適切なファイルの`main`メソッドを実行できるように、Spagoビルドコマンドを変更することで、`Main`モジュールを合わせられるようになっています。 -HTMLファイル `html/index.html`には、各例で使用される単一の -`canvas`要素、及びコンパイルされたPureScriptコードを読み込む `script`要素が含まれています。 +HTMLファイル`html/index.html`には、各例で使用される単一の`canvas`要素、及びコンパイルされたPureScriptコードを読み込む`script`要素が含まれています。 +各節のコードを試すにはブラウザでHTMLファイルを開きます。 ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありません。 ## 単純な図形 `Example/Rectangle.purs`ファイルには簡単な導入例が含まれています。 -この例ではcanvasの中心に青い四角形を1つ描画します。 +この例ではキャンバスの中心に青い四角形を1つ描画します。 このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas -APIを扱うための`Effect`モナドのアクションを含む`Graphics.Canvas`モジュールをインポートします。 +APIを扱うための`Effect`モナドの動作を含む`Graphics.Canvas`モジュールをインポートします。 -他のモジュールでも同様ですが、 -`main`アクションは最初に`getCanvasElementById`アクションを使ってcanvasオブジェクトへの参照を取得します。 -また、 `getContext2D`アクションを使ってキャンバスの2D描画コンテキストを参照します。 +他のモジュールでも同様ですが、`main`動作は最初に`getCanvasElementById`動作を使ってキャンバスオブジェクトへの参照を取得し、`getContext2D`動作を使ってキャンバスの2D描画文脈にアクセスします。 `void`関数は関手を取り値を`Unit`で置き換えます。 例では`main`がシグネチャに沿うようにするために使われています。 @@ -39,9 +37,9 @@ APIを扱うための`Effect`モナドのアクションを含む`Graphics.Canva *補足*:この`unsafePartial`の呼び出しは必須です。 これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと照合するためです。 -ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子と照合させ、適切なエラーメッセージを提供したほうがよいでしょう。 +ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子と照合させ、適切なエラー文言を提供したほうがよいでしょう。 -これらのアクションの型はPSCiを使うかドキュメントを見ると確認できます。 +これらの動作の型はPSCiを使うかドキュメントを見ると確認できます。 ```haskell getCanvasElementById :: String -> Effect (Maybe CanvasElement) @@ -52,28 +50,28 @@ getContext2D :: CanvasElement -> Effect Context2D `CanvasElement`と `Context2D`は `Graphics.Canvas`モジュールで定義されている型です。 このモジュールでは`Canvas`作用も定義されており、モジュール内の全てのアクションで使用されています。 -グラフィックスコンテキスト`ctx`はcanvasの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用するためのメソッドを提供します。 +グラフィックス文脈`ctx`はキャンバスの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用したりするための手段を提供します。 -話を進めると、`setFillStyle`アクションを使うことで塗り潰しスタイルを濃い青に設定できます。 +話を進めると、`setFillStyle`動作を使うことで塗り潰しスタイルを濃い青に設定できます。 より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がより簡単です。 ```haskell {{#include ../exercises/chapter12/src/Example/Rectangle.purs:setFillStyle}} ``` -`setFillStyle`アクションがグラフィックスコンテキストを引数として取っていることに注意してください。 -これは `Graphics.Canvas`ではよくあるパターンです。 +`setFillStyle`動作がグラフィックス文脈を引数として取っていることに注意してください。 +これは`Graphics.Canvas`ではよくあるパターンです。 -最後に、 `fillPath`アクションを使用して矩形を塗り潰しています。 +最後に、`fillPath`動作を使用して矩形を塗り潰しています。 `fillPath`は次のような型を持っています。 ```haskell fillPath :: forall a. Context2D -> Effect a -> Effect a ``` -`fillPath`はグラフィックスコンテキストと描画するパスを構築する別のアクションを引数にとります。 -`rect`アクションを使うとパスを構築できます。 -`rect`はグラフィックスコンテキストと矩形の位置及びサイズを格納するレコードを引数にとります。 +`fillPath`はグラフィックスの文脈と描画するパスを構築する他の動作を引数に取ります。 +`rect`動作を使うとパスを構築できます。 +`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを取ります。 ```haskell {{#include ../exercises/chapter12/src/Example/Rectangle.purs:fillPath}} @@ -85,12 +83,13 @@ mainモジュールの名前として`Example.Rectangle`を与えてこの長方 $ spago bundle-app --main Example.Rectangle --to dist/Main.js ``` -それでは `html/index.html`ファイルを開き、このコードによってcanvasの中央に青い四角形が描画されていることを確認してみましょう。 +それでは `html/index.html`ファイルを開き、このコードによってキャンバスの中央に青い四角形が描画されていることを確認してみましょう。 ## 行多相を利用する -パスを描画する方法は他にもあります。 `arc`関数は円弧を描画します。 -`moveTo`関数、 `lineTo`関数、 `closePath`関数は断片的な線分のパスを描画するのに使えます。 +パスを描画する方法は他にもあります。 +`arc`関数は円弧を描画します。 +`moveTo`関数、`lineTo`関数、`closePath`関数は断片的な線分のパスを描画できます。 `Shapes.purs`ファイルでは長方形と円弧と三角形の、3つの図形を描画しています。 @@ -106,7 +105,7 @@ type Rectangle = } ``` -`x`と `y`プロパティは左上隅の位置を表しており、 `w`と `h`のプロパティはそれぞれ幅と高さを表しています。 +`x`と`y`プロパティは左上隅の位置を表しており、`w`と`h`のプロパティはそれぞれ幅と高さを表しています。 `arc`関数に以下のような型を持つレコードを渡して呼び出すと、円弧を描画できます。 @@ -120,12 +119,12 @@ type Arc = } ``` -ここで、 `x`と `y`プロパティは弧の中心、 `r`は半径、 `start`と `end`は弧の両端の角度を弧度法で表しています。 +ここで、`x`と`y`プロパティは弧の中心、`r`は半径、`start`と`end`は弧の両端の角度を弧度法で表しています。 例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰します。 弧は1回転のうち2/3ラジアン分あります。 単位円が上下逆様になっている点に注意してください。 -これはy軸がcanvasの下向きに伸びるためです。 +これはy軸がキャンバスの下向きに伸びるためです。 ```haskell fillPath ctx $ arc ctx @@ -137,11 +136,11 @@ type Arc = } ``` -`Number`型の `x`と `y`というプロパティが `Rectangle`レコード型と`Arc`レコード型の両方に含まれていますね。 +`Rectangle`レコード型と`Arc`レコード型の両方共、`Number`型の`x`と`y`というプロパティを含んでいますね。 どちらの場合でもこの組は点を表しています。 -これは、何れのレコード型にも適用できる、行多相な関数を書くことができることを意味します。 +つまり、何れのレコード型にも作用する行多相な関数を書けます。 -例えば`Shapes`モジュールでは `x`と `y`のプロパティを変更し図形を並行移動する `translate`関数を定義されています。 +例えば`Shapes`モジュールでは`x`と`y`のプロパティを変更し図形を並行移動する`translate`関数が定義されています。 ```haskell {{#include ../exercises/chapter12/src/Example/Shapes.purs:translate}} @@ -156,7 +155,7 @@ type Arc = `shape { ... }`という式は、`shape`を元にして、括弧の中で指定された値で更新されたフィールドを持つ新たなレコードを作ります。 なお、波括弧の中の式はレコード直値のようなコロンではなく、等号でラベルと式を区切って書きます。 -`Shapes`の例からわかるように、 `translate`関数は `Rectangle`レコードと`Arc`レコード双方に対して使うことができます。 +`Shapes`の例からわかるように、`translate`関数は`Rectangle`レコードと`Arc`レコード双方に対して使えます。 `Shape`の例で描画される3つ目の型は線分の断片からなるパスです。 対応するコードは次のようになります。 @@ -179,15 +178,15 @@ mainモジュールとして`Example.Shapes`を指定して、この例をビル $ spago bundle-app --main Example.Shapes --to dist/Main.js ``` -そしてもう一度 `html/index.html`を開き、結果を確認してください。canvas -に3つの異なる図形が描画されるはずです。 +そしてもう一度`html/index.html`を開き、結果を確認してください。 +キャンバスに3つの異なる図形が描画されるはずです。 ## 演習 - 1. (簡単)これまでの例のそれぞれについて、 `strokePath`関数や`setStrokeStyle`関数を使ってみましょう。 - 1. (簡単)関数の引数の内部のdo記法ブロックにより、`fillPath`関数と`strokePath`関数を使って共通のスタイルを持つ複雑なパスを描画できます。 - 同じ `fillPath`呼び出しで隣り合った2つの矩形を描画するように、`Rectangle`のコード例を変更してみてください。 - 線分と円弧を組み合わせて、扇形を描画してみてください。 + 1. (簡単)これまでの各例について、`strokePath`関数や`setStrokeStyle`関数を使ってみましょう。 + 1. (簡単)関数の引数の内部でdo記法ブロックを使うと、`fillPath`関数と`strokePath`関数は共通のスタイルを持つ複雑なパスを描画できます。 + 同じ`fillPath`呼び出しを使って隣り合う2つの矩形を描画するように、`Rectangle`の例を変更してみてください。 + 線分と円弧の組み合わせを使って、扇形を描画してみてください。 1. (普通)次のような2次元の点を表すレコードが与えられたとします。 ```haskell @@ -210,38 +209,38 @@ $ spago bundle-app --main Example.Shapes --to dist/Main.js f :: Number -> Point ``` - この関数は引数として `1`から `0`の間の `Number`をとり、 `Point`を返します。 - `renderPath`関数を利用して関数 `f`のグラフを描くアクションを書いてください。 - そのアクションでは有限個の点を `f`からサンプリングすることによって近似しなければなりません。 + この関数は引数として`1`から`0`の間の`Number`を取り、`Point`を返します。 + `renderPath`関数を使い、関数`f`のグラフを描く動作を書いてください。 + その動作では有限個の点で`f`を標本化することによって近似しなければなりません。 関数 `f`を変更し、様々なパスが描画されることを確かめてください。 ## 無作為に円を描く -`Example/Random.purs`ファイルには2種類の異なる副作用が混在した`Effect`モナドを使う例が含まれています。 -1つは乱数生成で、もう1つはcanvasの操作です。 +`Example/Random.purs`ファイルには、`Effect`モナドを使って2種類の副作用を綴じ合わせる例が含まれています。 +1つの副作用は乱数生成で、もう1つはキャンバスの操作です。 この例では無作為に生成された円をキャンバスに100個描画します。 -`main`アクションではこれまでのようにグラフィックスコンテキストへの参照を取得し、ストロークと塗り潰しスタイルを設定します。 +`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗り潰しのスタイルを設定します。 ```haskell {{#include ../exercises/chapter12/src/Example/Random.purs:style}} ``` -次のコードでは `for_`アクションを使って `0`から `100`までの整数について反復しています。 +次のコードでは`for_`動作を使って`0`から`100`までの整数について反復しています。 ```haskell {{#include ../exercises/chapter12/src/Example/Random.purs:for}} ``` -それぞれの繰り返しでのdo記法ブロックは、`0`と`1`の間に分布する3つの乱数を生成することから始まります。 -これらの数は `0`から `1`の間に無作為に分布しており、それぞれ `x`座標、 `y`座標、半径 `r`を表しています。 +各繰り返しで、do記法ブロックは`0`と`1`の間に分布する3つの乱数を生成することから始まります。 +これらの数はそれぞれ`x`座標、`y`座標、半径`r`を表しています。 ```haskell {{#include ../exercises/chapter12/src/Example/Random.purs:random}} ``` -次のコードではそれぞれの円について、これらの変数に基づいて `Arc`を作成し、最後に現在のスタイルに従って円弧を塗り潰し線描きします。 +次のコードでは各円について、これらの変数に基づいて`Arc`を作成し、最後に現在のスタイルに従って円弧を塗り潰し線描きします。 ```haskell {{#include ../exercises/chapter12/src/Example/Random.purs:path}} @@ -258,7 +257,7 @@ $ spago bundle-app --main Example.Random --to dist/Main.js ## 座標変換 キャンバスは簡単な図形を描画するだけのものではありません。 -キャンバスは変換行列を扱うことができ、描画の前に形状を変形してから図形を描画できます。 +キャンバスは座標変換を管理しており、描画の前に図形を変形するのに使えます。 図形は平行移動、回転、拡大縮小、及び斜めに変形できます。 `canvas`ライブラリではこれらの変換を以下の関数で提供しています。 @@ -281,19 +280,19 @@ transform :: Context2D -> Effect Context2D ``` -`translate`アクションは`TranslateTransform`レコードのプロパティで指定した大きさだけ平行移動します。 +`translate`動作は`TranslateTransform`レコードのプロパティで指定した大きさだけ平行移動します。 -`rotate`アクションは最初の引数で指定されたラジアンの値に応じて、原点を中心として回転します。 +`rotate`動作は最初の引数で指定されたラジアンの数値に応じて、原点を中心として回転します。 -`scale`アクションは原点を中心として拡大縮小します。 -`ScaleTransform`レコードは `X`軸と `y`軸に沿った拡大率を指定するのに使います。 +`scale`動作は原点を中心として拡大縮小します。 +`ScaleTransform`レコードは`x`軸と`y`軸に沿った拡大率を指定するのに使います。 -最後の `transform`はこの4つのうちで最も一般化されたアクションです。 -このアクションでは行列に従ってアフィン変換します。 +最後の `transform`はこの4つのうちで最も一般化された動作です。 +この動作では行列に従ってアフィン変換します。 -これらのアクションが呼び出された後に描画される図形は、自動的に適切な座標変換が適用されます。 +これらの動作が呼び出された後に描画される図形は、自動的に適切な座標変換が適用されます。 -実際には、これらの関数のそれぞれの作用は、コンテキストの現在の変換行列に対して変換行列を*右から乗算*していきます。 +実際には、これらの関数の各作用は、文脈の現在の変換行列に対して変換行列を*右から乗算*していきます。 つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されていきます。 ```haskell @@ -305,11 +304,11 @@ transformations ctx = do renderScene ``` -この一連のアクションの作用では、まずシーンが回転され、それから拡大縮小され、最後に平行移動されます。 +この一連の動作の作用では、まずシーンが回転され、それから拡大縮小され、最後に平行移動されます。 -## コンテキストの保存 +## 文脈の保存 -変換を適用してシーンの一部を描画し、それからその変換を元に戻す、という使い方はよくあります。 +座標変換を使ってシーンの一部を描画し、それからその変換を元に戻す、という使い方はよくあります。 Canvas APIにはキャンバスの状態の*スタック*を操作する`save`と`restore`メソッドが備わっています。 `canvas`ではこの機能を次のような関数で梱包しています。 @@ -324,11 +323,10 @@ restore -> Effect Context2D ``` -`save`アクションは現在のコンテキストの状態(現在の変換行列や描画スタイル)をスタックにプッシュし、 -`restore`アクションはスタックの一番上の状態をポップし、コンテキストの状態を復元します。 +`save`動作は現在の文脈の状態(現在の変換行列や描画スタイル)をスタックにプッシュし、`restore`動作はスタックの一番上の状態をポップし、文脈の状態を復元します。 -これらのアクションにより、現在の状態を保存し、いろいろなスタイルや変換を適用してから原始的な図形を描画し、最後に元の変換と状態を復元できます。 -例えば、次の関数は回転を適用してから幾つかのキャンバスアクションを実行し、そのあとに変換を復元します。 +これらの動作により、現在の状態を保存し、いろいろなスタイルや変換を適用してから原始的な図形を描画し、最後に元の変換と状態を復元できます。 +例えば次の関数は幾つかのキャンバス動作を実行しますが、その前に回転を適用し、その後に変換を復元します。 ```haskell rotated ctx render = do @@ -338,8 +336,7 @@ rotated ctx render = do restore ctx ``` -こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元のコンテキスト状態を保存しつつ幾つかのキャンバスアクションを実行する -`withContext`関数が提供されています。 +こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元の文脈状態を保存しつつ幾つかのキャンバス動作を実行する`withContext`関数が提供されています。 ```haskell withContext @@ -361,7 +358,7 @@ rotated ctx render = この節では `refs`パッケージを使って `Effect`モナドの別の作用について実演してみます。 -`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及び関連する作用を提供します。 +`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及びそれに紐付く作用を提供します。 ```text > import Effect.Ref @@ -373,15 +370,15 @@ Type -> Type 型`Ref a`の値は型`a`の値を含む可変参照セルであり、大域的な変更を追跡するのに使われます。 そういったわけでこれは少しだけ使う分に留めておくべきです。 -`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに `Ref`作用を使用する例が含まれています。 +`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに `Ref`を使う例が含まれます。 -このコードでは最初に`new`アクションを使って値`0`を含む新しい参照を作成しています。 +このコードでは最初に`new`動作を使って値`0`を含む新しい参照を作成しています。 ```haskell {{#include ../exercises/chapter12/src/Example/Refs.purs:clickCount}} ``` -クリックイベント制御子の内部では、 `modify`アクションを使用してクリック数を更新し、更新された値が返されています。 +クリックイベント制御子の内部では、`modify`動作を使用してクリック数を更新し、更新された値が返されています。 ```haskell {{#include ../exercises/chapter12/src/Example/Refs.purs:count}} @@ -393,13 +390,12 @@ Type -> Type {{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}} ``` -このアクションでは元の変換を保存するために -`withContext`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。 +この動作では元の変換を保存するために`withContext`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。 - 矩形が`(-100, -100)`だけ平行移動し、中心が原点に来ます。 - 矩形が原点を中心に拡大されます。 - 矩形が原点を中心に`10`の倍数分の角度で回転します。 -- 矩形が`(300, 300)`だけ平行移動し、中心がcanvasの中心に来ます。 +- 矩形が`(300, 300)`だけ平行移動し、中心がキャンバスの中心に来ます。 このコード例をビルドしてみましょう。 @@ -413,25 +409,24 @@ $ spago bundle-app --main Example.Refs --to dist/Main.js ## 演習 1. (簡単)パスの線描と塗り潰しを同時に行う高階関数を書いてください。 - その関数を使用して `Random.purs`例を書き直してください。 - 1. (普通)`Random`作用と - `Dom`作用を使用して、マウスがクリックされたときに、キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してください。 - 1. (普通)指定された座標を中心としてシーンを回転させる関数を書いてください。 - *手掛かり*:最初にシーンを原点まで平行移動しましょう。 + その関数を使用して`Random.purs`の例を書き直してください。 + 1. (普通)`Random`作用と`Dom`作用を使用して、マウスがクリックされたときに、キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してください。 + 1. (普通)指定された座標の点を中心として回転させることでシーンを変換する関数を書いてください。 + *手掛かり*:変換を使い、最初にシーンを原点まで平行移動しましょう。 ## L-System この章の最後の例として、 `canvas`パッケージを使用して*L-system*(またの名を*Lindenmayer system*)を描画する関数を記述します。 -L-Systemは*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生成規則*の集合で定義されています。 -各生成規則は、アルファベットの文字をとり、それを置き換える文字の配列を返します。 -この処理は文字の初期配列から始まり、複数回繰り返されます。 +1つのL-Systemは*アルファベット*、つまりアルファベット由来の文字の初期の並びと、*生成規則*の集合で定義されます。 +各生成規則は、アルファベットの文字を取り、それを置き換える文字の並びを返します。 +この処理は文字の初期の並びから始まり、複数回繰り返されます。 -もしアルファベットの各文字がcanvas上で実行される命令と対応付けられていれば、その指示に順番に従うことでL-Systemを描画できます。 +もしアルファベットの各文字がキャンバス上で実行される命令と対応付けられていれば、その指示に順番に従うことでL-Systemを描画できます。 -例えばアルファベットが文字 `L`(左回転)、 `R`(右回転)、 `F`(前進)で構成されているとします。 -また、次のような生成規則を定義します。 +例えばアルファベットが文字`L`(左回転)、`R`(右回転)、`F`(前進)で構成されているとします。 +次のような生成規則を定義できます。 ```text L -> L @@ -447,7 +442,8 @@ FLFRRFLFRRFLFRRFLFRRFLFRRFLFRR FLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLF... ``` -この命令群に対応する線分パスをプロットすると、*コッホ曲線*と呼ばれる曲線に近似されます。 +というように続きます。 +この命令群に対応する線分パスをプロットすると、*コッホ曲線*に近似されます。 反復回数を増やすと、曲線の解像度が増していきます。 それでは型と関数のある言語へとこれを翻訳してみましょう。 @@ -478,10 +474,9 @@ FLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLF... これはまさに上記の仕様をそのまま書き写したものです。 -これで、この形式の仕様を受け取りcanvasに描画する関数 `lsystem`を実装できます。 +これで、この形式の仕様を受け取ってキャンバスに描画する関数`lsystem`を実装できます。 `lsystem`はどのような型を持っているべきでしょうか。 -この関数は初期状態 `initial`や生成規則 -`productions`のような値だけでなく、アルファベットの文字をcanvasに描画する関数を引数に取る必要があります。 +`initial`や`productions`のような値だけでなく、アルファベットの文字をキャンバスに描画できる関数を引数に取る必要があります。 `lsystem`の型の最初の大まかな設計は以下です。 @@ -495,8 +490,8 @@ Sentence 最初の2つの引数の型は、値 `initial`と `productions`に対応しています。 -3番目の引数は、アルファベットの文字を取り、canvas上の幾つかのアクションを実行することによって*解釈*する関数を表します。 -この例では、文字`L`は左回転、文字 `R`で右回転、文字 `F`は前進を意味します。 +3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行することによって*解釈*する関数を表します。 +この例では、文字`L`は左回転、文字`R`で右回転、文字`F`は前進を意味します。 最後の引数は、実行したい生成規則の繰り返し回数を表す数です。 @@ -512,9 +507,9 @@ forall a. Array a ``` 次に気付くこととしては、「左回転」と「右回転」のような命令を実装するためには、幾つかの状態を管理する必要があります。 -具体的に言えば、その時点でパスが向いている方向を状態として持たなければなりません。 -計算を通じて状態を関数に渡すように変更する必要があります。 -ここでも `lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数 `s`を使用してそれを表しています。 +具体的に言えば、その時点でパスが動いている方向を状態として持たなければなりません。 +計算を通じて状態を渡すように関数を変更する必要があります。 +ここでも`lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数`s`を使用してそれを表しています。 型 `s`を追加する必要があるのは3箇所で、次のようになります。 @@ -565,12 +560,12 @@ lsystem :: forall a s {{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_impl}} ``` -`go`関数は第2引数に応じて再帰することで動作します。 -場合分けは2つであり、`n`がゼロであるときと `n`がゼロでないときです。 +`go`関数は第2引数について再帰することで動作します。 +場合分けは2つであり、`n`がゼロであるときと`n`がゼロでないときです。 1つ目の場合は再帰は完了し、解釈関数に応じて現在の文を解釈します。 -型`Array a`の文、型 `s`の状態、型 `s -> a -> Effect s`の関数があります。 -以前定義した `foldM`でやったことみたいです。 +型`Array a`の文、型`s`の状態、型`s -> a -> Effect s`の関数があります。 +以前定義した`foldM`の出番のようです。 この関数は`control`パッケージで手に入ります。 ```haskell @@ -585,11 +580,11 @@ lsystem :: forall a s ``` これだけです。 -`foldM`や `concatMap`のような高階関数を使うと、このようにアイデアを簡潔に表現できるのです。 +`foldM`や`concatMap`のような高階関数を使うと、アイデアを簡潔に表現できるのです。 しかし、話はこれで終わりではありません。 ここで与えた型は、実際はまだ特殊化されすぎています。 -この定義ではcanvasの操作が実装のどこにも使われていないことに注目してください。 +この定義ではキャンバスの操作が実装のどこにも使われていないことに注目してください。 それに、全く`Effecta`モナドの構造を利用していません。 実際には、この関数は*どんな*モナド`m`についても動作します。 @@ -599,14 +594,14 @@ lsystem :: forall a s {{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_anno}} ``` -この型で書かれていることは、この解釈関数はモナド `m`が持つ任意の副作用を完全に自由に持つことができる、ということだと理解できます。 +この型で書かれていることは、この解釈関数はモナド`m`が持つ任意の副作用を完全に自由に持つことができる、ということだと理解できます。 キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれませんし、失敗や複数の戻り値に対応しているかもしれません。 こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めします。 この関数は実装からデータを分離することの威力を示す良い例となっています。 -この手法の利点は、複数の異なる方法でデータを解釈する自由が得られることです。 -`lsystem`は2つの小さな関数へと分解さえできるかもしれません。 -1つ目は `concatMap`の適用の繰り返しを使って文を構築するもので、2つ目は `foldM`を使って文を解釈するものです。 +この手法の利点は、複数の異なる方法でデータを解釈できることです。 +さらに`lsystem`を2つの小さな関数へと分解できます。 +1つ目は`concatMap`の適用の繰り返しを使って文を構築するもの、2つ目は`foldM`を使って文を解釈するものです。 これは読者の演習として残しておきます。 それでは解釈関数を実装して、この章の例を完成させましょう。 @@ -625,17 +620,17 @@ lsystem :: forall a s {{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} ``` -文字 `F`(前進)を解釈するには、パスの新しい位置を計算し、線分を描画し、状態を次のように更新します。 +文字`F`(前進)を解釈するには、次のようにパスの新しい位置を計算し、線分を描画し、状態を更新します。 ```haskell {{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretF}} ``` -なおこの章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`関数は `main`関数内で +なお、この章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`関数は `main`関数内で `let`束縛を使用して定義されています。 -`State`型がコンテキストを持つように変更できるでしょうが、それはこのシステムの状態の変化する部分ではないので不適切でしょう。 +`State`型が文脈を持つように変更できるでしょうが、それはこのシステムの状態の変化する部分ではないので不適切でしょう。 -このL-Systemを描画するには、次のような `strokePath`アクションを使用するだけです。 +このL-Systemを描画するには、次のような`strokePath`動作を使用するだけです。 ```haskell {{#include ../exercises/chapter12/src/Example/LSystem.purs:strokePath}} @@ -658,9 +653,7 @@ $ spago bundle-app --main Example.LSystem --to dist/Main.js 1. (普通)`lsystem`関数を2つの小さな関数に分割してください。 1つ目は`concatMap`の適用の繰り返しを使用して最終的な文を構築するもので、2つ目は `foldM`を使用して結果を解釈するものでなくてはなりません。 - 1. (普通)`setShadowOffsetX`アクション、 - `setShadowOffsetY`アクション、`setShadowBlur`アクション、 - `setShadowColor`アクションを使い、塗りつぶされた図形にドロップシャドウを追加してください。 + 1. (普通)`setShadowOffsetX`、`setShadowOffsetY`、`setShadowBlur`、`setShadowColor`動作を使い、塗りつぶされた図形にドロップシャドウを追加してください。 *手掛かり*:PSCiを使って、これらの関数の型を調べてみましょう。 1. (普通)向きを変えるときの角度の大きさは今のところ一定 (`tau/6`) です。 これに代えて、`Letter`データ型の中に角度を移動させ、生成規則によって変更できるようにしてください。 @@ -671,8 +664,9 @@ $ spago bundle-app --main Example.LSystem --to dist/Main.js data Letter = L Angle | R Angle | F ``` - 生成規則でこの新しい情報を使うと、どんな面白い図形を作ることができるでしょうか。 -1. (難しい)`L`(60度左回転)、 `R`(60度右回転)、`F`(前進)、 `M`(これも前進)という4つの文字からなるアルファベットでL-Systemが与えられたとします。 + この新しい情報を生成規則でどう使うと、面白い図形を作ることができるでしょうか。 +1. (難しい)4つの文字からなるアルファベットでL-Systemが与えられたとします。 + それぞれ`L`(60度左回転)、`R`(60度右回転)、`F`(前進)、`M`(これも前進)です。 このシステムの文の初期状態は、単一の文字 `M`です。 @@ -699,9 +693,9 @@ $ spago bundle-app --main Example.LSystem --to dist/Main.js ## まとめ -この章では、 `canvas`ライブラリを使用することにより、PureScriptからHTML5 Canvas APIを使う方法について学びました。 -また、これまで学んできた手法の多くを利用した実用的な例について見ました。 -マップや畳み込み、レコードと行多相、副作用を扱うための `Effect`モナドなどです。 +この章では、`canvas`ライブラリを使用することにより、PureScriptからHTML5 Canvas APIを使う方法について学びました。 +また、これまで学んできた多くの手法からなる実用的な実演を見ました。 +マップや畳み込み、レコードと行多相、副作用を扱うための`Effect`モナドです。 この章の例では、高階関数の威力を示すとともに、 _実装からのデータの分離_ も実演してみせました。これは例えば、代数データ型を使用してこれらの概念を次のように拡張し、描画関数からシーンの表現を完全に分離できるようになります。 @@ -716,6 +710,6 @@ data Scene | ... ``` -この手法は `drawing`パッケージでも採用されており、描画前にさまざまな方法でデータとしてシーンを操作できる柔軟性をもたらしています。 +この手法は`drawing`パッケージで取られており、描画前に様々な方法でシーンをデータとして操作できる柔軟性を齎しています。 -canvasに描画されるゲームの例については[cookbook](https://github.com/JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の「Behavior」と「Signal」のレシピを見てください。 +キャンバスに描画されるゲームの例については[cookbook](https://github.com/JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の「Behavior」と「Signal」のレシピを見てください。 diff --git a/text-ja/chapter13.md b/text-ja/chapter13.md index 0fb359ed..6483a1bd 100644 --- a/text-ja/chapter13.md +++ b/text-ja/chapter13.md @@ -38,7 +38,7 @@ merge :: Array Int -> Array Int -> Array Int ``` 典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成し、結果が正しい値と等しいことを確認することでテストを実施します。 -しかし、 `merge`関数について知る必要があるものは全て、この性質に要約できます。 +しかし、`merge`関数について知る必要があるものは全て、この性質に要約できます。 - `xs`と`ys`が整列済みなら、`merge xs ys`は両方の配列が一緒に結合されて整列された結果になります。 @@ -52,9 +52,8 @@ main = do eq (merge (sort xs) (sort ys)) (sort $ xs <> ys) ``` -このコードを実行すると、 `quickcheck`は無作為な入力 `xs`と -`ys`を生成してこの関数に渡すことで、主張しようとしている性質を反証しようとします。 -何らかの入力に対して関数が `false`を返した場合、性質は正しくないことが示され、ライブラリはエラーを発生させます。 +このコードを実行すると、`quickcheck`は無作為な入力`xs`と`ys`を生成してこの関数に渡すことで、主張した性質を反証しようとします。 +何らかの入力に対して関数が`false`を返した場合、性質は正しくなく、ライブラリはエラーを発生させます。 幸いなことに、次のように100個の無作為なテスト項目を生成しても、ライブラリはこの性質を反証できません。 ```text @@ -75,11 +74,11 @@ Error: Test 1 failed: Test returned false ``` -見ての通りこのエラーメッセージではあまり役に立ちませんが、少し工夫するだけで改良できます。 +見ての通りこのエラー文言ではあまり役に立ちませんが、少し工夫するだけで改良できます。 -## エラーメッセージの改善 +## エラー文言の改善 -テスト項目が失敗した時に同時にエラーメッセージを提供する上で、`quickcheck`は``演算子を提供しています。 +テスト項目が失敗した時に同時にエラー文言を提供する上で、`quickcheck`は``演算子を提供しています。 次のように性質の定義とエラー文言を``で区切って書くだけです。 ```haskell @@ -91,7 +90,7 @@ quickCheck \xs ys -> eq result expected "Result:\n" <> show result <> "\nnot equal to expected:\n" <> show expected ``` -このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗したときに改良されたエラーメッセージが表示されます。 +このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗したときに改良されたエラー文言が表示されます。 ```text Error: Test 1 (seed 534161891) failed: @@ -109,7 +108,7 @@ not equal to expected: *補足*:この新しい性質は冗長です。 というのもこの状況は既に既存の性質で押さえられているからです。 ここでは読者がQuickCheckを使う練習のための簡単なやり方を示そうとしているだけです。 - 1. (簡単)`merge`の残りの性質に対して、適切なエラーメッセージを追加してください。 + 1. (簡単)`merge`の残りの性質に対して、適切なエラー文言を追加してください。 ## 多相的なコードのテスト @@ -120,7 +119,7 @@ not equal to expected: mergePoly :: forall a. Ord a => Array a -> Array a -> Array a ``` -`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエラーメッセージが表示されます。 +`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエラー文言が表示されます。 ```text No type class instance was found for @@ -131,7 +130,7 @@ The instance head contains unknown type variables. Consider adding a type annotation. ``` -このエラーメッセージは、配列に持たせたい要素の型が何なのかわからないので、コンパイラが無作為なテスト項目を生成できなかったということを示しています。 +このエラー文言は、配列に持たせたい要素の型が何なのかわからないので、コンパイラが無作為なテスト項目を生成できなかったということを示しています。 このような場合、型註釈を使ってコンパイラが特定の型を推論するように強制できます。 例えば`Array Int`などです。 @@ -142,7 +141,7 @@ quickCheck \xs ys -> 代替案として型を指定する補助関数を使うこともできます。 こうするとより見通しのよいコードになることがあります。 -例えば同値関数の同義な関数`ints`を定義したとしましょう。 +例えば同値関数の同義語として関数`ints`を定義したとしましょう。 ```haskell ints :: Array Int -> Array Int @@ -156,18 +155,18 @@ quickCheck \xs ys -> eq (ints $ mergePoly (sort xs) (sort ys)) (sort $ xs <> ys) ``` -ここで、 `ints`関数が不明な型を解消するために使われているため、 `xs`と `ys`はどちらも型 `Array Int`を持っています。 +ここで、`ints`関数が不明な型の曖昧さを解消するために使われているため、`xs`と`ys`は型`Array Int`を持っています。 ## 演習 - 1. (簡単)`xs`と `ys`の型を `Array Boolean`に強制する関数 `bools`を書き、 - `mergePoly`をその型でテストする性質を追加してください。 - 1. (普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエラーメッセージを含めてQuickCheckの性質を書いてください。 + 1. (簡単)`xs`と`ys`の型を`Array + Boolean`に強制する関数`bools`を書き、`mergePoly`をその型でテストする性質を追加してください。 + 1. (普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエラー文言を含めてQuickCheckの性質を書いてください。 その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定しなければいけません。 ## 任意のデータの生成 -`quickcheck`ライブラリを使って性質に対するテスト項目を無作為に生成する方法について説明します。 +それでは`quickcheck`ライブラリが性質に対するテスト項目をどのように無作為に生成できているのかを見ていきます。 無作為に値を生成できるような型は、次のような型クラス `Arbitary`のインスタンスを持っています。 @@ -183,9 +182,8 @@ class Arbitrary t where `Gen`はモナドでもアプリカティブ関手でもあるので、 `Arbitary`型クラスの新しいインスタンスを作成するのに、いつも使っているようなコンビネータを自由に使うことができます。 -例えば、 `quickcheck`ライブラリで提供されている `Int`型用の -`Arbitrary`インスタンスを使い、256個のバイト値上の分布を作ることができます。 -これには`Gen`用に`Functor`インスタンスを使って整数から任意の整数値のバイトまでマップします。 +例えば、`quickcheck`ライブラリで提供されている`Int`型用の`Arbitrary`インスタンスを使い、256個のバイト値上の分布を作れます。 +これには`Gen`用の`Functor`インスタンスを使い、整数からバイトへの関数を任意の整数値に写します。 ```haskell newtype Byte = Byte Int @@ -197,9 +195,9 @@ instance Arbitrary Byte where | otherwise = intToByte (-n) ``` -ここでは、0から255までの間の整数値であるような型 `Byte`を定義しています。 -`Arbitrary`インスタンスは `map`演算子を使って、 `intToByte`関数を `arbitrary`アクションまで持ち上げています。 -`arbitrary`アクション内部の型は `Gen Int`と推論されます。 +ここでは、0から255までの間の整数値であるような型`Byte`を定義しています。 +`Arbitrary`インスタンスは`map`演算子を使って、`intToByte`関数を`arbitrary`動作まで持ち上げています。 +`arbitrary`動作内部の型は`Gen Int`と推論されます。 この考え方を `merge`用のテストに使うこともできます。 @@ -208,9 +206,8 @@ quickCheck \xs ys -> eq (numbers $ mergePoly (sort xs) (sort ys)) (sort $ xs <> ys) ``` -このテストでは、任意の配列 `xs`と `ys`を生成しますが、 `merge`は整列済みの入力を期待しているので、 `xs`と -`ys`を整列しておかなければなりません。 -一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する `Arbitrary`インスタンスを書くこともできます。 +このテストでは、任意の配列`xs`と`ys`を生成しますが、`merge`は整列済みの入力を期待しているので、これらを整列しておかなければなりません。 +一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する`Arbitrary`インスタンスを書くこともできます。 ```haskell newtype Sorted a = Sorted (Array a) @@ -229,9 +226,9 @@ quickCheck \xs ys -> eq (ints $ mergePoly (sorted xs) (sorted ys)) (sort $ sorted xs <> sorted ys) ``` -これは些細な変更に見えるかもしれませんが、 `xs`と `ys`の型はただの `Array Int`から `Sorted Int`へと変更されています。 -これにより、 `mergePoly`関数は整列済みの入力を取る、という*意図*を、わかりやすく示すことができます。 -理想的には、 `mergePoly`関数自体の型が `Sorted`型構築子を使うようにするといいでしょう。 +これは些細な変更に見えるかもしれませんが、`xs`と`ys`の型はただの`Array Int`から`Sorted Int`へと変更されています。 +これにより、`mergePoly`関数は整列済みの入力を取る、という*意図*をわかりやすく示すことができます。 +理想的には、`mergePoly`関数自体の型が`Sorted`型構築子を使うようにするといいでしょう。 より興味深い例として、 `Tree`モジュールでは枝の値で整列された二分木の型が定義されています。 @@ -250,7 +247,7 @@ fromArray :: forall a. Ord a => Array a -> Tree a toArray :: forall a. Tree a -> Array a ``` -`insert`関数は新しい要素を整列済みの二分木に挿入するのに使われ、 `member`関数は特定の値の有無を木に問い合わせるのに使われます。 +`insert`関数は新しい要素を整列済みの木に挿入し、`member`関数は特定の値について木に問い合わせます。 例えば次のようになります。 ```text @@ -263,16 +260,16 @@ true false ``` -`toArray`関数と `fromArray`関数は、整列された木と整列された配列を相互に変換するために使われます。 -`fromArray`を使うと、木についての `Arbitrary`インスタンスを書くことができます。 +`toArray`関数と`fromArray`関数は、整列された木と配列を相互に変換できます。 +`fromArray`を使うと、木についての`Arbitrary`インスタンスを書けます。 ```haskell instance (Arbitrary a, Ord a) => Arbitrary (Tree a) where arbitrary = map fromArray arbitrary ``` -型 `a`についての`Arbitary`インスタンスが使えるなら、テストする性質の引数の型として `Tree a`を使うことができます。例えば、 -`member`テストは値を挿入した後は常に `true`を返すことをテストできます。 +型`a`用に使える`Arbitary`インスタンスがあるなら、テストする性質の引数の型として`Tree a`を使えます。 +例えば、`member`による木の確認については、値を挿入した後は常に`true`を返すことをテストできます。 ```haskell quickCheck \t a -> @@ -287,16 +284,16 @@ quickCheck \t a -> 1. (普通)`a-z`の範囲から無作為に選ばれた文字の集まりを生成する `Arbitrary`インスタンスを持つ、`String`のnewtypeを作ってください。 *手掛かり*:`Test.QuickCheck.Gen`モジュールから `elements`と `arrayOf`関数を使います。 - 1. (難しい)木に挿入された値は、どれだけ挿入があった後でも、その木の構成要素であることを主張する性質を書いてください。 + 1. (難しい)木に挿入された値は、どれだけ沢山の挿入があった後でも、その木の構成要素であることを主張する性質を書いてください。 ## 高階関数のテスト -`Merge`モジュールは `merge`関数の別の一般化も定義しています。 -`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を決定するのに使われます。 -つまり `mergeWith`は高階関数です。 +`Merge`モジュールは`merge`関数の別の一般化も定義しています。 +`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を判定します。 +つまり`mergeWith`は高階関数です。 例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列を統合できます。 -このとき、結果も長さの昇順になっていなければなりません。 +その結果もまた長さの昇順になっているでしょう。 ```haskell > import Data.String @@ -309,34 +306,33 @@ quickCheck \t a -> ``` このような関数をテストするにはどうしたらいいでしょうか。 -理想的には、関数である最初の引数を含めた、3つの引数全てについて、値を生成したいと思うでしょう。 +理想的には、関数である最初の引数を含めた3つの引数全てについて、値を生成したいところです。 -関数を無作為に生成できるようにする、もう1つの型クラスがあります。 -この型クラスは `Coarbitrary`と呼ばれており、次のように定義されています。 +無作為に生成された関数を作れるようにする、2つ目の型クラスがあります。 +`Coarbitrary`という名前で次のように定義されています。 ```haskell class Coarbitrary t where coarbitrary :: forall r. t -> Gen r -> Gen r ``` -`coarbitrary`関数は、型 `t`と、関数の結果の型 `r`についての乱数生成器を関数の引数としてとり、乱数生成器を _かき乱す_ -のにこの引数を使います。つまり関数の引数を使って、乱数生成器の無作為な出力を変更しているのです。 +`coarbitrary`関数は、型`t`の関数の引数と、型`r`の関数の結果の乱数生成器を取ります。 +この関数引数を使って乱数生成器を*かき乱し*ます。 +つまり、関数の引数を使って乱数生成器の無作為な出力を変更し、結果としているのです。 -また、もし関数の定義域が `Coarbitrary`で、値域が -`Arbitrary`なら、`Arbitrary`の関数を与える型クラスインスタンスが存在します。 +また、もし関数の定義域が`Coarbitrary`で値域が`Arbitrary`なら、`Arbitrary`の関数を与える型クラスインスタンスが存在します。 ```haskell instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b) ``` -実は、これが意味しているのは、引数として関数を取るような性質を記述できるということです。 +実際のところ、引数として関数を取るような性質を記述できます。 `mergeWith`関数の場合では、新しい引数を考慮するようにテストを修正すると、最初の引数を無作為に生成できます。 結果が整列されていることは保証できません。 -必ずしも`Ord`インスタンスを持っているとさえ限らないのです。 -しかし、引数として渡す関数 `f`に従って結果が整列されていることは期待されます。 -更に、2つの入力配列が `f`に従って整列されている必要がありますので、`sortBy`関数を使って関数 `f`が適用されたあとの比較に基づいて -`xs`と`ys`を整列します。 +`Ord`インスタンスを持っているとさえ限らないのです。 +しかし、引数として渡す関数`f`に従って結果が整列されていることは期待されます。 +更に、2つの入力配列が`f`に従って整列されている必要がありますので、`sortBy`関数を使って関数`f`が適用されたあとの比較に基づいて`xs`と`ys`を整列します。 ```haskell quickCheck \xs ys f -> @@ -366,8 +362,8 @@ intToBool = id instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b) ``` -これは値の生成が単純な関数だけに限定されるものではないことを意味しています。 -つまり*高階関数*や、引数が高階関数であるような関数もまた、無作為に生成できるのです。 +つまり値や関数だけに制限されません。 +*高階関数*や、引数が高階関数であるような関数やその他諸々もまた、無作為に生成できるのです。 ## Coarbitraryのインスタンスを書く @@ -382,8 +378,8 @@ instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b) instance Coarbitrary a => Coarbitrary (Tree a) where ``` -型 `Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があります。 -入力値が `Leaf`であれば、そのままにしておく生成器を返します。 +型`Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があります。 +入力値が`Leaf`であれば、そのままにしておく生成器を返します。 ```haskell coarbitrary Leaf = id @@ -400,14 +396,15 @@ instance Coarbitrary a => Coarbitrary (Tree a) where ``` これで、木を引数にとるような関数を引数に含む性質を自由に書くことができるようになりました。 -例えば`Tree`モジュールでは`anywhere`が定義されており、これは述語が引数のどんな部分木についても成り立っているかを調べる関数です。 +例えば`Tree`モジュールでは関数`anywhere`が定義されています。 +これは述語が引数のどんな部分木についても満たされるかを調べます。 ```haskell anywhere :: forall a. (Tree a -> Boolean) -> Tree a -> Boolean ``` -これで、この述語関数`anywhere`を無作為に生成できるようになりました。 -例えば、 `anywhere`関数は*ある命題のもとで不変*であることが期待されます。 +今となっては述語関数を無作為に生成できます。 +例えば、`anywhere`関数は*選言の法則を満たす*ことが期待されます。 ```haskell quickCheck \f g t -> @@ -424,9 +421,9 @@ treeOfInt = id ## 副作用のないテスト -通常、テストの目的ではテストスイートの `main`アクションに`quickCheck`関数の呼び出しが含まれています。 -しかし、副作用を使わない`quickCheckPure`と呼ばれる `quickCheck`関数の亜種もあります。 -`quickCheckPure`は、入力として乱数の種をとり、テスト結果の配列を返す純粋な関数です。 +通常、テストの目的ではテストスイートの`main`動作に`quickCheck`関数の呼び出しが含まれています。 +しかし`quickCheck`関数には亜種があり、`quickCheckPure`という名前です。 +副作用を使わない代わりに、入力として乱数の種を取ってテスト結果の配列を返す純粋な関数です。 PSCiを使用して `quickCheckPure`を試せます。 ここでは `merge`操作が結合法則を満たすことをテストします。 @@ -446,7 +443,7 @@ PSCiを使用して `quickCheckPure`を試せます。 Success : Success : ... ``` -`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数をとります。 +`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を取ります。 もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出力されます。 `quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションのフォームデータ例を無作為に生成するというような状況で便利かもしれません。 @@ -462,11 +459,11 @@ Success : Success : ... data OneTwoThree a = One a | Two a a | Three a a a ``` - *手掛かり*:`Test.QuickCheck.Gen`で定義された `oneOf`関数を使って `Arbitrary`インスタンスを定義してください。 - 1. (普通)`all`を使って `quickCheckPure`関数の結果を単純化してください。 + *手掛かり*:`Test.QuickCheck.Gen`で定義された`oneOf`関数を使って`Arbitrary`インスタンスを定義してください。 + 1. (普通)`all`を使って`quickCheckPure`関数の結果を単純化してください。 この新しい関数は型`List Result -> Boolean`を持ち、全てのテストが通れば`true`を、そうでなければ`false`を返します。 2. (普通)`quickCheckPure`の結果を単純にする別の手法として、関数`squashResults :: List Result -> Result`を書いてみてください。 - `Data.Maybe.First`の`First`モノイドと共に`foldMap`関数を使うことで、失敗した場合の最初のエラーを保存することを検討してください。 + `Data.Maybe.First`の`First`モノイドと共に`foldMap`関数を使うことで、失敗した場合の最初のエラーを保持することを検討してください。 ## まとめ @@ -474,7 +471,6 @@ Success : Success : ... これを使うと*生成的テスティング*のパラダイムを使って、宣言的な方法でテストを書くことができました。具体的には以下です。 - `spago test`を使ってQuickCheckのテストを自動化する方法を見ました。 -- 性質を関数として書く方法とエラーメッセージを改良する ``演算子の使い方を説明しました。 -- `Arbitrary`と - `Coarbitrary`型クラスによって、如何にして定型的なテストコードの自動生成を可能にし、またどうすれば高階な性質関数が可能になるかを見てきました。 +- 性質を関数として書く方法とエラー文言を改良する``演算子の使い方を説明しました。 +- `Arbitrary`と`Coarbitrary`型クラスによって定型的なテストコードの自動生成を可能にする方法や、高階な性質のテストを可能にする方法を見ました。 - 独自のデータ型に対して `Arbitrary`と `Coarbitrary`インスタンスを実装する方法を見ました。 diff --git a/text-ja/chapter14.md b/text-ja/chapter14.md index 96dff977..d8f13a6c 100644 --- a/text-ja/chapter14.md +++ b/text-ja/chapter14.md @@ -5,23 +5,23 @@ この章では多数の標準的な手法を使い、PureScriptにおける*領域特化言語*(または*DSL*)の実装について探求していきます。 領域特化言語とは、特定の問題領域での開発に適した言語のことです。 -領域特化言語の構文及び機能は、その領域内の考え方を表現するコードの読みやすさを最大限に発揮すべく選択されます。 +構文及び機能は、その領域内の考え方を表現するに使われるコードの読みやすさを最大化すべく選択されます。 本書の中では、既に領域特化言語の例を幾つか見てきています。 -- 第11章で開発された `Game`モナドと関連するアクションは、 _テキストアドベンチャーゲーム開発_ - という領域に対しての領域特化言語を構成しています。 -- 第13章で扱った `quickcheck`パッケージは、 _生成的テスティング_ - の領域の領域特化言語です。このコンビネータはテストの性質に対して特に表現力の高い記法を可能にします。 +- 第11章で開発された`Game`モナドと関連する動作は、*テキストアドベンチャーゲーム開発*という領域に対しての領域特化言語を構成しています。 +- 第13章で扱った`quickcheck`パッケージは、*生成的テスティング*の領域に向けた領域特化言語です。 + このコンビネータはテストの性質に対して特に表現力の高い記法を可能にします。 -この章では、領域特化言語の実装において、幾つかの標準的な技法による構造的な手法に迫ります。 -これがこの話題の完全な説明だということでは決してありませんが、自分の目的に合う具体的なDSLを構築するのには充分な知識をもたらすことでしょう。 +この章では、領域特化言語の実装において、幾つかの標準的な技法にについて構造的な手法を取ります。 +この話題の完全な解説では決してありませんが、目的に合う実践的なDSLを構築するのに充分な知識は得られるでしょう。 -この章で実行している例は、HTML文書を作成するための領域特化言語です。 +ここでの実行例はHTML文書を作成するための領域特化言語です。 正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装を徐々に改善しつつ進めていきます。 ## プロジェクトの準備 -この章で使うプロジェクトには新しい依存性が1つ追加されます。これから使う道具の1つである*Freeモナド*が定義されている `free`ライブラリです。 +この章に付随するプロジェクトには新しい依存性が1つ追加されます。 +これから使う道具の1つである*Freeモナド*が定義されている`free`ライブラリです。 このプロジェクトをPSCiを使って試していきます。 @@ -47,9 +47,9 @@ newtype Attribute = Attribute } ``` -`Element`型はHTMLの要素を表しています。 -各要素は要素名、属性の対の配列と、要素の内容で構成されています。 -contentプロパティは、`Maybe`タイプを適切に使って、要素が開いている(他の要素やテキストを含む)か閉じているかを示しています。 +`Element`型はHTMLの要素を表します。 +各要素は要素名、属性の対の配列と、内容で構成されます。 +内容のプロパティには`Maybe`型を適切に使い、要素が開いている(他の要素やテキストを含む)か閉じているかを示します。 このライブラリの鍵となる機能は次の関数です。 @@ -89,7 +89,7 @@ unit 現状のライブラリには幾つもの問題があります。 -- HTML文書の作成に手がかかります。 +- HTML文書の作成に手が掛かります。 全ての新しい要素に少なくとも1つのレコードと1つのデータ構築子が必要です。 - 無効な文書を表現できてしまいます。 - 開発者が要素名の入力を間違えるかもしれません @@ -100,9 +100,9 @@ unit ## スマート構築子 -最初に導入する手法は方法こそ単純なものですが、とても効果的です。 -モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリストを使ってデータ構築子 `Element`、 `Content`、 -`Attribute`を隠蔽し、正しいことが明らかなデータだけ構築する、いわゆる*スマート構築子*だけをエクスポートします。 +最初に導入する手法は単純ですがとても効果的です。 +モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリストを使ってデータ構築子`Element`、`Content`、`Attribute`を隠蔽します。 +そして正しいことが分かっているデータを構築する、いわゆる*スマート構築子*だけをエクスポートします。 例を示しましょう。まず、HTML要素を作成するための便利な関数を提供します。 @@ -115,8 +115,8 @@ element name attribs content = Element } ``` -次に、欲しいHTML要素を利用者が作れるように、スマート構築子を作成します。 -これには`element`関数を適用します。 +次にHTML要素のためのスマート構築子を作成します。 +この要素は利用者が`element`関数を適用して作成できるようになってほしいものです。 ```haskell a :: Array Attribute -> Array Content -> Element @@ -150,21 +150,22 @@ module Data.DOM.Smart - 値(ないし関数)。その値の名前により指定されます。 - 型クラス。クラス名により指定されます。 -- 型構築子と関連するデータ構築子。型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定されます。 +- 型構築子とそれに紐付くデータ構築子。 + 型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定されます。 -ここでは、 `Element`の*型*をエクスポートしていますが、データ構築子はエクスポートしていません。 -もしデータ構築子をエクスポートすると、モジュールの使用者が不正なHTML要素を構築できてしまいます。 +ここでは、`Element`の*型*をエクスポートしていますが、データ構築子はエクスポートしていません。 +もしデータ構築子をエクスポートすると、使用者が不正なHTML要素を構築できてしまいます。 `Attribute`と `Content`型についてはデータ構築子を全てエクスポートしています(エクスポートリストの記号 `..`で示されています)。 すぐ後で、これらの型にもスマート構築子の手法を適用していきます。 既にライブラリに幾つもの大きな改良が加わっていることに注目です。 -- 不正な名前を持つHTML要素は表現できません(もちろん、ライブラリが提供する要素名に制限されています)。 +- 不正な名前を持つHTML要素は表現できません(勿論ライブラリが提供する要素名に制限されています)。 - 閉じた要素は構築するときに内容を含められません。 `Content`型にとても簡単にこの手法を適用できます。 -単にエクスポートリストから `Content`型のデータ構築子を取り除き、次のスマート構築子を提供します。 +単にエクスポートリストから`Content`型のデータ構築子を取り除き、次のスマート構築子を提供します。 ```haskell text :: String -> Content @@ -188,8 +189,8 @@ attribute key value = Attribute infix 4 attribute as := ``` -この定義では元の `Element`型と同じ問題に直面しています。 -存在しなかったり、名前が間違っているような属性を表現できます。 +この定義では元の`Element`型と同じ問題に直面しています。 +存在しなかったり、名前が間違って入力された属性を表現できます。 この問題を解決するために、属性名を表すnewtypeを作成します。 ```haskell @@ -269,15 +270,14 @@ $ spago repl unit ``` -しかし、基盤をなすデータ表現は変更されなかったので、 `render`関数を変更する必要はなかったことにも注目してください。 +しかし、基盤をなすデータ表現は全く変更されなかったので、`render`関数を変更する必要はなかったことにも注目してください。 これはスマート構築子による手法の利点のひとつです。 -外部APIの使用者によって認識される表現からモジュールの内部データ表現を分離できるのです。 +外部APIの使用者によって認識される表現から、モジュールの内部データ表現を分離できるのです。 ## 演習 1. (簡単)`Data.DOM.Smart`モジュールで `render`を使った新しいHTML文書の作成を試してみましょう。 - 1. (普通)`checked`と `disabled`など、値を要求しないHTML属性がありますが、これらは次のような _空の属性_ - として表示されるかもしれません。 + 1. (普通)`checked`や`disabled`といったHTML属性は値を要求せず、*空の属性*として書き出せます。 ```html @@ -388,11 +388,10 @@ unit ## 演習 - 1. (簡単)ピクセルまたはパーセントの長さの何れかを表すデータ型を作成してください。 - その型について `IsValue`のインスタンスを書いてください。 - この型を使うように `width`と `height`属性を変更してください。 - 1. (難しい)幻影型を使って真偽値 `true`、 `false`用の最上位の表現を定義することで、 `AttributeKey`が - `disabled`や `checked`のような*空の属性*を表現しているかどうかをエンコードできます。 + 1. (簡単)ピクセルまたはパーセントの何れかの長さを表すデータ型を作成してください。 + その型について`IsValue`のインスタンスを書いてください。 + この新しい型を使うように`width`と`height`属性を変更してください。 + 1. (難しい)真偽値`true`、`false`用の最上位の表現を定義することで、幻影型を使って`AttributeKey`が`disabled`や`checked`のような*空の属性*を表現しているかどうかをエンコードできます。 ```haskell data True @@ -403,8 +402,9 @@ unit ## Freeモナド -APIに施す最後の変更は、 `Content`型をモナドにしてdo記法を使えるようにするために、 _Freeモナド_ -と呼ばれる構造を使うことです。これによって入れ子になった要素がわかりやすくなるようにHTML文書を構造化できます。以下の代わりに…… +APIに施す最後の変更では、`Content`型をモナドにしてdo記法を使えるようにするために、*Freeモナド*と呼ばれる構造を使っていきます。 +これによって入れ子になった要素がわかりやすくなるような形式でHTML文書を構造化できます。 +以下の代わりに…… ```haskell p [ _class := "main" ] @@ -429,10 +429,10 @@ p [ _class := "main" ] $ do text "A cat" ``` -しかし、do記法だけがFreeモナドの恩恵だというわけではありません。Freeモナドがあれば、モナドのアクションの _表現_ をその _解釈_ -から分離し、同じアクションに _複数の解釈_ を持たせることさえできます。 +しかし、do記法だけがFreeモナドの恩恵ではありません。 +Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複数の解釈*を持たせることさえできます。 -`Free`モナドは `free`ライブラリの `Control.Monad.Free`モジュールで定義されています。 +`Free`モナドは`free`ライブラリの`Control.Monad.Free`モジュールで定義されています。 PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができます。 ```text @@ -443,12 +443,12 @@ PSCiを使うと、次のようにFreeモナドについての基本的な情報 ``` `Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示しています。 -実は、`Free`モナドを使えば任意の`Functor`を`Monad`にできます。 +実はなんと、`Free`モナドを使えば任意の`Functor`を`Monad`にできるのです。 -モナドのアクションの*表現*の定義から始めます。 -こうするには、対応する各モナドアクションそれぞれについて、1つのデータ構築子を持つ `Functor`を作成する必要があります。 -今回の場合、2つのモナドのアクションは `elem`と `text`になります。 -実際には、 `Content`型を次のように変更するだけです。 +モナドの動作の*表現*の定義から始めます。 +これには対応したい各モナド動作について、1つのデータ構築子を持つ`Functor`を作成する必要があります。 +今回の場合、2つのモナドの動作は`elem`と`text`になります。 +`Content`型を次のように変更するだけでできます。 ```haskell data ContentF a @@ -460,9 +460,9 @@ instance Functor ContentF where map f (ElementContent e x) = ElementContent e (f x) ``` -ここで、この `ContentF`型構築子は以前の `Content`データ型とよく似ています。 +ここで、この`ContentF`型構築子は以前の`Content`データ型とよく似ています。 しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引数として取るように変更されています。 -`Functor`インスタンスでは、単に各データ構築子で型 `a`の構成要素に関数 `f`を適用します。 +`Functor`インスタンスでは、単に各データ構築子で型`a`の値に関数`f`を適用します。 これにより、新しい`Content`モナドを`Free`モナド用の型シノニムとして定義できます。 これは最初の型引数として `ContentF`型構築子を使うことで構築されます。 @@ -471,8 +471,8 @@ instance Functor ContentF where type Content = Free ContentF ``` -型シノニムの代わりにnewtypeを使用して、使用者に対してライブラリの内部表現を露出することを避けられます。 -`Content`データ構築子を隠すことで、提供しているモナドのアクションだけを使うことを使用者に制限しています。 +型同義語の代わりに`newtype`を使用して、使用者に対してライブラリの内部表現を露出することを避けられます。 +`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使用者に制限しています。 `ContentF`は `Functor`なので、 `Free ContentF`用の`Monad`インスタンスが自動的に手に入ります。 @@ -487,16 +487,16 @@ newtype Element = Element } ``` -また、 `Content`モナドについての新しいモナドのアクションになる `elem`と `text`関数を変更する必要があります。 +また、`Content`モナドについての新しいモナドの動作になるよう、`elem`と`text`関数を変更する必要があります。 これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えます。 -この関数の型は次のようになっています。 +以下がその型です。 ```haskell liftF :: forall f a. f a -> Free f a ``` -`liftF`により、何らかの型 `a`について、型 `f a`の値からFreeモナドのアクションを構築できるようになります。 -今回の場合、 `ContentF`型構築子のデータ構築子をそのまま使うだけです。 +`liftF`により、何らかの型`a`について、型`f a`の値からFreeモナドの動作を構築できるようになります。 +今回の場合、`ContentF`型構築子のデータ構築子をそのまま使えます。 ```haskell text :: String -> Content Unit @@ -529,18 +529,17 @@ runFreeM -> m a ``` -`runFree`関数は、 _純粋な_ 結果を計算するために使用されます。 -`runFreeM`関数があればFreeモナドのアクションを解釈するためにモナドが使えます。 +`runFree`関数は、*純粋な*結果を計算するために使用されます。 +`runFreeM`関数があればFreeモナドの動作を解釈するためにモナドが使えます。 -*補足*:厳密には、より強い`MonadRec`制約を満たすモナド `m`を使用するよう制限されています。 -実際には、これはスタックオーバーフローを心配する必要がないことを意味します。 -なぜなら `m`は安全な*末尾再帰モナド*に対応しているからです。 +*補足*:厳密には、より強い`MonadRec`制約を満たすモナド`m`に制限されています。 +実際、ら`m`は安全な*末尾再帰モナド*に対応してため、スタックオーバーフローを心配する必要はありません。 -まず、アクションを解釈できるモナドを選ばなければなりません。 -`Writer String`モナドを使って、結果のHTML文字列を累積することにします。 +まず、動作を解釈できるモナドを選ばなければなりません。 +`Writer String`モナドを使って、結果のHTML文字列を累算することにします。 新しい`render`メソッドが開始すると、補助関数 -`renderElement`に移譲し、`execWriter`を使って`Writer`モナドで計算を走らせます。 +`renderElement`に移譲し、`execWriter`を使って`Writer`モナドで計算します。 ```haskell render :: Element -> String @@ -555,7 +554,7 @@ render = execWriter <<< renderElement renderElement (Element e) = do ``` -`renderElement`の定義は直感的で、複数の小さな文字列を累積するために `Writer`モナドの `tell`アクションを使っています。 +`renderElement`の定義は直感的で、複数の小さな文字列を累算するために`Writer`モナドの`tell`動作を使っています。 ```haskell tell "<" @@ -602,7 +601,7 @@ render = execWriter <<< renderElement renderContentItem :: ContentF (Content Unit) -> Writer String (Content Unit) ``` -`ContentF`の2つのデータ構築子でパターン照合するだけでこの関数を実装できます。 +`ContentF`の2つのデータ構築子でパターン照合すればこの関数を実装できます。 ```haskell renderContentItem (TextContent s rest) = do @@ -613,8 +612,8 @@ render = execWriter <<< renderElement pure rest ``` -それぞれの場合において、式 `rest`は型 `Content Unit`を持っており、解釈計算の残りを表しています。 -`rest`アクションを呼び出すことによってそれぞれの場合を完了できます。 +それぞれの場合において、式`rest`は型`Content Unit`を持っており、解釈された計算の残りを表しています。 +`rest`動作を返すことでそれぞれの場合を完成できます。 できました。 PSCiで、次のようにすれば新しいモナドのAPIを試すことができます。 @@ -636,28 +635,26 @@ unit ## 演習 - 1. (普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメントを出力する新しいアクション - `comment`に対応してください。 - `liftF`を使ってこの新しいアクションを実装してください。 - 新しい構築子を適切に解釈するように、解釈 `renderContentItem`を更新してください。 + 1. (普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメントを出力する新しい動作`comment`に対応してください。 + `liftF`を使ってこの新しい動作を実装してください。 + 新しい構築子を適切に解釈するように、解釈`renderContentItem`を更新してください。 ## 言語の拡張 -全てのアクションが型 `Unit`の何かを返すようなモナドは、さほど興味深いものではありません。 -実際のところ、概ね良くなったと思われる構文は別として、このモナドは `Monoid`以上の機能を何ら追加していません。 +全動作が型`Unit`の何かを返すようなモナドは、さほど興味深いものではありません。 +実際のところ、概ね良くなったと思われる構文は別として、このモナドは`Monoid`以上の機能を何ら追加していません。 -非自明な結果を返す新しいモナドアクションでこの言語を拡張することで、Freeモナド構造の威力をお見せしましょう。 +非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナドを構築する威力をお見せしましょう。 -*アンカー*を使用して文書のさまざまな節へのハイパーリンクが含まれているHTML文書を生成するとします。 -これは既に達成できています。 -手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めればよいのです。 -1つはアンカーの定義自身に、もう1つはそれぞれのハイパーリンクにあります。 -しかし、この方法には根本的な問題が幾つかあります。 +*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を生成したいとします。 +手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めれば、これは達成できます。 +1つはアンカーの定義自身に、もう1つは各ハイパーリンクにあります。 +しかし、この手法には基本的な問題が幾つかあります。 - 開発者が一意なアンカー名の生成をし損なうかもしれません。 - 開発者がアンカー名を1つ以上の箇所で打ち間違うかもしれません。 -開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい一意な名前を生成するためのモナドアクションを提供できます。 +開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい一意な名前を生成するためのモナド動作を提供できます。 最初の工程は名前の型を新しく追加することです。 @@ -671,7 +668,7 @@ runName (Name n) = n 繰り返しになりますが、`Name`は `String`のnewtypeとして定義しているものの、モジュールのエクスポートリスト内でデータ構築子をエクスポートしないように注意する必要があります。 -次に、属性値として `Name`を使うことができるように、新しい型に`IsValue`型クラスのインスタンスを定義します。 +次に、属性値に`Name`を使えるよう、新しい型に`IsValue`型クラスのインスタンスを定義します。 ```haskell instance IsValue Name where @@ -711,7 +708,9 @@ data ContentF a | NewName (Name -> a) ``` -`NewName`データ構築子は型 `Name`の値を返すアクションに対応しています。データ構築子の引数として `Name`を要求するのではなく、型 `Name -> a`の _関数_ を提供するように使用者に要求していることに注意してください。型 `a`は _計算の残り_ を表していることを思い出すと、この関数は、型 `Name`の値が返されたあとで、計算を継続する方法を提供しているのだとわかります。 +`NewName`データ構築子は型`Name`の値を返す動作に対応しています。 +データ構築子の引数として`Name`を要求するのではなく、型`Name -> a`の*関数*を提供するように使用者に要求していることに注意してください。 +型`a`は*計算の残り*を表していることを思い出すと、この関数は、型`Name`の値が返されたあとで、計算を継続する方法を提供しているのだとわかります。 新しいデータ構築子を考慮するよう、次のように`ContentF`用の`Functor`インスタンスを更新する必要もあります。 @@ -722,7 +721,7 @@ instance Functor ContentF where map f (NewName k) = NewName (f <<< k) ``` -これで、以前と同じように`liftF`関数を使って新しいアクションを構築できます。 +これで、以前と同じように`liftF`関数を使って新しい動作を構築できます。 ```haskell newName :: Content Name @@ -730,13 +729,13 @@ newName = liftF $ NewName id ``` `id`関数を継続として提供していることに注意してください。 -これは型 `Name`の結果を変更せずに返すということを意味しています。 +つまり型`Name`の結果を変更せずに返しています。 -最後に、新しいアクションを解釈するために解釈関数を更新する必要があります。 -以前は計算を解釈するために `Writer -String`モナドを使っていましたが、このモナドは新しい名前を生成する能力を持っていないので、何か他のものに切り替えなければなりません。 -`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせることができます。 -型注釈を短く保てるように、この解釈モナドを型同義語として定義しておきます。 +最後に、新しい動作を解釈させるように解釈関数を更新する必要があります。 +以前は計算を解釈するために`Writer +String`モナドを使っていましたが、このモナドは新しい名前を生成できないので、何か他のものに切り替えなければなりません。 +`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせられます。 +型注釈が短く保たれるよう、この解釈モナドを型同義語として定義できます。 ```haskell type Interp = WriterT String (State Int) @@ -744,10 +743,10 @@ type Interp = WriterT String (State Int) ここで、`Int`型の状態は増加していくカウンタとして振舞い、一意な名前を生成するのに使われます。 -`Writer`と `WriterT`モナドはそれらのアクションを抽象化するのに同じ型クラスメンバを使うので、どのアクションも変更する必要がありません。 -必要なのは、 `Writer String`への参照全てを `Interp`で置き換えることだけです。 -しかし、これを計算するために使われる制御子を変更しなければいけません。 -こうなると単なる`execWriter`の代わりに、ここでも`evalState`を使う必要があります。 +`Writer`と`WriterT`モナドはそれらの動作を抽象化するのに同じ型クラスの構成要素を使うので、どの動作も変更する必要がありません。 +必要なのは、`Writer String`への参照全てを`Interp`で置き換えることだけです。 +しかし、計算に使われる制御子は変更する必要があります。 +単なる`execWriter`の代わりに、`evalState`も使う必要があります。 ```haskell render :: Element -> String @@ -769,7 +768,7 @@ renderContentItem (NewName k) = do `get`を使って状態を読み、その状態を使って一意な名前を生成し、それから `put`で状態に1だけ足すのです。 最後に、継続にこの新しい名前を渡して、計算を完了します。 -以上をもって、この新しい機能をPSCiで試すことができます。 +以上をもって、この新しい機能をPSCiで試せます。 これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンクのリンク先の両方として使います。 ```text @@ -790,38 +789,40 @@ renderContentItem (NewName k) = do unit ``` -複数回の `newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめられます。 +複数回の`newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめられます。 ## 演習 1. (普通)使用者から `Element`型を隠蔽すると、更にAPIを簡素にできます。 次の手順に従って、これらの変更を加えてください。 - - `p`や `img`のような(返る型が `Element`の)関数を `elem`アクションと結合して、型 `Content - Unit`を返す新しいアクションを作ってください。 + - `p`や`img`のような(返る型が`Element`の)関数を`elem`動作と結合して、型`Content + Unit`を返す新しい動作を作ってください。 - `Element`の代わりに型`Content Unit`の引数を受け付けるように`render`関数を変更してください。 - 1. (普通)型同義語の代わりに`newtype`を使うことによって`Content`モナドの実装を隠してください。 + 1. (普通)型同義語の代わりに`newtype`を使って`Content`モナドの実装を隠してください。 `newtype`用のデータ構築子はエクスポートすべきではありません。 - 1. (難しい)`ContentF`型を変更して以下の新しいアクションに対応してください。 + 1. (難しい)`ContentF`型を変更して以下の新しい動作に対応してください。 ```haskell isMobile :: Content Boolean ``` - このアクションは、この文書がモバイルデバイス上での表示のためにレンダリングされているかどうかを示す真偽値を返します。 + この動作は、この文書がモバイルデバイス上での表示のために描画されているかどうかを示す真偽値を返します。 - *手掛かり*:`ask`アクションと`ReaderT`モナド変換子を使って、このアクションを解釈してください。 + *手掛かり*:`ask`動作と`ReaderT`モナド変換子を使って、この動作を解釈してください。 あるいは、`RWS`モナドを使うほうが好みの人もいるかもしれません。 ## まとめ この章では、幾つかの標準的な技術を使って、素朴な実装を段階的に改善することにより、HTML文書を作成するための領域特化言語を開発しました。 -- _スマート構築子_ を使ってデータ表現の詳細を隠し、利用者には _構築により正しい_ 文書だけを作ることを許しました。 +- *スマート構築子*を使ってデータ表現の詳細を隠し、利用者には*構築により正しい*文書だけを作ることを許しました。 - *独自に定義された中置2引数演算子*を使い、言語の構文を改善しました。 -- _幻影型_ を使ってデータの型の中に追加の情報を折り込みました。これにより利用者が誤った型の属性値を与えることを防いでいます。 -- _Freeモナド_ - を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。それからこの表現を新しいモナドアクションに対応するよう拡張し、標準モナド変換子を使ってモナドの計算を解釈しました。 +- *幻影型*を使ってデータの型の中に追加の情報を折り込みました。 + これにより利用者が誤った型の属性値を与えることを防いでいます。 +- *Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。 + それからこの表現を新しいモナド動作に対応するよう拡張し、標準的なモナド変換子を使ってモナドの計算を解釈しました。 これらの手法は全て、使用者が間違いを犯すのを防いだり領域特化言語の構文を改良したりするために、PureScriptのモジュールと型システムを活用しています。 -関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野ですが、幾つかの簡単な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言語で作業することの威力を示すことができていれば幸いです。 +関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野です。 +それでも、幾つかの単純な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言語で作業することの威力を示すことができていれば幸いです。 diff --git a/text-ja/chapter2.md b/text-ja/chapter2.md index 2166389b..7175c813 100644 --- a/text-ja/chapter2.md +++ b/text-ja/chapter2.md @@ -2,8 +2,8 @@ ## この章の目標 -この章では実際のPureScriptの開発環境を立ち上げ、幾つかの演習を解き、この本で提供されているテストを使って答えを確認します。 -もし映像を見る学習の仕方が合っているようでしたら、[この章を通しで進めるビデオ](https://www.youtube.com/watch?v=GPjPwb6d-70)が役に立つでしょう。 +本章では実際のPureScriptの開発環境を立ち上げ、幾つかの演習を解き、本書で提供されているテストを使って答えを確認します。 +もし映像を見る学習の仕方が合っているようでしたら、[本章を通しで進めるビデオ](https://www.youtube.com/watch?v=GPjPwb6d-70)が役に立つでしょう。 ## 環境構築 @@ -22,13 +22,16 @@ PureScriptを書く上で(例えば本書の演習を解くなど)お好み ## 演習を解く -ここまでで必要な開発ツールをインストールできているので、この本のリポジトリをクローンしてください。 +ここまでで必要な開発ツールをインストールできているので、本書のリポジトリをクローンしてください。 ```sh git clone https://github.com/purescript-contrib/purescript-book.git ``` -本のリポジトリにはPureScriptのコード例とそれぞれの章に付属する演習のための単体テストが含まれます。演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準備ができます。この工程は`resetSolutions.sh`スクリプトを使えば簡単にできます。また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくのもよいでしょう(これらのアンカーはコードスニペットを本の変換後のMarkdownにコピーするために使われており、自分のローカルリポジトリではこのアンカーで散らかっていないほうがよいでしょう)。 +本書のリポジトリにはPureScriptのコード例と各章に付属する演習のための単体テストが含まれます。 +演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準備ができます。 +この工程は`resetSolutions.sh`スクリプトを使えば簡単にできます。 +また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくと良いでしょう(これらのアンカーはコード片を本書のMarkdownから書き出した媒体に複製するために使われており、自分のローカルリポジトリではこのアンカーで散らかっていないほうが良いでしょう)。 ```sh cd purescript-book @@ -55,15 +58,15 @@ spago test All 2 tests passed! 🎉 ``` -なお、`answer`関数(`src/Euler.purs`にあります)は、任意の整数以下の3と5の倍数を見付けるように変更されています。 -この`answer`関数のためのテストスート(`test/Main.purs`にあります)ははじめの手引きの冒頭にあるテストよりも網羅的です。 -はじめの章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い詰めなくて大丈夫です。 +なお、(`src/Euler.purs`にある)`answer`関数は任意の整数以下の3と5の倍数を見付けるように変更されています。 +(`test/Main.purs`にある)この`answer`関数のためのテストスートははじめの手引きの冒頭にあるテストよりも網羅的です。 +前の方の章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い詰めなくて大丈夫です。 -本の残りの部分には多くの演習が含まれます。 +本書の残りの部分には多くの演習が含まれます。 `Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、提供されているテストスートを使って確認できます。 -テスト駆動開発のスタイルでこの次の演習を一緒に進めてみましょう。 +テスト駆動開発でこの次の演習を一緒に進めてみましょう。 ## 演習 @@ -93,7 +96,8 @@ at test/Main.purs:21:27 - 21:35 (line 21, column 27 - line 21, column 35) Unknown value diagonal ``` -まずは、この関数が欠陥のあるバージョンになっているときに何が起こるのか見てみましょう。以下のコードを`test/MySolutions.purs`に追加してください。 +まずはこの関数に欠陥があるときに何が起こるのか見てみましょう。 +以下のコードを`test/MySolutions.purs`に追加してください。 ```hs import Data.Number (sqrt) @@ -147,14 +151,14 @@ All 4 tests passed! 🎉 この章ではPureScriptコンパイラとSpagoツールをインストールしました。 演習の解答の書き方と正しさの確認方法も学びました。 -この先の章にはもっと沢山の演習があり、それらに取り組むうちに学習の助けになっているでしょう。 -演習のどこかでお手上げになったら、この本の[困ったときは](chapter1.ja.md#getting-help)の節に挙げられているコミュニティの資料のどれかを見てみたり、この[本のリポジトリ](https://github.com/purescript-contrib/purescript-book/issues)にイシューを報告したりできます。 -こうした演習の敷居を下げることに繋がる読者のフィードバックが、本の向上の助けになっています。 +この先の章にはもっと沢山の演習があり、それらに取り組むうちに内容を学ぶ助けになっているでしょう。 +演習のどこかでお手上げになったら、本書の[困ったときは](chapter1.ja.md#getting-help)の節に挙げられているコミュニティの資料のどれかに手を伸ばしたり、[本書のリポジトリ](https://github.com/purescript-contrib/purescript-book/issues)でイシューを報告したりできます。 +こうした演習の敷居を下げることに繋がる読者のフィードバックのお陰で本書が改善されています。 章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べられます。 -ただしカンニングしてはだめで、これらの演習を誠実に自力で解く労力を払わないことがないようにしてください。 +カンニングはせず、演習を誠実に自力で解く労力を割いてください。 そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるようにしてください。 -演習のネタバレをするよりも、小さな手掛かりをあげたいからです。 -もっとエレガントな解法(とはいえ本の内容で押さえられている知識のみを必要とするもの)を見つけたときはPRを送ってください。 +ネタバレをするよりも小さな手掛かりをあげたいからです。 +もっとエレガントな解法(とはいえ本書で押さえられている知識のみで済むもの)を見つけたときはPRを送ってください。 リポジトリは継続して改訂されているため、それぞれの新しい章を始める前に更新を確認するようにしてください。 diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md index 3e9e8037..b4b8516f 100644 --- a/text-ja/chapter3.md +++ b/text-ja/chapter3.md @@ -21,15 +21,19 @@ ここでは、幾つかのモジュールをインポートします。 +- `Prelude`モジュールには標準的な定義と関数の小さな集合が含まれます。 + `purescript-prelude`ライブラリから多くの基礎的なモジュールを再エクスポートしているのです。 - `Control.Plus`モジュールには`empty`値が定義されています。 -- `Data.List`モジュールは`lists`パッケージで提供されておりSpagoを使ってインストールできます。 - 連結リストを使うために必要な幾つかの関数が含まれています。 -- `Data.Maybe`モジュールは、オプショナルな値を扱うためのデータ型と関数を定義しています。 +- `Data.List`モジュールは`lists`パッケージで提供されています。 + またこのパッケージはSpagoを使ってインストールできます。 + モジュールには連結リストを使うために必要な幾つかの関数が含まれています。 +- `Data.Maybe`モジュールは、省略可能な値を扱うためのデータ型と関数を定義しています。 訳者注:ダブルドット (`..`) を使用すると、 指定された型コンストラクタのすべてのデータコンストラクタをインポートできます。 -このモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください。明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。 +これらのモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください(`Prelude`は除きます。これは一括インポートされるのが普通です)。 +明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。 ソースコードリポジトリをクローンしたと仮定すると、この章のプロジェクトは次のコマンドでSpagoを使用して構築できます。 @@ -40,10 +44,9 @@ $ spago build ## 単純な型 -JavaScriptのプリミティブ型に対応する組み込みデータ型として、PureScriptでは数値型と文字列型、真偽型の3つが定義されています。 +JavaScriptの原始型に対応する組み込みデータ型として、PureScriptでは数値型と文字列型、真偽型の3つが定義されています。 これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポートされます。 -これらはそれぞれ `Number`、 `String`、 -`Boolean`と呼ばれており、PSCiで`:type`コマンドを使うと簡単な値の型を表示させて確認できます。 +それぞれ`Number`、`String`、`Boolean`と呼ばれており、PSCiで簡単な値の型を表示するのに`:type`コマンドを使うと確認できます。 ```text $ spago repl @@ -87,7 +90,8 @@ Array Boolean Could not match type Int with type Boolean. ``` -最後の例で起きているエラーは型検証器によって報告されたもので、配列の2つの要素の型を*単一化*(Unification、等価にする意)しようとして失敗したことを示しています。 +最後の例は型検証器によるエラーを示しています。 +配列の2つの要素の型を*単一化*(つまり等価にする意)するのに失敗したのです。 レコードはJavaScriptのオブジェクトに対応しており、レコード直値はJavaScriptのオブジェクト直値と同じ構文になっています。 @@ -100,8 +104,9 @@ Could not match type Int with type Boolean. } ``` -この型が示しているのは、指定されたオブジェクトは、 `String`型のフィールド `name` と `Array String`つまり -`String`の配列の型のフィールド `interests` という2つの _フィールド_ (field) を持っているということです。 +この型が示しているのは指定されたオブジェクトが2つの*フィールド*を持っているということです。 +それぞれ`String`型のフィールド`name`と`Array +String`型のフィールド`interests`で、後者は`String`の配列ということです。 ドットに続けて参照したいフィールドのラベルを書くとレコードのフィールドを参照できます。 @@ -113,29 +118,22 @@ Could not match type Int with type Boolean. ["Functional Programming","JavaScript"] ``` -PureScriptの関数はJavaScriptの関数に対応しています。PureScriptの標準ライブラリは多くの関数の例を提供しており、この章ではそれらをもう少し詳しく見ていきます。 - -```text -> import Prelude -> :type flip -forall a b c. (a -> b -> c) -> b -> a -> c - -> :type const -forall a b. a -> b -> a -``` - -ファイルのトップレベルでは、等号の直前に引数を指定することで関数を定義できます。 +PureScriptの関数はJavaScriptの関数に対応します。 +関数はファイルの最上位で定義でき、等号の前に引数を指定します。 ```haskell +import Prelude -- (+) 演算子をスコープに持ち込みます + add :: Int -> Int -> Int add x y = x + y ``` -バックスラッシュに続けて空白文字で区切られた引数名のリストを書くことで、関数をインラインでも定義できます。 -PSCiで複数行の宣言を入力するには、 `:paste`コマンドを使用して「貼り付けモード」に入ります。 -このモードでは、*Control-D*キーシーケンスを使用して宣言を終了します。 +代えて、バックスラッシュ文字に続けて空白文字で区切られた引数名のリストを書くことで、関数をインラインでも定義できます。 +PSCiで複数行の宣言を入力するには、`:paste`コマンドを使用して「貼り付けモード」に入ります。 +このモードでは、*Control-D*キーシーケンスを使って宣言を終了します。 ```text +> import Prelude > :paste … add :: Int -> Int -> Int … add = \x y -> x + y @@ -149,53 +147,11 @@ PSCiでこの関数が定義されていると、次のように関数の隣に2 30 ``` -## 量化された型 - -前の節ではPreludeで定義された関数の型を幾つか見てきました。 -例えば`flip`関数は次のような型を持っていました。 - -```text -> :type flip -forall a b c. (a -> b -> c) -> b -> a -> c -``` - -この `forall`キーワードは、 `flip`が _全称量化された型_ (universally quantified type) -を持っていることを示しています。これは、 `a`や `b`、 `c`をどの型に置き換えても、 `flip`はその型でうまく動作するという意味です。 - -例えば、 `a`を `Int`、 `b`を `String`、 `c`を `String`というように選んでみたとします。この場合、 -`flip`の型を次のように*特殊化* (specialize) できます。 - -```text -(Int -> String -> String) -> String -> Int -> String -``` - -量化された型を特殊化したいということをコードで示す必要はありません。 -特殊化は自動的に行われます。 -例えば次のように単に`flip`を使用できます。 -あたかも既にその型の`flip`を持っていたかのようです。 - -```text -> flip (\n s -> show n <> s) "Ten" 10 - -"10Ten" -``` - -`a`、 `b`、 `c`の型はどんな型でも選ぶことができるといっても、型の不整合は生じないようにしなければなりません。 -`flip`に渡す関数の型は、他の引数の型と整合性がなくてはなりません。 -第2引数として文字列 `"Ten"`、第3引数として数 `10`を渡したのはそれが理由です。 -もし引数が逆になっているとうまくいかないでしょう。 - -```text -> flip (\n s -> show n <> s) 10 "Ten" - -Could not match type Int with type String -``` - ## 字下げについての注意 PureScriptのコードは字下げの大きさに意味があります。ちょうどHaskellと同じで、JavaScriptとは異なります。コード内の空白の多寡は無意味ではなく、Cのような言語で中括弧によってコードのまとまりを示しているように、PureScriptでは空白がコードのまとまりを示すために使われているということです。 -宣言が複数行にわたる場合は、最初の行以外は最初の行の字下げより深くしなければなりません。 +宣言が複数行にわたる場合、最初の行以外は最初の行の字下げより深くしなければなりません。 したがって、次は正しいPureScriptコードです。 @@ -211,7 +167,7 @@ add x y z = x + y + z ``` -後者では、PureScriptコンパイラはそれぞれの行ごとに1つ、つまり*2つ*の宣言であると構文解析します。 +後者では、PureScriptコンパイラはそれぞれの行毎に1つ、つまり*2つ*の宣言であると構文解析します。 一般に、同じブロック内で定義された宣言は同じ深さで字下げする必要があります。 例えばPSCiでlet文の宣言は同じ深さで字下げしなければなりません。 @@ -233,19 +189,30 @@ y + z … ^D ``` -PureScriptの幾つかの予約語(例えば `where`や `of`、 -`let`)は新たなコードのまとまりを導入しますが、そのコードのまとまり内の宣言はそれより深く字下げされている必要があります。 +PureScriptの幾つかのキーワードは新たなコードのまとまりを導入します。 +その中での宣言はそれより深く字下げされなければなりません。 ```haskell -example x y z = foo + bar - where +example x y z = + let foo = x * y bar = y * z + in + foo + bar ``` -ここで `foo`や `bar`の宣言は `example`の宣言より深く字下げされていることに注意してください。 +これはコンパイルされません。 -ただし、ソースファイルの先頭、最初の `module`宣言における予約語 `where`だけは、この規則の唯一の例外になっています。 +```haskell +example x y z = + let + foo = x * y + bar = y * z + in + foo + bar +``` + +より多くを学びたければ(あるいは何か問題に遭遇したら)[構文](https://github.com/purescript/documentation/blob/master/language/Syntax.md#syntax)のドキュメントを参照してください。 ## 独自の型の定義 @@ -255,10 +222,10 @@ PureScriptで新たな問題に取り組むときは、まずはこれから扱 {{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}} ``` -これは `Entry`という*型同義語*(type synonym、型シノニム)を定義しています。 -型 `Entry`は等号の右辺と同じ型ということです。 -レコードの型は何れも文字列である `firstName`、 `lastName`、 `phone`という3つのフィールドからなります。 -前者の2つのフィールドは型 `String`を持ち、 `address`は以下のように定義された型 `Address`を持っています。 +これは`Entry`という*型同義語*を定義しています。 +型`Entry`は等号の右辺と等価ということです。 +レコードの型は`firstName`、`lastName`、`phone`という3つのフィールドからなります。 +2つの名前のフィールドは型`String`を持ち、`address`は以下で定義された型`Address`を持ちます。 ```haskell {{#include ../exercises/chapter3/src/Data/AddressBook.purs:Address}} @@ -266,23 +233,24 @@ PureScriptで新たな問題に取り組むときは、まずはこれから扱 なお、レコードには他のレコードを含めることができます。 -それでは、3つめの型同義語も定義してみましょう。住所録のデータ構造としては、単に項目の連結リストとして格納することにします。 +それでは、住所録のデータ構造として3つめの型同義語も定義してみましょう。 +単に項目の連結リストとして表すことにします。 ```haskell {{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}} ``` -`List Entry`は `Array Entry`とは同じではないということに注意してください。 `Array Entry`は住所録の項目の -_配列_ を意味しています。 +なお、`List Entry`は `Array Entry`とは同じではありません。 +後者は項目の*配列*を表しています。 ## 型構築子と種 -`List`は*型構築子*(type constructor、型コンストラクタ)の一例になっています。`List`そのものは型ではなく、何らかの型 -`a`があるとき `List a`が型になっています。つまり、 `List`は _型引数_ (type argument) `a`をとり、新たな型 -`List a`を _構築_ するのです。 +`List`は*型構築子*の一例になっています。 +`List`そのものは型ではなく、何らかの型 `a`があるとき `List a`が型になっています。 +つまり、 `List`は*型引数*`a`を取り、新たな型 `List a`を*構築*するのです。 -ちょうど関数適用と同じように、型構築子は他の型に並べることで適用されることに注意してください。型 `List Entry`は実は型構築子 -`List`が型 `Entry`に _適用_ されたものです。これは住所録項目のリストを表しています。 +なお、ちょうど関数適用と同じように、型構築子は他の型に並置するだけで適用されます。 +実際、型`List Entry`は型構築子`List`が型`Entry`に*適用*されたもので、項目のリストを表しています。 もし間違って(型注釈演算子 `::`を使って)型 `List`の値を定義しようとすると、今まで見たことのない種類のエラーが表示されるでしょう。 @@ -316,20 +284,71 @@ Type PureScriptの _種システム_ は他にも面白い種に対応していますが、それらについては本書の他の部分で見ていくことになるでしょう。 +## 量化された型 + +説明しやすくするため、任意の2つの引数を取り最初のものを返す原始的な関数を定義しましょう。 + +```text +> :paste +… constantlyFirst :: forall a b. a -> b -> a +… constantlyFirst = \a b -> a +… ^D +``` + +> なお、`:type`を使って`constantlyfirst`の型について尋ねた場合、もっと冗長になります。 +> +> ```text +> : type constantlyFirst +> forall (a :: Type) (b :: Type). a -> b -> a +> ``` +> +> 型シグネチャには追加で種の情報が含まれます。 +> `a`と`b`が具体的な型であることが明記されています。 + +この`forall`キーワードは、`constantlyFirst`が*全称量化された型*を持つことを示しています。 +つまり`a`や`b`をどの型に置き換えても良く、`constantlyFirst`はその型で動作するのです。 + +例えば、`a`を`Int`、`b`を`String`と選んだとします。 +その場合、`constantlyFirst`の型を次のように*特殊化*できます。 + +```text +Int -> String -> Int +``` + +量化された型を特殊化したいということをコードで示す必要はありません。 +特殊化は自動的に行われます。 +例えば、あたかも既にその型に備わっていたかの如く`constantlyFirst`を使えます。 + +```text +> constantlyFirst 3 "ignored" + +3 +``` + +`a`と`b`にはどんな型でも選べますが、`constantlyFirst`が返す型は最初の引数の型と同じでなければなりません(両方とも同じ`a`に「紐付く」からです)。 + +```text +:type constantlyFirst true "ignored" +Boolean + +:type constantlyFirst "keep" 3 +String +``` + ## 住所録の項目の表示 それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。 まずは関数に型を与えることから始めます。 型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくようにすると良いでしょう。 -実際、トップレベルの宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。 +実際、最上位の宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。 型宣言は関数の名前とその型を `::`記号で区切るようにして書きます。 ```haskell {{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_signature}} ``` -`showEntry`は引数として `Entry`を取り `String`を返す関数であるということを、この型シグネチャは言っています。 -`showEntry`のコードは次の通りです。 +この型シグネチャが言っているのは、`showEntry`は引数として`Entry`を取り`String`を返す関数であるということです。 +以下は`showEntry`のコードです。 ```haskell {{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_implementation}} @@ -389,8 +408,8 @@ $ spago repl ## 住所録の作成 -今度は住所録の操作を支援する関数を幾つか書いてみましょう。 -空の住所録を表す値が必要ですが、これには空のリストを使います。 +今度は住所録を扱う補助関数を幾つか書いてみましょう。 +空の住所録を表す値が必要ですが、これは空のリストです。 ```haskell {{#include ../exercises/chapter3/src/Data/AddressBook.purs:emptyBook}} @@ -402,15 +421,14 @@ $ spago repl {{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}} ``` -この型シグネチャに書かれているのは、最初の引数として `Entry`、第二引数として `AddressBook`を取り、新しい -`AddressBook`を返すということです。 +この型シグネチャに書かれているのは、最初の引数として`Entry`、第2引数として`AddressBook`を取り、新しい`AddressBook`を返すということです。 -既存の `AddressBook`を直接変更することはしません。 -その代わりに、同じデータが含まれている新しい `AddressBook`を返すようにします。 -このように、 `AddressBook`は*不変データ構造*の一例となっています。 +既存の`AddressBook`を直接変更することはしません。 +代わりに、同じデータが含まれている新しい`AddressBook`を返します。 +このように`AddressBook`は*不変データ構造*の一例となっています。 これはPureScriptにおける重要な考え方です。 -変更はコードの副作用であり、効率の良いコードの挙動を考えるときの妨げになります。 -そのため、可能な限り純粋な関数や不変のデータにする方が好ましいのです。 +変更はコードの副作用であり、効率良く挙動を探る上で妨げになります。 +そのため可能な限り純粋関数や不変なデータにする方が好ましいのです。 `insertEntry`を実装するのに`Data.List`の`Cons`関数が使えます。 この関数の型を見るには、PSCiを起動し `:type`コマンドを使います。 @@ -421,10 +439,10 @@ $ spago repl > import Data.List > :type Cons -forall a. a -> List a -> List a +forall (a :: Type). a -> List a -> List a ``` -この型シグネチャで書かれているのは、`Cons`が何らかの型`a`の値と型`a`を要素に持つリストを引数に取り、同じ型の要素を持つ新しいリストを返すということです。 +この型シグネチャで書かれているのは、`Cons`が何らかの型`a`の値と型`a`の要素のリストを取り、同じ型の項目を持つ新しいリストを返すということです。 `a`を`Entry`型として特殊化してみましょう。 ```haskell @@ -447,24 +465,75 @@ Entry -> AddressBook -> AddressBook insertEntry entry book = Cons entry book ``` -等号の左側にある2つの引数`entry`と`book`がスコープに導入されますから、これらに `Cons`関数を適用して結果の値を作成しています。 +こうすると、等号の左側にある2つの引数`entry`と`book`がスコープに導入されます。 +それから`Cons`関数を適用し、結果を作成しています。 ## カリー化された関数 -PureScriptでは、関数は常に1つの引数だけを取ります。`insertEntry`関数は2つの引数を取るように見えますが、これは実際には*カリー化された関数*の一例となっています。 +PureScriptの関数はきっかり1つの引数を取ります。 +`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。 +PureScriptでは全ての関数はカリー化されたものと見做されます。 + +カリー化が意味するのは複数の引数を取る関数を1度に1つ取る関数に変換することです。 +関数を呼ぶときに1つの引数を渡し、これまた1つの引数を取る別の関数を返し、といったことを全ての引数が渡されるまで続けます。 + +例えば`add`に`5`に渡すと別の関数が得られます。 +その関数は整数を取り、5を足し、合計を結果として返します。 + +```haskell +add :: Int -> Int -> Int +add x y = x + y + +addFive :: Int -> Int +addFive = add 5 +``` + +`addFive`は*部分適用*の結果です。 +つまり複数の引数を取る関数に、引数の全個数より少ない数だけ渡すのです。 +試してみましょう。 + +> なお、お済みでなければ`add`関数を定義しなくてはなりません。 +> +> ```text +> > import Prelude +> > :paste +>… add :: Int -> Int -> Int +>… add x y = x + y +>… ^D +> ``` + +```text +> :paste +… addFive :: Int -> Int +… addFive = add 5 +… ^D + +> addFive 1 +6 + +> add 5 1 +6 +``` + +カリー化と部分適用をもっと理解するには、例にあった`add`とは別の関数を2、3作ってみてください。 +そしてそれができたら`insertEntry`に戻りましょう。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}} +``` -`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。 +(型シグネチャ中の)`->`演算子は右結合です。 +つまりコンパイラは型を次のように解釈します。 ```haskell Entry -> (AddressBook -> AddressBook) ``` -すなわち、 `insertEntry`は関数を返す関数である、ということです。 -この関数は単一の引数 `Entry`を取り、それから単一の引数 `AddressBook`を取り新しい -`AddressBook`を返す新しい関数を返すのです。 +`insertEntry`は単一の引数`Entry`を取り、新しい関数を返します。 +そして今度はその関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。 -これは例えば、最初の引数だけを与えると `insertEntry`を _部分適用_ (partial application) -できることを意味します。PSCiでこの結果の型を見てみましょう。 +これはつまり、最初の引数だけを与えて`insertEntry`を*部分適用*できたりするということです。 +PSCiで結果の型が見られます。 ```text > :type insertEntry entry @@ -480,14 +549,15 @@ AddressBook -> AddressBook AddressBook ``` -ここで括弧は不要であることにも注意してください。次の式は同等です。 +ただし、ここでの括弧は不要です。 +以下は等価です。 ```text > :type insertEntry entry emptyBook AddressBook ``` -これは関数適用が左結合であるためで、なぜ空白で区切った引数を関数に指定するだけでいいのかの説明にもなっています。 +これは関数適用が左に結合するためで、なぜ空白で区切った引数を次々に関数に指定するだけでいいのかの説明にもなっています。 関数の型の`->`演算子は関数の*型構築子*です。 この演算子は2つの型引数を取ります。 @@ -503,10 +573,10 @@ insertEntry :: Entry -> AddressBook -> AddressBook insertEntry entry book = Cons entry book ``` -もし式の右辺に明示的に括弧をつけるなら、 `(Cons entry) book`となります。 -`insertEntry entry`はその引数が単に関数 `(Cons entry)`に渡されるような関数だということです。 -でもこの2つの関数はどんな入力についても同じ結果を返しますから、つまりこれらは同じ関数です。 -よって、両辺から引数 `book`を削除できます。 +もし式の右辺に明示的に括弧をつけるなら、`(Cons entry) book`となります。 +つまり`insertEntry entry`はその引数が単に関数`(Cons entry)`に渡されるような関数だということです。 +ところがこの2つの関数はどんな入力についても同じ結果を返すので、となると同じ関数ではないですか。 +よって、両辺から引数`book`を削除できます。 ```haskell insertEntry :: Entry -> AddressBook -> AddressBook @@ -519,10 +589,11 @@ insertEntry entry = Cons entry {{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}} ``` -この処理は _イータ変換_ (eta conversion) と呼ばれ、(その他の技法を併用して)引数を参照することなく関数を定義する -_ポイントフリー形式_ (point-free form) へと関数を書き換えるのに使うことができます。 +この処理は*イータ変換*と呼ばれ、(その他の技法を併用して)*ポイントフリー形式*へと関数を書き換えるのに使えます。 +つまり、引数を参照せずに関数を定義できるのです。 -`insertEntry`の場合には、イータ変換によって「`insertEntry`は単にリストに対するconsだ」となり、関数の定義はとても明確になりました。しかし、一般的にポイントフリー形式のほうがいいのかどうかには議論の余地があります。 +`insertEntry`の場合、イータ変換によって「`insertEntry`は単にリストにおけるconsだ」となり、とても明快な関数の定義になりました。 +しかし、一般にポイントフリー形式のほうがいいのかどうかには議論の余地があります。 ## プロパティ取得子 @@ -559,13 +630,14 @@ _.address.city ## 住所録に問い合わせる -最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索し適切な -`Entry`を返すものです。これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるでしょう。 +最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索し適切な`Entry`を返すものです。 +これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるでしょう。 -まずは住所録を絞り込み、該当する姓名を持つ項目だけを保持するようにするのがいいでしょう。それから、結果のリストの先頭の (head) -要素を返すだけです。 +住所録を絞り込めば該当する姓名を持つ項目だけを保持するようにできます。 +そうすれば結果のリストの先頭(つまり最初)の要素を返せます。 -この大まかな仕様に従って、この関数の型を計算できます。まずPSCiを起動し、 `filter`関数と `head`関数の型を見てみましょう。 +この大まかな道筋の仕様があれば関数の型を計算できます。 +まずPSCiを開いて`filter`関数と`head`関数の型を探してみましょう。 ```text $ spago repl @@ -573,24 +645,23 @@ $ spago repl > import Data.List > :type filter -forall a. (a -> Boolean) -> List a -> List a +forall (a :: Type). (a -> Boolean) -> List a -> List a > :type head -forall a. List a -> Maybe a +forall (a :: Type). List a -> Maybe a ``` 型の意味を理解するために、これらの2つの型の一部を取り出してみましょう。 -`filter`はカリー化された2引数の関数です。 -最初の引数は、リストの要素を取り `Boolean`値を結果として返す関数です。 +`filter`は2引数のカリー化された関数です。 +最初の引数は関数で、リストの要素を取り`Boolean`値を返します。 第2引数は要素のリストで、返り値は別のリストです。 -`head`は引数としてリストを取り、 `Maybe a`という今まで見たことがないような型を返します。 -`Maybe a`は型 `a`のオプショナルな値、つまり -`a`の値を持つか持たないかのどちらかの値を示しており、JavaScriptのような言語で値がないことを示すために使われる -`null`の型安全な代替手段を提供します。 -これについては後の章で詳しく扱います。 +`head`は引数としてリストを取り、 `Maybe a`という今までに見たことがない型を返します。 +`Maybe +a`は型`a`の省略可能な値を表しており、JavaScriptのような言語で値がないことを示すための`null`を使う代わりとなる、型安全な代替を提供します。 +後の章で改めて詳しく見ていきます。 `filter`と `head`の全称量化された型は、PureScriptコンパイラによって次のように _特殊化_ (specialized) されます。 @@ -601,7 +672,7 @@ filter :: (Entry -> Boolean) -> AddressBook -> AddressBook head :: AddressBook -> Maybe Entry ``` -検索する関数の引数として姓と名前を渡す必要があるのもわかっています。 +関数の引数として姓名を渡す必要があるだろうということは分かっています。 `filter`に渡す関数も必要になることもわかります。この関数を `filterEntry`と呼ぶことにしましょう。 `filterEntry`は `Entry -> Boolean`という型を持っています。 `filter filterEntry`という関数適用の式は、 `AddressBook -> AddressBook`という型を持つでしょう。もしこの関数の結果を `head`関数に渡すと、型 `Maybe Entry`の結果を得ることになります。 @@ -611,8 +682,8 @@ head :: AddressBook -> Maybe Entry {{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_signature}} ``` -この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び`AddressBook`を引数に取り、`Entry`のオプション型の値を結果として返すということです。 -オプショナルな結果は名前が住所録で発見された場合にのみ値を持ちます。 +この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び`AddressBook`を引数に取り、省略可能な`Entry`を返すということです。 +省略可能な結果は名前が住所録に見付かった場合にのみ値を持ちます。 そして、 `findEntry`の定義は次のようになります。 @@ -628,8 +699,8 @@ findEntry firstName lastName book = head (filter filterEntry book) `findEntry`は、どちらも文字列型である `firstName`と `lastName`、`AddressBook`型の `book`という3つの名前をスコープに導入します。 -定義の右辺では `filter`関数と `head`関数が組み合わされています。 -まず項目のリストを絞り込み、その結果に `head`関数を適用しています。 +定義の右辺では`filter`関数と`head`関数が組み合わさっています。 +まず項目のリストを絞り込み、その結果に`head`関数を適用しています。 真偽型を返す関数 `filterEntry`は `where`節の内部で補助的な関数として定義されています。 このため、 `filterEntry`関数はこの定義の内部では使用できますが、外部では使用できません。 @@ -637,32 +708,33 @@ findEntry firstName lastName book = head (filter filterEntry book) `firstName`と `lastName`を使用しているので、 `filterEntry`が `findEntry`の内部にあることは必須になっています。 -最上位での宣言と同じように、必ずしも -`filterEntry`の型シグネチャを指定しなくてもよいことに注意してください。ただし、ドキュメントとしても役に立つので型シグネチャを書くことは推奨されています。 +なお、最上位での宣言と同じように、必ずしも`filterEntry`の型シグネチャを指定しなくても構いません。 +ただし、ドキュメントの一形態として指定しておくことが推奨されます。 ## 中置の関数適用 -これまでお話しした関数のほとんどは _前置_ 関数適用でした。関数名が引数の _前_ -に置かれていたということです。例えば`insertEntry`関数を使って`Entry` (`john`) -を空の`AddressBook`に追加する場合、以下のように書けます。 +これまでお話しした関数のほとんどは*前置*関数適用でした。 +関数名が引数の*前*に置かれていたということです。 +例えば`insertEntry`関数を使って`Entry` (`john`) を空の`AddressBook`に追加する場合、以下のように書けます。 ```haskell > book1 = insertEntry john emptyBook ``` -しかしこの章には _中置_ -[2引数演算子](https://github.com/purescript/documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれています。例えば`filterEntry`の定義中の`==`演算子で、演算子が2つの引数の -_間_ に置かれています。実はこうした中置演算子はPureScriptのソースコードで、背後にある _前置_ -版の実装への中置別称として定義されています。例えば`==`は以下の行により前置の`eq`関数の中置別称として定義されています。 +しかし本章には*中置*[2引数演算子](https://github.com/purescript/documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれています。 +`filterEntry`の定義中の`==`演算子がそうで、2つの引数の*間*に置かれています。 +PureScriptのソースコードでこうした中置演算子は隠れた*前置*の実装への中置別称として定義されています。 +例えば`==`は以下の行により前置の`eq`関数の中置別称として定義されています。 ```haskell infix 4 eq as == ``` したがって`filterEntry`中の`entry.firstName == firstName`は`eq entry.firstName -firstName`で置き換えられます。この節の後のほうで中置演算子を定義する例にもう少し触れます。 +firstName`で置き換えられます。 +この節の後のほうで中置演算子を定義する例にもう少し触れます。 -前置関数を演算子としての中置の位置に置くとより読みやすいコードになる場面があります。 +前置関数を演算子としての中置の位置に置くと、より読みやすいコードになる場面があります。 その一例が`mod`関数です。 ```text @@ -670,8 +742,9 @@ firstName`で置き換えられます。この節の後のほうで中置演算 2 ``` -上の用例は正しく動きますが、読みづらいです。 -より馴染みのある表現の仕方は「8 mod 3」ですが、バックスラッシュ (\`) の中に前置関数を包めばこのように書けます。 +上の用例でも充分動作しますが、読みにくいです。 +より馴染みのある表現の仕方は「8 mod 3」です。 +バックスラッシュ (\`) の中に前置関数を包むとそのように書けます。 ```text > 8 `mod` 3 @@ -707,7 +780,7 @@ infixr 5 insertEntry as ++ book5 = john ++ (peggy ++ (ned ++ emptyBook)) ``` -そして新しい`++`演算子が右結合なので意味を変えずに括弧を除去できます。 +新しい`++`演算子の右結合性により、意味を変えずに括弧を除去できます。 ```haskell book6 = john ++ peggy ++ ned ++ emptyBook @@ -725,7 +798,7 @@ book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook この記号の意味を覚えるための記憶術として、ドル記号を2つの括弧に打ち消し線が引かれたものと見ることで、これで括弧が不必要になったのだと推測できるという方法があります。 なお、`($)`は言語にハードコードされた特別な構文ではありません。 -単に`apply`という名前の通常の関数のための中置演算子であって、`Data.Function`で以下のように定義されています。 +単に`apply`という名前の普通の関数のための中置演算子であって、`Data.Function`で以下のように定義されています。 ```haskell apply :: forall a b. (a -> b) -> a -> b @@ -811,7 +884,8 @@ filter filterEntry >>> head どちらにしても、これは「`findEntry`は絞り込み関数と`head`関数の合成である」という `findEntry`関数のわかりやすい定義を与えます。 -どちらの定義のほうがわかりやすいかの判断はお任せしますが、このように関数を部品として捉えると有用なことがよくあります。関数は1つの役目だけをこなし、機能を関数合成で組み立てるというように。 +どちらの定義のほうが分かりやすいかの判断はお任せしますが、このように関数を部品として捉えるとしばしば有用です。 +各関数は1つの役目をこなすようにし、解法を関数合成を使って組み立てるのです。 ## 演習 @@ -826,24 +900,25 @@ filter filterEntry >>> head 実装した関数をPSCiと`spago test`を走らせてテストしてください。 1. (普通)`filterEntry`を(`<<<`や`>>>`を使った)合成で置き換えて、`findEntryByStreet`を書き直してください。 合成の対象は、プロパティ取得子(`_.`記法を使います)と、与えられた文字列引数が与えられた通りの住所に等しいかを判定する関数です。 - 1. (普通)指定された名前が `AddressBook`に存在するかどうかを調べて真偽値で返す関数`isInBook`を書いてみましょう。 - *手掛かり*:リストが空かどうかを調べる `Data.List.null`関数の型をPSCiで調べてみてみましょう。 - 1. (難しい)「重複」している項目を住所録から削除する関数 `removeDuplicates`を書いてみましょう。 + 1. (普通)名前が`AddressBook`に存在するかどうかを調べて真偽値で返す関数`isInBook`を書いてみましょう。 + *手掛かり*:PSCiを使って`Data.List.null`関数の型を見付けてください。 + この関数はリストが空かどうかを調べます。 + 1. (難しい)「重複」している住所録の項目を削除する関数`removeDuplicates`を書いてみましょう。 項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複していると考えます。 - *手掛かり*:関数 `Data.List.nubBy`の型を、PSCiを使用して調べてみましょう。 - この関数は値同士の等価性を定義する述語関数に基づいてリストから重複要素を削除します。 - なお、それぞれの重複する項目の集合における最初の要素(リストの先頭に最も近い)が保持する項目です。 + *手掛かり*:`Data.List.nubByEq`関数の型をPSCiを使って調べましょう。 + この関数は等価性の述語に基づいてリストから重複要素を削除します。 + なお、それぞれの重複する項目の集合において最初の要素(リストの先頭に最も近い)が保持する項目です。 ## まとめ -この章では、関数型プログラミングの新しい概念を幾つも導入しました。 +この章では関数型プログラミングの新しい概念を幾つか押さえ、以下の方法を学びました。 -- 対話的モードのPSCiを使用して、関数を調べるなどの思いついたことを試す方法 -- 検証や実装の道具としての型の役割 -- 多引数関数を表現する、カリー化された関数の使用 -- 関数合成で小さな部品を組み合わせてのプログラムの構築 -- `where`節を利用したコードの構造化 -- `Maybe`型を使用してnull値を回避する方法 -- イータ変換や関数合成のような手法を利用した、よりわかりやすいコードへの再構成 +- 対話的モードのPSCiを使用して、関数で実験したり思いついたことを試したりする。 +- 正確さのための道具として、また実装のための道具として型を使う。 +- 多引数の関数を表現するためにカリー化された関数を使う。 +- 合成により小さな部品からプログラムを作る。 +- `where`式を使ってコードを手際良く構造化する。 +- `Maybe`型を使用してnull値を回避する。 +- イータ変換や関数合成のような技法を使ってより分かりやすい仕様にリファクタする。 次の章からは、これらの考えかたに基づいて進めていきます。 diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md index 2a89ea8a..37b5187a 100644 --- a/text-ja/chapter4.md +++ b/text-ja/chapter4.md @@ -2,12 +2,14 @@ ## この章の目標 -この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて見ていきましょう。再帰は関数型プログラミングの基本的な手法であり、この本の全体に亙って使われます。 +この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて見ていきましょう。 +再帰は関数型プログラミングの基本的な手法であり、本書全体にわたって使われます。 また、PureScriptの標準ライブラリから標準的な関数を幾つか取り扱います。 `map`や`fold`といった関数だけでなく、`filter`や`concatMap`といった特別な場合において便利なものについても見ていきます。 -この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用います。この章で学ぶ手法を応用して、擬似的なファイルシステムによって表されるファイルのプロパティを計算する関数を記述します。 +この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用います。 +この章で学ぶ技術を応用し、ファイルシステムのモデルにより表現されるファイルのプロパティを計算する関数を書きます。 ## プロジェクトの準備 @@ -31,7 +33,7 @@ test`を走らせることで解答を確認してください。 再帰は一般のプログラミングでも重要な手法ですが、特に純粋関数型プログラミングでは当たり前のように用いられます。この章で見ていくように、再帰はプログラムの変更可能な状態を減らすために役立つからです。 再帰は*分割統治*戦略と密接な関係があります。 -分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分ごとの答えから最終的な答えを組み立てるということです。 +分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分毎の答えから最終的な答えを組み立てるということです。 それでは、PureScriptにおける再帰の簡単な例を幾つか見てみましょう。 @@ -41,9 +43,11 @@ test`を走らせることで解答を確認してください。 {{#include ../exercises/chapter4/test/Examples.purs:factorial}} ``` -部分問題へ問題を分割することによって階乗関数がどのように計算されるかがわかります。より小さい数へと階乗を計算していくということです。ゼロに到達すると、答えは直ちに求まります。 +このように、問題を部分問題へ分割することによって階乗関数の計算方法が見てとれます。 +より小さい数の階乗を計算していくということです。 +ゼロに到達すると、答えは直ちに求まります。 -次は、 _フィボナッチ関数_ (Fibonacci function) を計算するという、これまたよくある例です。 +次は、*フィボナッチ関数*を計算するという、これまたよくある例です。 ```haskell {{#include ../exercises/chapter4/test/Examples.purs:fib}} @@ -53,7 +57,8 @@ test`を走らせることで解答を確認してください。 このとき、`fib (n - 1)`と`fib (n - 2)`という式に対応した、2つの部分問題があります。 これらの2つの部分問題が解決されていれば、この部分的な答えを加算することで、全体の答えを組み立てることができます。 -なお上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。パターン照合の技法は後の章でお話しします。 +> なお、上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。 +> パターン照合の技法は後の章でお話しします。 ## 配列上での再帰 @@ -72,26 +77,30 @@ import Data.Maybe (fromMaybe) ``` この関数では配列が空かどうかで分岐するために`if ... then ... else`式を使っています。 -この`null`関数は配列が空のときに`true`を返します。 -空の配列の長さはゼロであり、空でない配列の長さは配列の先頭を取り除いた残りの部分の長さより1大きいというわけです。 +この`null`関数は空の配列で`true`を返します。 +空の配列の長さはゼロであり、空でない配列の長さは尾鰭の長さより1大きいというわけです。 -`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返します。配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。`fromMaybe`関数は既定値と`Maybe`値を取ります。後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返します。 +`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返します。 +配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。 +`fromMaybe`関数は既定値と`Maybe`値を取ります。 +後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返します。 -JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえませんが、次の演習を完遂するための手がかりとしては充分でしょう。 +JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえませんが、次の演習を完遂するための手掛かりとしては充分でしょう。 ## 演習 - 1. (簡単)入力が偶数であるとき、かつそのときに限り`true`に返すような再帰関数を書いてみましょう。 - 2. (少し難しい)配列内の偶数の数を数える再帰関数`countEven`を書いてみましょう。 - *手掛かり*:`Data.Array`モジュールの`head`関数を使うと、空でない配列の最初の要素を見つけることができます。 + 1. (簡単)入力が偶数であるとき、かつそのときに限り`true`に返す再帰関数`isEven`を書いてみましょう。 + 2. (普通)配列内の偶数の整数を数える再帰関数`countEven`を書いてみましょう。 + *手掛かり*:`head`関数(これも`Data.Array`モジュールから手に入ります)を使うと、空でない配列の最初の要素を見つけられます。 ## マップ -`map`関数は配列に対する再帰関数の1つです。この関数を使うと、配列の各要素に順番に関数を適用することで、配列の要素を変換できます。そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存されます。 +`map`関数は配列に対する再帰関数の一例です。 +配列の各要素に順番に関数を適用し、配列の要素を変換するのに使われます。 +そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存されます。 -本書の後半で _型クラス_ (type class) -の内容を押さえるとき、`map`関数が形状保存関数のより一般的な様式の一例であることを見ていきます。これは _関手_ (functor) -と呼ばれる型構築子のクラスを変換するものです。 +本書の後半で*型クラス*の内容を押さえるとき、`map`関数が形状を保存する関数のより一般的な様式の一例であることを見ていきます。 +この関数は*関手*と呼ばれる型構築子のクラスを変換するものです。 それでは、PSCiで`map`関数を試してみましょう。 @@ -117,7 +126,7 @@ $ spago repl この構文は _中置関数適用_ と呼ばれ、どんな関数でもこのように中置できます。普通は2引数の関数に対して使うのが最適でしょう。 -配列を扱うときは、`map`関数と等価な`<$>`という演算子が存在します。この演算子は他の二項演算子と同じように中置で使用できます。 +配列を扱う際は`map`関数と等価な`<$>`という演算子が存在します。 ```text > (\n -> n + 1) <$> [1, 2, 3, 4, 5] @@ -128,13 +137,13 @@ $ spago repl ```text > :type map -forall a b f. Functor f => (a -> b) -> f a -> f b +forall (f :: Type -> Type) (a :: Type) (b :: Type). Functor f => (a -> b) -> f a -> f b ``` 実は`map`の型は、この章で必要とされているものよりも一般的な型になっています。今回の目的では、`map`は次のようなもっと具体的な型であるかのように考えるとよいでしょう。 ```text -forall a b. (a -> b) -> Array a -> Array b +forall (a :: Type) (b :: Type). (a -> b) -> Array a -> Array b ``` この型では、`map`関数に適用するときには`a`と`b`という2つの型を自由に選ぶことができる、ということも示されています。 @@ -151,7 +160,7 @@ forall a b. (a -> b) -> Array a -> Array b 中置演算子`<$>`は特別な構文のように見えるかもしれませんが、実はPureScriptの普通の関数の別称です。 中置構文を使用した単なる*適用*にすぎません。 実際、括弧でその名前を囲むと、この関数を通常の関数のように使用できます。 -これは、`map`代わりに、括弧で囲まれた`(<$>)`という名前を使って配列に関数を適用できるということです。 +これは、`map`代わりに、括弧で囲まれた`(<$>)`という名前が使えるということです。 ```text > (<$>) show [1, 2, 3, 4, 5] @@ -181,7 +190,7 @@ infix 8 range as .. 上記の例では、`1 .. 5`という式は括弧で囲まれていましたが、実際にはこれは必要ありません。 なぜなら、`Data.Array`モジュールは、`<$>`に割り当てられた優先順位より高い優先順位を`..`演算子に割り当てているからです。 -上の例では、`..`の優先順位は、予約語`infix`のあとに書かれた数の`8` と定義されていました。 +上の例では、`..`の優先順位は、キーワード`infix`のあとに書かれた数の`8` と定義されていました。 ここでは`<$>`の優先順位よりも高い優先順位を`..`に割り当てており、このため括弧を付け加える必要がないということです。 ```text @@ -189,12 +198,13 @@ infix 8 range as .. ["1","2","3","4","5"] ``` -中置演算子に(左または右の)*結合性*を与えたい場合は、代わりに予約語`infixl`と`infixr`を使います。`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。 +中置演算子に(左または右の)*結合性*を与えたい場合は、代わりにキーワード`infixl`と`infixr`を使います。 +`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。 ## 配列の絞り込み `Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供しています。 -この関数は、述語関数に適合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。 +この関数は、述語関数に照合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。 例えば1から10までの数で、偶数であるような数の配列を計算したいとします。 これは次のようにできます。 @@ -227,13 +237,14 @@ infix 8 range as .. > import Data.Array > :type concat -forall a. Array (Array a) -> Array a +forall (a :: Type). Array (Array a) -> Array a > concat [[1, 2, 3], [4, 5], [6]] [1, 2, 3, 4, 5, 6] ``` -関連する関数として、`concat`と`map`を組み合わせたような`concatMap`と呼ばれる関数もあります。`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それに対して`concatMap`は値から値の配列への関数を取ります。 +関連する関数として、`concat`と`map`を組み合わせた`concatMap`と呼ばれる関数もあります。 +`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それに対して`concatMap`は値から値の配列への関数を取ります。 実際に動かして見てみましょう。 @@ -241,7 +252,7 @@ forall a. Array (Array a) -> Array a > import Data.Array > :type concatMap -forall a b. (a -> Array b) -> Array a -> Array b +forall (a :: Type) (b :: Type). (a -> Array b) -> Array a -> Array b > concatMap (\n -> [n, n * n]) (1 .. 5) [1,1,2,4,3,9,4,16,5,25] @@ -333,9 +344,8 @@ PSCiを対話式の開発環境として使用し、1つずつこの手順を進 しかし、このコードの可読性は大幅に向上できます。`map`や`concatMap`は基本的な関数であり、 _do記法_ (do notation) と呼ばれる特別な構文の基礎になっています(もっと厳密にいえば、それらの一般化である`map`と`bind`が基礎をなしています)。 -*補足*:`map`と`concatMap`が _配列内包表記_ を書けるようにしているように、もっと一般的な演算子である`map`と`bind`は -_モナド内包表記_ (monad comprehensions) と呼ばれているものを書けるようにします。本書の後半では _モナド_ (monad) -の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。 +> *補足*:`map`と`concatMap`があることで*配列内包表記*を書けるように、もっと一般的な演算子である`map`と`bind`があることで*モナド内包表記*と呼ばれているものが書けます。 +> 本書の後半では*モナド*の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。 do記法を使うと、先ほどの`factors`関数を次のように書き直すことができます。 @@ -343,12 +353,13 @@ do記法を使うと、先ほどの`factors`関数を次のように書き直す {{#include ../exercises/chapter4/test/Examples.purs:factors}} ``` -キーワード`do`はdo記法を使うコードのブロックを導入します。このブロックは幾つかの種類の式で構成されています。 +キーワード`do`はdo記法を使うコードのブロックを導入します。 +このブロックは幾つかの種類の式で構成されています。 - 配列の要素を名前に束縛する式。 - これは後ろ向きの矢印`<-`で示されていて、その左側は名前、右側は配列の型を持つ式です。 + これは後ろ向きの矢印`<-`で示されており、左側には名前が、右側には配列の型を持つ式があります。 - 名前に配列の要素を束縛しない式。 - `do`の _結果_ はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されています。 + `do`の*結果*はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されています。 - `let`キーワードを使用し、式に名前を与える式。 この新しい記法を使うと、アルゴリズムの構造がわかりやすくなることがあります。 @@ -362,7 +373,7 @@ do記法を使うと、先ほどの`factors`関数を次のように書き直す ``` 配列の場合、`pure`は単に1要素の配列を作成します。 -実際、`factors`関数を変更して、`pure`の代わりにこの形式も使うようにできます。 +`factors`関数を変更して、`pure`の代わりにこの形式も使うようにできます。 ```haskell {{#include ../exercises/chapter4/test/Examples.purs:factorsV2}} @@ -388,7 +399,7 @@ import Control.Alternative (guard) > import Control.Alternative > :type guard -forall m. Alternative m => Boolean -> m Unit +forall (m :: Type -> Type). Alternative m => Boolean -> m Unit ``` 今回の場合は、PSCiは次の型を報告するものと考えてください。 @@ -409,7 +420,8 @@ Boolean -> Array Unit 0 ``` -つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返すのです。もし式が`false`と評価された場合は、その結果は空です。 +つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返すのです。 +もし式が`false`と評価された場合は、その結果は空です。 ガードが失敗した場合、配列内包表記の現在の分岐は、結果なしで早めに終了されることを意味します。 これは、`guard`の呼び出しが、途中の配列に対して`filter`を使用するのと同じだということです。 @@ -418,24 +430,25 @@ Boolean -> Array Unit ## 演習 - 1. (簡単)整数の引数が素数であるかどうかを調べる関数`isPrime`を定義してみましょう。 + 1. (簡単)関数`isPrime`を書いてください。 + この関数は整数の引数が素数であるかを調べます。 *手掛かり*:`factors`関数を使ってください。 1. (普通)do記法を使い、2つの配列の*直積集合*を見つけるための関数`cartesianProduct`を書いてみましょう。 直積集合とは、要素`a`、`b`の全ての組み合わせの集合のことです。 ここで`a`は最初の配列の要素、`b`は2つ目の配列の要素です。 - 1. (普通)数値`n`を取って構成要素(値`a`, `b`, `c`)がそれぞれ`n`以下であるような全てのピタゴラスの3つ組 - (pythagorean triples) を返す関数`triples :: Int -> Array (Array - Int)`を書いてください。 - *ピタゴラスの3つ組*は数値の配列`[a, b, c]`で `a² + b² = c²` です。 + 1. (普通)関数`triples :: Int -> Array (Array Int)`を書いてください。 + この関数は数値`n`を取り、構成要素(値`a`、`b`、`c`)がそれぞれ`n`以下であるような全てのピタゴラスの3つ組 + (pythagorean triples) を返します。 + *ピタゴラスの3つ組*は`a² + b² = c²`であるような数値の配列`[a, b, c]`です。 *手掛かり*:配列内包表記で`guard`関数を使ってください。 - 1. (難しい)`factors`関数を使用して、数`n`の[素因数分解](https://www.mathsisfun.com/prime-factorization.html)を求める関数`primeFactors`を定義してみましょう。 - 数`n`の素因数分解とは、素数の積が`n`であるような整数の配列のことです。 + 1. (難しい)`factors`関数を使用して、`n`の[素因数分解](https://www.mathsisfun.com/prime-factorization.html)を求める関数`primeFactors`を定義してみましょう。 + `n`の素因数分解とは、積が`n`であるような素数の配列のことです。 *手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してください。 最初の因数を探し、それから残りの因数を探すのです。 ## 畳み込み -配列における左右の畳み込みは、再帰を用いて実装される別の興味深い一揃いの関数を提供します。 +配列における左右の畳み込みは、再帰を用いて実装できる別の興味深い一揃いの関数を提供します。 PSCiを使って、`Data.Foldable`モジュールをインポートし、`foldl`と`foldr`関数の型を調べることから始めましょう。 @@ -443,30 +456,38 @@ PSCiを使って、`Data.Foldable`モジュールをインポートし、`foldl` > import Data.Foldable > :type foldl -forall a b f. Foldable f => (b -> a -> b) -> b -> f a -> b +forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (b -> a -> b) -> b -> f a -> b > :type foldr -forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b +forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (a -> b -> b) -> b -> f a -> b ``` これらの型は、現在興味があるものよりも一般化されています。 -この章の目的に対して、PSCiは以下の(より具体的な)答えをくれていると考えておきましょう。 +この章では単純化して以下の(より具体的な)型シグネチャと見て構いません。 ```text -> :type foldl +-- foldl forall a b. (b -> a -> b) -> b -> Array a -> b -> :type foldr +-- foldr forall a b. (a -> b -> b) -> b -> Array a -> b ``` -どちらの型でも、`a`は配列の要素の型に対応しています。 -型`b`は、配列を走査 (traverse) したときの結果を累積する「累積器」(accumulator) の型だと考えることができます。 +どちらの場合でも、型`a`は配列の要素の型に対応しています。 +型`b`は「累算器」の型として考えることができます。 +累算器とは配列を走査しつつ結果を累算するものです。 `foldl`関数と`foldr`関数の違いは走査の方向です。 `foldr`が「右から」配列を畳み込むのに対して、`foldl`は「左から」配列を畳み込みます。 -実際にこれらの関数の動きを見てみましょう。`foldl`を使用して数の配列の和を求めてみます。型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。ここでは、次の要素を累積器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累積器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。最初の引数としては、加算演算子を使用できますし、累積器の初期値はゼロになります。 +実際にこれらの関数の動きを見てみましょう。 +`foldl`を使用して数の配列の和を求めてみます。 +型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。 +ここでは3つの引数を与える必要があります。 +1つ目は次の要素を累算器に加算する`Int -> Int -> Int`という型の関数です。 +2つ目は累算器の`Int`型の初期値です。 +3つ目は和を求めたい`Int`の配列です。 +最初の引数としては、加算演算子を使用できますし、累算器の初期値はゼロになります。 ```text > foldl (+) 0 (1 .. 5) @@ -480,8 +501,8 @@ forall a b. (a -> b -> b) -> b -> Array a -> b 15 ``` -`foldl`と`foldr`の違いを説明するために、畳み込み関数の選択が影響する例も書いてみましょう。 -加算関数の代わりに、文字列連結を使用して文字列を作ってみます。 +違いを説明するために、畳み込み関数の選択が大事になってくる例も書きましょう。 +加算関数の代わりに、文字列連結を使用して文字列を構築しましょう。 ```text > foldl (\acc n -> acc <> show n) "" [1,2,3,4,5] @@ -497,7 +518,7 @@ forall a b. (a -> b -> b) -> b -> Array a -> b ((((("" <> show 1) <> show 2) <> show 3) <> show 4) <> show 5) ``` -それに対し、右畳み込みは以下に相当します。 +それに対し、右畳み込みは以下と等価です。 ```text ((((("" <> show 5) <> show 4) <> show 3) <> show 2) <> show 1) @@ -505,8 +526,8 @@ forall a b. (a -> b -> b) -> b -> Array a -> b ## 末尾再帰 -再帰はアルゴリズムを定義するための強力な手法ですが、問題も抱えています。 -JavaScriptで再帰関数を評価するとき、入力が大きすぎるとスタックオーバーフローでエラーを起こす可能性があるのです。 +再帰はアルゴリズムを指定する強力な手法ですが、問題も抱えています。 +JavaScriptで再帰関数を評価するとき、入力が大き過ぎるとスタックオーバーフローでエラーを起こす可能性があるのです。 PSCiで次のコードを入力すると、この問題を簡単に検証できます。 @@ -525,18 +546,20 @@ PSCiで次のコードを入力すると、この問題を簡単に検証でき RangeError: Maximum call stack size exceeded ``` -これは問題です。関数型プログラミングの基本的な手法として再帰を採用しようとするなら、境界がない可能性がある再帰でも扱える方法が必要です。 +これは問題です。 +関数型プログラミングの標準的な手法として再帰を採用しようとするなら、境界がない再帰がありうるときでも扱える方法が必要です。 -PureScriptは _末尾再帰最適化_ (tail recursion optimization) -の形でこの問題に対する部分的な解決策を提供しています。 +PureScriptは*末尾再帰最適化*の形でこの問題に対する部分的な解決策を提供しています。 -*補足*:この問題へのより完全な解決策としては、いわゆる*トランポリン*を使用したライブラリで実装する方法がありますが、それはこの章で扱う範囲を超えています。 -この内容に興味のある読者は[`free`](https://pursuit.purescript.org/packages/purescript-free)や[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec)パッケージのドキュメントを参照してみてください。 +> *補足*:この問題へのより完全な解決策としては、いわゆる*トランポリン*を使用するライブラリで実装できますが、それはこの章で扱う範囲を超えています。 +> 興味のある読者は[`free`](https://pursuit.purescript.org/packages/purescript-free)や[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec)パッケージのドキュメントをあたると良いでしょう。 -末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 _末尾位置_ (tail position) -にある関数の再帰的な呼び出しは、スタックフレームが確保されない _ジャンプ_ -に置き換えることができます。関数が戻るより前の最後の呼び出しであるとき、呼び出しが _末尾位置_ -にあるといいます。なぜこの例でスタックオーバーフローが見られたのかはこれが理由です。この`f`の再帰呼び出しは、末尾位置 _ではない_ からです。 +末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 +*末尾位置*にある関数の再帰的な呼び出しは*ジャンプ*に置き換えられます。 +このジャンプではスタックフレームが確保されません。 +関数が戻るより前の最後の呼び出しであるとき、呼び出しが*末尾位置*にあるといいます。 +なぜ先の例でスタックオーバーフローが見られたのかはこれが理由です。 +`f`の再帰呼び出しが末尾位置*でなかったからです。 実際には、PureScriptコンパイラは再帰呼び出しをジャンプに置き換えるのではなく、再帰的な関数全体を _whileループ_ に置き換えます。 @@ -546,13 +569,14 @@ PureScriptは _末尾再帰最適化_ (tail recursion optimization) {{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}} ``` -`fact`への再帰呼び出しは、この関数の中で起こる最後のものである、つまり末尾位置にあることに注意してください。 +`factorialTailRec`への再帰呼び出しがこの関数の最後にある点に注目してください。 +つまり末尾位置にあるのです。 -## 累積器 +## 累算器 -末尾再帰ではない関数を末尾再帰関数に変える一般的な方法としては、 _累積器引数_ (accumulator parameter) -を使用する方法があります。累積器引数は関数に追加される余剰の引数で返り値を _累積_ -するものです。これは結果を累積するために返り値を使うのとは対称的です。 +末尾再帰ではない関数を末尾再帰関数に変える一般的な方法は、*累算器引数*を使用することです。 +累算器引数は関数に追加される余剰の引数で、返り値を*累算*するものです。 +これは結果を累算するために返り値を使うのとは対照的です。 例えば章の初めに示した`length`関数を再考しましょう。 @@ -571,19 +595,23 @@ length arr = {{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}} ``` -ここでは、配列を逆転させる作業を補助関数`length'`に委譲しています。`length'`は末尾再帰です。その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。これは、生成されたコードが -_whileループ_ となり、大きな入力でもスタックが溢れないことを意味します。 +ここでは補助関数`length'`に委譲しています。 +この関数は末尾再帰です。 +その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。 +つまり、生成されるコードは*whileループ*となり、大きな入力でもスタックが溢れません。 -`lengthTailRec`の実装を理解するために補助関数`length'`に着目しましょう。この関数は必然的に累積器引数を使って追加の状態……これは部分的な結果です……を保持しています。0から始まり、入力の配列中の全ての要素それぞれについて1ずつ足されて大きくなっていきます。 +`lengthTailRec`の実装を理解する上では、補助関数`length'`が基本的に累算器引数を使って追加の状態を保持していることに注目してください。 +追加の状態とは、部分的な結果です。 +0から始まり、入力の配列中の全ての各要素について1ずつ足されて大きくなっていきます。 -累積器を「状態」と考えることもできますが、直接には変更されているわけではないことにも注意してください。 +なお、累算器を「状態」と考えることもできますが、直接には変更されていません。 ## 明示的な再帰より畳み込みを選ぼう -末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けることができるので、全ての関数をこの形で書こうとする誘惑にかられます。 +末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けられるので、全ての関数をこの形で書こうとする誘惑にかられます。 しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書くことができることを忘れがちです。 `map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、コードの単純さという利点があります。 -これらの部品はよく知られており、明示的な再帰よりもアルゴリズムの*意図*をよりはっきりとさせるのです。 +これらの部品はよく知られており、だからこそ明示的な再帰よりもアルゴリズムの*意図*がより良く伝わるのです。 例えば`foldr`を使って配列を反転できます。 @@ -607,13 +635,13 @@ _whileループ_ となり、大きな入力でもスタックが溢れないこ 2. (普通。テストなし)関数`foldl (==) false xs`が真を返すような配列`xs`とはどのようなものか説明してください。 言い換えると、「関数は`xs`が……を含むときに`true`を返す」という文を完成させることになります。 3. (普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`を書いてください。 - *手掛かり*:累積器引数を使ってください。 + *手掛かり*:累算器引数を使ってください。 4. (普通)`foldl`を使って`reverse`を書いてみましょう。 ## 仮想ファイルシステム -この節では、これまで学んだことを応用して、模擬的なファイルシステムで動作する関数を書いていきます。 -事前に定義されたAPIで動作するように、マップ、畳み込み、及びフィルタを使用します。 +この節ではこれまで学んだことを応用してファイルシステムのモデルを扱う関数を書きます。 +事前に定義されたAPIを扱う上でマップ、畳み込み、及びフィルタを使用します。 `Data.Path`モジュールでは、次のように仮想ファイルシステムのAPIが定義されています。 @@ -621,7 +649,7 @@ _whileループ_ となり、大きな入力でもスタックが溢れないこ - ルートディレクトリを表すパス`root`があります。 - `ls`関数はディレクトリ内のファイルを列挙します。 - `filename`関数は`Path`のファイル名を返します。 -- `size`関数は`Path`が示すファイルの大きさを返します。 +- `size`関数はファイルを表す`Path`のファイルの大きさを返します。 - `isDirectory`関数はファイルかディレクトリかを調べます。 型について言うと、次のような型定義があります。 @@ -655,19 +683,23 @@ true [/bin/,/etc/,/home/] ``` -`Test.Examples`モジュールでは`Data.Path`APIを使用する関数を定義しています。 +`Test.Examples`モジュールでは`Data.Path` APIを使用する関数を定義しています。 `Data.Path`モジュールを変更したり定義を理解したりする必要はありません。 全て`Test.Examples`モジュールだけで作業します。 ## 全てのファイルの一覧 -それでは、ディレクトリの中身を含めた全てのファイルを列挙する関数を書いてみましょう。この関数は以下のような型を持つでしょう。 +それでは、ディレクトリの中身を含めた全てのファイルを深く列挙する関数を書いてみましょう。 +この関数は以下のような型を持つでしょう。 ```haskell {{#include ../exercises/chapter4/test/Examples.purs:allFiles_signature}} ``` -再帰を使ってこの関数を定義できます。まずは`ls`を使用してディレクトリの直接の子を列挙します。それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返ってくるでしょう。同時に`concatMap`を適用すると、この結果を平坦にできます。 +再帰を使ってこの関数を定義できます。 +`ls`を使うとディレクトリ直下の子が列挙されます。 +それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返ります。 +`concatMap`を使うと、`allFiles`を適用して平坦化するまでを一度にできます。 最後に、cons演算子`:`を使って現在のファイルも含めます。 @@ -675,8 +707,8 @@ true {{#include ../exercises/chapter4/test/Examples.purs:allFiles_implementation}} ``` -*補足*:実はcons演算子`:`は、不変な配列に対して効率性が悪いので、一般的には推奨されません。 -連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させることができます。 +> *補足*:実はcons演算子`:`は、不変な配列に対して効率性が悪いので、一般的には推奨されません。 +> 連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させられます。 それではPSCiでこの関数を試してみましょう。 @@ -694,8 +726,9 @@ do記法で配列内包表記を使ってもこの関数を書くことができ 逆向きの矢印は配列から要素を選択するのに相当することを思い出してください。 最初の工程は引数の直接の子から要素を選択することです。 -それから、単にそのファイルに対してこの再帰関数を呼びします。 -do記法を使用しているので、再帰的な結果を全て連結する`concatMap`が暗黙に呼び出されています。 +それからそのファイルに対して再帰関数を呼び出します。 +do記法を使用しているので`concatMap`が暗黙に呼び出されています。 +この関数は再帰的な結果を全て連結します。 新しいバージョンは次のようになります。 @@ -703,7 +736,9 @@ do記法を使用しているので、再帰的な結果を全て連結する`co {{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}} ``` -PSCiで新しいコードを試してみてください。同じ結果が返ってくるはずです。どちらのほうがわかりやすいかの選定はお任せします。 +PSCiで新しいコードを試してみてください。 +同じ結果が返ってくるはずです。 +どちらのほうがわかりやすいかの選定はお任せします。 ## 演習 @@ -722,11 +757,11 @@ PSCiで新しいコードを試してみてください。同じ結果が返っ ``` *手掛かり*:この関数をdo記法を使った配列内包表記で書いてみましょう。 - 3. (難しい)`Path`を取って`Path`に最大のファイルと最小のファイルを1つずつ含む配列を返す関数`largestSmallest`を書いてください。 - *補足*:空配列や1要素の配列を返すことで、`Path`にゼロか1個のファイルがある場合についても考慮してください。 + 3. (難しい)`Path`中の最大のファイルと最小のファイルを1つずつ含む配列を返す関数`largestSmallest`を書いてください。 + *補足*:空配列や1要素の配列を返すことで、`Path`にそれぞれゼロか1個のファイルがある場合についても考慮してください。 ## まとめ -この章では、アルゴリズムを簡潔に表現する手段として、PureScriptでの再帰の基本を説明しました。 +この章ではアルゴリズムを簡潔に表現するためにPureScriptでの再帰の基本を押さえました。 また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関数、及びこれらの概念を組み合わせた配列内包表記を導入しました。 -最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累積器引数を使用して末尾再帰形に関数を変換する方法を示しました。 +最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。 diff --git a/text-ja/chapter5.md b/text-ja/chapter5.md index 3afe1547..3d08a94c 100644 --- a/text-ja/chapter5.md +++ b/text-ja/chapter5.md @@ -2,22 +2,25 @@ ## この章の目標 -この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱います。 +この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。 +また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱います。 -パターン照合は関数型プログラミングにおける一般的な手法で、複数の場合に実装を分解することにより、開発者は水面下では複雑な動作をする関数を簡潔に書くことができます。 +パターン照合は関数型プログラミングにおける一般的な手法であり、開発者が簡潔に関数を書けるようになります。 +関数の実装を複数の場合に分解することにより、水面下の複雑なアイディアが表現されるのです。 -代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等の水準の表現力を可能にしています。パターン照合とも密接に関連しています。 +代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等の水準の表現力を可能にしています。 +パターン照合とも密接に関連しています。 -この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラフィックスを描画し操作するためのライブラリを書くことです。 +この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラフィックスを記述し操作するためのライブラリを書くことです。 ## プロジェクトの準備 この章のソースコードはファイル `src/Data/Picture.purs`で定義されています。 -`Data.Picture`モジュールは、簡単な図形を表すデータ型 `Shape`や、図形の集合である型 -`Picture`、及びこれらの型を扱うための関数を定義しています。 +`Data.Picture`モジュールは簡単な図形を表すデータ型`Shape`やその図形の集合である型`Picture`を定義します。 +また、これらの型を扱うための関数もあります。 -このモジュールでは、データ構造の畳込みを行う関数を提供する `Data.Foldable`モジュールもインポートします。 +このモジュールでは、データ構造を畳込む関数を提供する`Data.Foldable`モジュールもインポートします。 ```haskell {{#include ../exercises/chapter5/src/Data/Picture.purs:module_picture}} @@ -29,14 +32,16 @@ {{#include ../exercises/chapter5/src/Data/Picture.purs:picture_import_as}} ``` -こうすると型や関数をモジュール内で使用できるようになりますが、`Number.max`のように*修飾名*を使ったときに限定されます。重複したインポートを避けたり、どのモジュールからインポートされたのかを明らかにするのに役立ちます。 +こうすると型や関数をモジュール内で使用できるようになりますが、 +`Number.max`のように*修飾名*を使ったときに限定されます。 +重複したインポートを避けたり、どのモジュールからインポートされたのかを明らかにするのに役立ちます。 -*補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありません。 -`import Math as M`などのより短い名前にできますし、かなりよく見掛けます。 +> *補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありません。 +> `import Math as M`などのより短い名前にできますし、かなりよく見掛けます。 ## 単純なパターン照合 -それではコード例を見ることから始めましょう。 +例を見ることから始めましょう。 パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになります。 ```haskell @@ -45,13 +50,13 @@ このアルゴリズムはユークリッドの互除法と呼ばれています。 その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が見つかるでしょう。 -パターン照合の利点の1つは、上記のようにコードを場合分けして定義でき、数学関数の定義と似たような簡潔で宣言型なコードを書くことができることです。 +パターン照合の利点の1つは、コードを場合分けして定義でき、数学関数の仕様に似た単純で宣言型なコードを定義できることです。 パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作します。 この定義の各行は*選択肢*や*場合*と呼ばれています。 等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ以上のパターンで構成されています。 場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなければならない条件を表現しています。 -それぞれの場合は上からこの順番に試されていき、最初に入力に適合した場合が返り値を決定します。 +それぞれの場合は上からこの順番に試されていき、最初にパターンが入力に照合した場合が返り値を決定します。 例えば`gcd`関数は次の手順で評価されます。 @@ -63,21 +68,21 @@ なお、パターンでは値を名前に束縛できます。 この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛しています。 -さまざまな種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力の引数から名前を選ぶさまざまな方法に対応することがわかるでしょう。 +様々な種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力の引数から名前を選ぶ様々な方法に対応することがわかるでしょう。 ## 単純なパターン 上記のコード例では、2種類のパターンを示しました。 -- `Int`型の値が正確に一致する場合にのみ適合する、整数直値パターン +- `Int`型の値が正確に一致する場合にのみ照合する、整数直値パターン - 引数を名前に束縛する、変数パターン 単純なパターンには他にも種類があります。 - `Number`、`String`、`Char`、そして`Boolean`といった直値 -- どんな引数とも適合するが名前に束縛はしない、アンダースコア (`_`) で表されるワイルドカードパターン +- どんな引数とも照合するが名前に束縛はしない、アンダースコア (`_`) で表されるワイルドカードパターン -ここではこれらの単純なパターンを使用して、もう2つ例を示します。 +これらの単純なパターンを使用する実演として、もう2つの例が以下です。 ```haskell {{#include ../exercises/chapter5/src/ChapterExamples.purs:fromString}} @@ -89,16 +94,19 @@ PSCiでこれらの関数を試してみてください。 ## ガード -ユークリッドの互除法の例では、`m > n`のときと `m <= n`のときの2つに分岐するために `if .. then .. else`式を使っていました。こういうときには他に _ガード_ (guard) を使うという選択肢もあります。 +ユークリッドの互除法の例では、`m > n`のときと`m <= n`のときの2つの選択肢の間を切り替えるために`if .. then .. else`式を使いました。 +こういうときには*ガード*を使うという他の選択肢もあります。 -ガードはパターンによる制約に加えて満たされなくてはいけない真偽値の式です。 -ガードを使用してユークリッドの互除法を書き直すと、次のようになります。 +ガードとは、パターンにより課された制約に加えて満たされなくてはいけない真偽値の式です。 +ガードを使用してユークリッドのアルゴリズムを書き直すと、次のようになります。 ```haskell {{#include ../exercises/chapter5/src/ChapterExamples.purs:gcdV2}} ``` -この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を付け加えています。最後の行でのガードは式`otherwise`を使っており、キーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。 +この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を課しています。 +最後の行でのガードは式`otherwise`を使っています。 +これはキーワードのようにも見えますが、実際はただの`Prelude`にある普通の束縛です。 ```text > :type otherwise @@ -121,7 +129,7 @@ true 数式\\( n! / k! (n - k)! \\)を使ってください。 ここで \\( ! \\) は前に書いた階乗関数です。 *手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。 - 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、もっと使用例を追加してみてください。 + 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、特殊な場合を更に追加してみてください。 1. (普通)[_パスカルの法則_](https://en.wikipedia.org/wiki/Pascal%27s_rule)を使って前の演習と同じ2項係数を計算する関数`pascal`を書いてください。 ## 配列パターン @@ -134,13 +142,13 @@ true {{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}} ``` -次の関数では、長さ5の配列と適合し、配列の5つの要素をそれぞれ違った方法で束縛しています。 +次の関数では、長さ5の配列と照合し、配列の5つの要素をそれぞれ違った方法で束縛しています。 ```haskell {{#include ../exercises/chapter5/src/ChapterExamples.purs:takeFive}} ``` -最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にのみ適合します。 +最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にのみ照合します。 その場合、関数は第3要素と第4要素の積を返します。 それ以外の場合は、関数は0を返します。 例えばPSCiで試してみると次のようになります。 @@ -161,8 +169,9 @@ true 0 ``` -配列の直値パターンでは、固定長の配列と一致させることはできますが、PureScriptは不特定の長さの配列を照合させる手段を提供していません。 -そのような方法で不変な配列を分解すると、実行速度が低下する可能性があるためです。 +配列の直値パターンでは、固定長の配列と一致させることはできます。 +しかしPureScriptは不特定の長さの配列を照合させる手段は全く提供して*いません*。 +そのような類の方法で不変な配列を分解すると、実行速度が低下する可能性があるためです。 このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めします。 その他の操作について、より優れた漸近性能を提供するデータ構造も存在します。 @@ -187,7 +196,7 @@ true > showPerson { first: x, last: y } = y <> ", " <> x > :type showPerson -forall r. { first :: String, last :: String | r } -> String +forall (r :: Row Type). { first :: String, last :: String | r } -> String ``` この型変数 `r`は何でしょうか。 @@ -201,9 +210,9 @@ PSCiで`showPerson`を使ってみると、面白いことがわかります。 "Freeman, Phil" ``` -レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま動作するのです。レコードに少なくとも型が`String`であるようなフィールド -`first`と `last`が含まれていれば、関数適用は正しく型付けされます。しかし、フィールドが _不足_ していると、 -`showPerson`の呼び出しは _不正_ となります。 +レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま動作するのです。 +レコードに少なくとも型が`String`であるようなフィールド`first`と`last`が含まれていれば、関数適用は正しく型付けされます。 +しかし、フィールドが*不足*していると、`showPerson`の呼び出しは*不正*となります。 ```text > showPerson { first: "Phil" } @@ -221,12 +230,12 @@ _厳密に_ `first`と`last`フィールドしかないレコードのみを受 > showPerson p = p.last <> ", " <> p.first ``` -この場合も、 PSCiは先ほどと同じ型を推論するでしょう。 +そしてPSCiは同じ型を推論することでしょう。 ## レコード同名利用 -`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と -`y`という名前の値に束縛していたのでした。別の方法として、フィールド名自体を再利用するだけで、このようなパターン照合を次のように単純化できます。 +`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と`y`という名前の値に束縛していたのでした。 +別の方法として、フィールド名自体を再利用してこのような類のパターン照合を次のように単純化できます。 ```haskell {{#include ../exercises/chapter5/src/ChapterExamples.purs:showPersonV2}} @@ -242,11 +251,14 @@ _厳密に_ `first`と`last`フィールドしかないレコードのみを受 {{#include ../exercises/chapter5/src/ChapterExamples.purs:unknownPerson}} ``` -こうすると、状況によってはコードの可読性向上に役立ちます。 +こうすると、状況によってはコードの可読性が向上します。 ## 入れ子になったパターン -配列パターンとレコードパターンはどちらも小さなパターンを組み合わせることで大きなパターンを構成しています。これまでの例ではほとんどの場合で配列パターンとレコードパターンの内部に単純なパターンを使用していましたが、パターンを自由に*入れ子*にできることも知っておくのが大切です。入れ子になったパターンを使うと、潜在的に複雑なデータ型に対して条件分岐を用いて関数を定義できるようになります。 +配列パターンとレコードパターンはどちらも小さなパターンを組み合わせることで大きなパターンを構築しています。 +これまでのほとんどの例では配列パターンとレコードパターンの内部で単純なパターンを使用していました。 +しかし特筆すべきこととして、パターンは自由に*入れ子*にできます。 +これにより潜在的に複雑なデータ型についての条件を使って関数を定義できます。 例えばこのコードは2つのレコードパターンを組み合わせています。 @@ -265,8 +277,8 @@ _厳密に_ `first`と`last`フィールドしかないレコードのみを受 {{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}} ``` -このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。なおもし入力の配列が _厳密に_ -2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返しています。 +このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。 +なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返します。 ## 演習 @@ -274,12 +286,16 @@ _厳密に_ `first`と`last`フィールドしかないレコードのみを受 1. (普通)行多相を考慮すると、 `sameCity`関数の最も一般的な型は何でしょうか。 先ほど定義した`livesInLA`関数についてはどうでしょうか。 *補足*:この演習にテストはありません。 -1. (普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数`fromSingleton`を書いてみましょう。1要素だけを持つ配列でない場合、関数は指定された既定値を返します。この関数は - `forall a. a -> Array a -> a`という型を持っています。 +1. (普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数`fromSingleton`を書いてみましょう。 + 1要素だけを持つ配列でない場合、関数は与えられた既定値を返します。 + この関数は`forall a. a -> Array a -> a`という型を持ちます。 -## Case式 +## case式 -パターンは最上位にある関数宣言だけに現れるわけではありません。`case`式を使って計算の途中の値に対してパターン照合を使うことができます。case式には無名関数に似たような便利さがあります。関数に名前を与えることがいつも望ましいわけではないように、パターン照合を使いたいためだけに関数に名前をつけるようなことを避けられるようになります。 +パターンが現れるのは最上位にある関数宣言だけではありません。 +`case`式を使う計算中の途中の値に対してパターン照合を使えます。 +case式には無名関数に似た便利さがあります。 +関数に名前を与えることがいつも望ましいわけではないように、パターンを使いたいためだけに関数に名前をつけるようなことを避けられるようになります。 例を示しましょう。 次の関数は、配列の「最長ゼロ末尾」(和がゼロであるような、最も長い配列の末尾)を計算します。 @@ -300,12 +316,15 @@ _厳密に_ `first`と`last`フィールドしかないレコードのみを受 [-1, -2, 3] ``` -この関数は場合ごとの分析によって動作します。もし配列が空なら、唯一の選択肢は空の配列を返すことです。配列が空でない場合は、更に2つの場合に分けるためにまず -`case`式を使用します。配列の合計がゼロであれば、配列全体を返します。そうでなければ、配列の残りに対して再帰します。 +この関数は場合毎の分析によって動作します。 +もし配列が空なら、唯一の選択肢は空の配列を返すことです。 +配列が空でない場合は、更に2つの場合に分けるためにまず`case`式を使用します。 +配列の合計がゼロであれば、配列全体を返します。 +そうでなければ、配列の残りに対して再帰します。 ## パターン照合の失敗と部分関数 -case式のパターンを順番に照合していって、もし選択肢の何れの場合も入力が適合しなかった時は何が起こるのでしょうか。 +case式のパターンを順番に照合していって、どの選択肢の場合も入力が照合しなかった時はどうなるのでしょう。 この場合、*パターン照合失敗*によって、case式は実行時に失敗します。 簡単な例でこの動作を見てみましょう。 @@ -316,7 +335,9 @@ case式のパターンを順番に照合していって、もし選択肢の何 {{#include ../exercises/chapter5/src/ChapterExamples.purs:partialFunction}} ``` -この関数は単一の場合しか含んでおらず、単一の入力である`true`にのみ照合します。このファイルをコンパイルしてPSCiでそれ以外の値を与えてテストすると、実行時エラーが発生します。 +この関数は単一の場合しか含んでいません。 +そしてその場合は単一の入力である`true`にのみ照合します。 +このファイルをコンパイルしてPSCiでそれ以外の値を与えて試すと実行時エラーが発生します。 ```text > partialFunction false @@ -324,17 +345,16 @@ case式のパターンを順番に照合していって、もし選択肢の何 Failed pattern match ``` -どんな入力の組み合わせに対しても値を返すような関数は _全関数_ (total function) と呼ばれ、そうでない関数は _部分的_ -(partial) であると呼ばれます。 +どんな入力の組み合わせに対しても値を返すような関数は*全関数*と呼ばれ、そうでない関数は*部分的*であると呼ばれます。 一般的には、可能な限り全関数として定義したほうが良いと考えられています。 もし関数が何らかの妥当な入力の集合について結果を返さないことがわかっているなら、大抵は失敗であることを示すことができる値を返すほうがよいでしょう。 例えば何らかの`a`についての型`Maybe a`で、妥当な結果を返せないときは`Nothing`を使います。 この方法なら、型安全な方法で値の有無を示すことができます。 -PureScriptコンパイラは、パターンマッチが不完全で関数が全関数ではないことを検出するとエラーを生成します。 -部分関数が安全である場合、`unsafePartial`関数を使ってこれらのエラーを抑制できます(その部分関数が安全だと言い切れるなら)。 -もし上記の `unsafePartial`関数の呼び出しを取り除くと、コンパイラは次のエラーを生成します。 +PureScriptコンパイラは、パターン照合が不完全であるために関数が全関数ではないことが検出されると、エラーを出します。 +`unsafePartial`関数を使うとこうしたエラーを抑制できます(ただしその部分関数が安全だと言い切れるなら)。 +もし上記の`unsafePartial`関数の呼び出しを取り除くと、コンパイラは次のエラーを出します。 ```text A case expression could not be determined to cover all inputs. @@ -360,9 +380,10 @@ partialFunction true = true Partial => Boolean -> Boolean ``` -本書ではのちに`=>`記号を含むいろいろな型を見ることになります(これらは*型クラス*に関連しています)。しかし、今のところは、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。 +本書では以降、`=>`記号が絡む(*型クラス*に関連する)型をもっと見ていきます。 +しかし現時点では、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。 -コンパイラは、定義されたパターンが _冗長_ であることを検出した場合(前の方に定義されたパターンのみに一致する場合)でも警告を生成します。 +コンパイラは、*冗長*な場合を検出したとき(つまり、その場合より前の方に定義された場合にのみ一致するとき)などにも警告を出します。 ```haskell redundantCase :: Boolean -> Boolean @@ -379,7 +400,8 @@ A case expression contains unreachable cases: false ``` -*補足*:PSCiは警告を表示しないので、この例を再現するには、この関数をファイルとして保存し、 `pulp build`を使ってコンパイルします。 +> *補足*:PSCiは警告を表示しません。 +> そのため、この例を再現するには、この関数をファイルとして保存し、`spago build`を使ってコンパイルします。 ## 代数的データ型 @@ -394,10 +416,10 @@ A case expression contains unreachable cases: しかし、この方針は大きな欠点を1つ抱えています。 `Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に把握し、`Shape`インターフェースに定義する必要があるのです。 -このため、モジュール性を壊さずに新しい操作を追加することが難しくなります。 +モジュール性を壊さずに新しい操作を追加することが難しくなります。 -もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決する型安全な方法を提供します。モジュール性のある方法で -`Shape`に新たな操作を定義し、型安全性を維持できます。 +もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決する型安全な方法を提供します。 +モジュール性のある方法で `Shape`に新たな操作を定義しつつ、型安全性を維持できます。 代数的データ型としてどのように`Shape`が表現されるかを次に示します。 @@ -411,12 +433,14 @@ A case expression contains unreachable cases: `Shape`は、中央 `Point`と半径(数値)を持つ `Circle`か、`Rectangle`、 `Line`、 `Text`の何れかです。 他に`Shape`型の値を構築する方法はありません。 -代数的データ型の定義はキーワード `data`から始まり、それに新しい型の名前と任意個の型引数が続きます。その型の構築子(あるいは _データ構築子_ -(data constructor))は等号の後に定義され、パイプ文字 (`|`) -で区切られます。ADTの構築子が持つデータは原始型に限りません。構築子にはレコード、配列、また他のADTさえも含むことができます。 +代数的データ型 (algebraic data type; ADT) +の定義はキーワード`data`から始まり、それに新しい型の名前と任意個の型引数が続きます。 +その型の構築子(これを*データ構築子*と言います)は等号の後に定義され、パイプ文字 (`|`) で区切られます。 +ADTの構築子が持つデータは原始型に限りません。 +構築子にはレコード、配列、また他のADTさえも含められます。 それではPureScriptの標準ライブラリから別の例を見てみましょう。 -オプショナルな値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。 +省略可能な値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。 `maybe`パッケージでは `Maybe`を次のように定義しています。 ```haskell @@ -426,7 +450,7 @@ data Maybe a = Nothing | Just a この例では型引数 `a`の使用方法を示しています。パイプ文字を「または」と読むことにすると、この定義は「`Maybe a`型の値は、無い (`Nothing`) か、ただの (`Just`) 型 `a`の値だ」とほぼ英語のように読むことができます。 -なおデータ定義のどこにも構文`forall a`を使っていません。 +なお、データ定義のどこにも構文`forall a`を使っていません。 `forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義するときは使われません。 データ構築子は再帰的なデータ構造を定義するためにも使用できます。更に例を挙げると、要素が型 @@ -469,14 +493,15 @@ data List a = Nil | Cons a (List a) 各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できます。 `showShape`の最初の場合を考えてみましょう。 -もし `Shape`が `Circle`構築子に適合した場合、2つの変数パターン `c`と -`r`を使って`Circle`の引数(中心と半径)がスコープに導入されます。その他の場合も同様です。 +もし `Shape`が `Circle`構築子に照合した場合、2つの変数パターン `c`と +`r`を使って`Circle`の引数(中心と半径)がスコープに導入されます。 +その他の場合も同様です。 ## 演習 1. (簡単)`Circle`(型は`Shape`)を構築する関数`circleAtOrigin`を書いてください。 中心は原点にあり、半径は`10.0`です。 -1. (普通)`Shape`を原点を中心として`2.0`倍に拡大する関数`doubleScaleAndCenter`を書いてみましょう。 +1. (普通)原点を中心として`Shape`の大きさを`2.0`倍に拡大する関数`doubleScaleAndCenter`を書いてみましょう。 1. (普通)`Shape`からテキストを抽出する関数`shapeText`を書いてください。 この関数は`Maybe String`を返しますが、もし入力が`Text`を使用して構築されたのでなければ、返り値には`Nothing`構築子を使ってください。 @@ -545,14 +570,19 @@ a`の*単一*の値を期待します)。 newtype CouldError err a = CouldError (Either err a) ``` -また、newtypeの構築子はよくnewtype自身と同じ名前を持つことがあります。ただこれは必須ではありません。例えば別個の名前であっても妥当です。 +また、newtypeの構築子はよくnewtype自身と同じ名前を持つことがあります。 +ただこれは必須ではありません。 +例えば別個の名前であっても正しいものです。 ```haskell {{#include ../exercises/chapter5/src/ChapterExamples.purs:Coulomb}} ``` -この場合`Coulomb`は*型構築子*(引数はゼロ)で`MakeCoulomb`は _データ構築子_ -です。これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名前に一意性があります。これは全てのADTについて言えることです。なお、型構築子とデータ構築子は異なる名前を持つことができますが、実際には同じ名前を共有するのが普通です。前述の`Amp`と`Volt`の場合がこれです。 +この場合`Coulomb`は(引数ゼロの)*型構築子*で、`MakeCoulomb`は*データ構築子*です。 +これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名前には一意性があります。 +これは全てのADTについて言えることです。 +なお、型構築子とデータ構築子には異なる名前を付けられますが、実際には同じ名前を共有するのが普通です。 +前述の`Amp`と`Volt`の場合がこれです。 newtypeの別の応用は、実行時表現を変えることなく、既存の型に異なる _挙動_ を加えることです。その利用例については次章で _型クラス_ をお話しするときに押さえます。 @@ -571,7 +601,8 @@ calculateWattage :: Amp -> Volt -> Watt これまで定義してきたデータ型を使って、ベクターグラフィックスを扱う簡単なライブラリを作成していきましょう。 -ただの `Shape`の配列であるような、 `Picture`という型同義語を定義しておきます。 +`Picture`という型同義語を定義しておきます。 +これはただの`Shape`の配列です。 ```haskell {{#include ../exercises/chapter5/src/Data/Picture.purs:Picture}} @@ -608,7 +639,7 @@ $ spago repl {{#include ../exercises/chapter5/src/Data/Picture.purs:Bounds}} ``` -`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累積するため、`bounds`には `Data.Foldable`の +`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累算するため、`bounds`には `Data.Foldable`の `foldl`関数を使用しています。 ```haskell @@ -618,9 +649,10 @@ $ spago repl 基底の場合では、空の `Picture`の最小外接矩形を求める必要がありますが、`emptyBounds`で定義される空の外接矩形がその条件を満たしています。 -累積関数 `combine`は `where`ブロックで定義されています。`combine`は -`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`を引数にとり、ユーザ定義の演算子 -`union`を使って2つの外接矩形の和を計算しています。`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。 +累算関数`combine`は`where`ブロックで定義されています。 +`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の +`Shape`を引数に取り、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。 +`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。 ## 演習 @@ -636,8 +668,10 @@ $ spago repl この章では、関数型プログラミングから基本的ながら強力なテクニックであるパターン照合を扱いました。複雑なデータ構造の一部分と照合するために、簡単なパターンの使い方だけではなく、配列パターンやレコードパターンを使った深さのあるデータ構造の一部分との照合方法を見てきました。 -また、この章ではパターン照合に密接に関連する代数的データ型を紹介しました。代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上でモジュール性のある方法がもたらされることを見てきました。 +また、この章ではパターン照合に密接に関連する代数的データ型も紹介しました。 +代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上で、モジュール性のある方法が齎されるのでした。 -最後に強力な抽象化である _行多相_ を扱いました。これにより多くの既存のJavaScript関数に型を与えられます。 +最後に*行多相*を扱いました。 +これは強力な抽象化をする型であり、これにより多くの既存のJavaScript関数に型を与えられます。 本書では今後も代数的データ型とパターン照合をいろんなところで使用するので、今のうちにこれらに習熟しておくと後で実を結ぶことでしょう。これ以外にも独自の代数的データ型を作成し、パターン照合を使用してそれらの型を使う関数を書いてみてください。 diff --git a/text-ja/chapter6.md b/text-ja/chapter6.md index e2c79526..9dbe5b0c 100644 --- a/text-ja/chapter6.md +++ b/text-ja/chapter6.md @@ -2,9 +2,11 @@ ## この章の目標 -この章では、PureScriptの型システムによって可能になる強力な抽象化の手法である、型クラスを導入します。 +この章では、PureScriptの型システムにより可能になっている強力な抽象化の形式を導入します。 +そう、型クラスです。 -この章ではデータ構造をハッシュ化するためのライブラリを題材に説明していきます。データ自身の構造について直接考えることなく複雑な構造のデータのハッシュ値を求める上で、型クラスの仕組みがどのようにして働くのかを見ていきます。 +データ構造をハッシュ化するためのライブラリを本章の動機付けの例とします。 +データ自体の構造について直接考えることなく複雑な構造のデータのハッシュ値を求める上で、型クラスの仕組みがどのように働くかを見ていきます。 また、PureScriptのPreludeや標準ライブラリに含まれる、標準的な型クラスも見ていきます。PureScriptのコードは概念を簡潔に表現するために型クラスの強力さに大きく依存しているので、これらのクラスに慣れておくと役に立つでしょう。 @@ -17,7 +19,7 @@ このプロジェクトには以下の依存関係があります。 -- `maybe`: オプショナルな値を表す `Maybe`データ型が定義されています。 +- `maybe`: 省略可能な値を表す `Maybe`データ型が定義されています。 - `tuples`: 値の組を表す `Tuple`データ型が定義されています。 - `either`: 非交和を表す `Either`データ型が定義されています。 - `strings`: 文字列を操作する関数が定義されています。 @@ -37,7 +39,7 @@ class Show a where show :: a -> String ``` -このコードでは、型変数 `a`でパラメータ化された、`Show`という新しい _型クラス_ (type class) を宣言しています。 +このコードでは、型変数`a`を引数に取る`Show`という新しい*型クラス*を宣言しています。 型クラス _インスタンス_ には、型クラスで定義された関数の、その型に特殊化された実装が含まれています。 @@ -50,8 +52,8 @@ instance Show Boolean where ``` このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。 -PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインスタンスに名前をつけます。このとき、 -_`Boolean`型は `Show`型クラスに属している_ といいます。 +PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインスタンスに名前を付けられます。 +このとき、`Boolean`型は*`Show`型クラスに属している*といいます。 PSCiで、いろいろな型の値を`Show`型クラスを使って表示してみましょう。 @@ -68,7 +70,7 @@ PSCiで、いろいろな型の値を`Show`型クラスを使って表示して "\"Hello World\"" ``` -この例ではさまざまなプリミティブ型の値を `show`しましたが、もっと複雑な型を持つ値も`show`できます。 +この例では様々な原始型の値を `show`しましたが、もっと複雑な型を持つ値も`show`できます。 ```text > import Data.Tuple @@ -82,7 +84,10 @@ PSCiで、いろいろな型の値を`Show`型クラスを使って表示して "(Just \"testing\")" ``` -`show`の出力は、REPLに(あるいは`.purs`ファイルに)もう一度貼り付ければ、表示されたものを再作成できるような文字列であるべきです。以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出して、引用符なしに文字列を表示するものです。`unit`の表示は無視してください。第8章で`Effect`を調べるときに押さえます。`Effect`を持つものには`log`などがあります。 +`show`の出力は、REPLに(あるいは`.purs`ファイルに)貼り戻せば、表示されたものを再作成できるような文字列であるべきです。 +以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出すものであり、引用符なしに文字列が表示されます。 +`unit`の表示は無視してください。 +第8章で`log`のような`Effect`を調べるときに押さえます。 ```text > import Effect.Console @@ -96,7 +101,7 @@ unit unit ``` -型 `Data.Either`の値を表示しようとすると、興味深いエラーメッセージが表示されます。 +型 `Data.Either`の値を表示しようとすると、興味深いエラー文言が表示されます。 ```text > import Data.Either @@ -110,10 +115,10 @@ has type variables which are not mentioned in the body of the type. Consider add ``` ここでの問題は `show`しようとしている型に対する -`Show`インスタンスが存在しないということではなく、PSCiがこの型を推論できなかったということです。このエラーメッセージで _未知の型_ -`a`と表示されているのがそれです。 +`Show`インスタンスが存在しないということではなく、PSCiがこの型を推論できなかったということです。 +これは推論された型で*未知の型*`a`とされていることが示しています。 -`::`演算子を使って式に対して型注釈を加えると、PSCiが正しい型クラスインスタンスを選ぶことができるようになります。 +`::`演算子を使って式に註釈を付けてPSCiが正しい型クラスインスタンスを選べるようにできます。 ```text > show (Left 10 :: Either Int String) @@ -122,7 +127,7 @@ has type variables which are not mentioned in the body of the type. Consider add `Show`インスタンスを全く持っていない型もあります。 関数の型 `->`がその一例です。 -`Int`から `Int`への関数を `show`しようとすると、型検証器によってその旨のエラーメッセージが表示されます。 +`Int`から `Int`への関数を `show`しようとすると、型検証器によってその旨のエラー文言が表示されます。 ```text > import Prelude @@ -158,15 +163,17 @@ No type class instance was found for ### Eq -`Eq`型クラスは、2つの値が等しいかどうかを調べる`eq`関数を定義しています。 -等値演算子 (`==`) は`eq`の別名にすぎません。 +`Eq`型クラスは`eq`関数を定義しています。 +この関数は2つの値について等値性を調べます。 +実は`==`演算子は`eq`の別名です。 ```haskell class Eq a where eq :: a -> a -> Boolean ``` -なお、異なる型の2つの値を比較しても意味がありませんから、等しいにせよ等しくないにせよ2つの引数は同じ型を持つ必要があります。 +何れにせよ、2つの引数は同じ型を持つ必要があります。 +異なる型の2つの値を等値性に関して比較しても意味がありません。 PSCiで `Eq`型クラスを試してみましょう。 @@ -180,7 +187,9 @@ true ### Ord -`Ord`型クラスは順序付け可能な型に対して2つの値を比較する `compare`関数を定義します。比較演算子 `<`、 `>`と、その仲間の厳密な大小比較ではない`<=`、 `>=`も、`compare`を使って定義されます。 +`Ord`型クラスは`compare`関数を定義します。 +この関数は2つの値を比較するのに使えるもので、その値の型は順序付けに対応したものです。 +比較演算子`<`、`>`と厳密な大小比較ではない`<=`、`>=`は`compare`を用いて定義されます。 *補足*:以下の例ではクラスシグネチャに`<=`が含まれています。 この文脈での`<=`の使われ方はEqがOrdの上位クラスであり、比較演算子としての`<=`の用途を表す意図はありません。 @@ -193,11 +202,12 @@ class Eq a <= Ord a where compare :: a -> a -> Ordering ``` -`compare`関数は2つの値を比較して `Ordering`の3つの値のうち何れかを返します。 +`compare`関数は2つの値を比較して`Ordering`を返します。 +これには3つ選択肢があります。 -- `LT`- 最初の引数が2番目の値より小さいとき -- `EQ`- 最初の引数が2番目の値と等しい(または比較できない)とき -- `GT`- 最初の引数が2番目の値より大きいとき +- `LT`- 最初の引数が2番目の値より小さいとき。 +- `EQ`- 最初の引数が2番目の値と等しいとき。 +- `GT`- 最初の引数が2番目の値より大きいとき。 ここでも`compare`関数についてPSCiで試してみましょう。 @@ -211,19 +221,19 @@ LT ### Field -`Field`型クラスは加算、減算、乗算、除算などの数値演算子が使える型を示します。必要に応じて再利用できるように、これらの演算子を抽象化するわけです。 +`Field`型クラスは加算、減算、乗算、除算などの数値演算子に対応した型を示します。 +これらの演算子を抽象化して提供されているので、適切な場合に再利用できるのです。 -*補足*:型クラス `Eq`や `Ord`のクラスとちょうど同じように、`Field`型のクラスはPureScriptコンパイラで特別に扱われ、`1 + -2 * 3`のような単純な式は単純なJavaScriptへと変換されます。 -型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。 +> *補足*:型クラス`Eq`ないし`Ord`とちょうど同じように、`Field`型クラスはPureScriptコンパイラで特別に扱われ、`1 + 2 * 3`のような単純な式は単純なJavaScriptへと変換されます。 +> 型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。 ```haskell class EuclideanRing a <= Field a ``` -`Field`型クラスは、幾つかのより抽象的な*上位クラス* (Super Class) が組み合わさってできています。 -これは、その型は`Field`型クラスの操作の全てを提供しているわけではないが、その一部を提供する、というように抽象的に説明できます。 -例えば、自然数の型は加算及び乗算については閉じていますが、減算については閉じていません。 +`Field`型クラスは、幾つかのより抽象的な*上位クラス*が組み合わさってできています。 +このため、`Field`の操作の全てを提供しているわけではないが、その一部を提供する型について抽象的に説明できます。 +例えば、自然数の型は加算及び乗算については閉じていますが、減算については必ずしも閉じていません。 そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタンスですが、`Ring`や`Field`のインスタンスではありません。 上位クラスについては、この章の後半で詳しく説明します。 @@ -239,8 +249,8 @@ class Semigroup a where append :: a -> a -> a ``` -文字列は普通の文字列連結について半群をなし、同様に配列も半群をなします。その他の標準的なインスタンスの幾つかは、 -`prelude`パッケージで提供されています。 +文字列は普通の文字列連結について半群をなし、配列も同様です。 +その他の標準的なインスタンスは`prelude`パッケージで提供されています。 以前に見た `<>`連結演算子は、 `append`の別名として提供されています。 @@ -253,9 +263,9 @@ class Semigroup m <= Monoid m where ここでも文字列や配列はモノイドの簡単な例になっています。 -`Monoid`型クラスインスタンスでは、「空」の値から始めて新たな値を合成していき、その型で*累積*した結果を返すにはどうするかを記述する型クラスです。 -例えば、畳み込みを使って幾つかのモノイドの値の配列を連結する関数を書くことができます。 -PSCiで試すと次のようになります。 +ある型にとっての`Monoid`型クラスインスタンスとは、「空」の値から始めて新たな結果に組み合わせ、その型を持つ結果を*累算*する方法を記述するものです。 +例えば、畳み込みを使って何らかのモノイドの値の配列を連結する関数を書けます。 +PSCiで以下の通りです。 ```haskell > import Prelude @@ -287,14 +297,14 @@ class Foldable f where foldMap :: forall a m. Monoid m => (a -> m) -> f a -> m ``` -この定義は `f`を配列の型構築子として特殊化して考えてみるとわかりやすくなります。 -この場合、全ての `a`について `f a`を `Array a`に置き換える事ができますが、`foldl`と -`foldr`の型が、最初に見た配列に対する畳み込みの型になるとわかります。 +`f`を配列の型構築子として特殊化すると分かりやすいです。 +この場合、任意の`a`について`f a`を`Array +a`に置き換えられますが、そうすると`foldl`と`foldr`の型が、最初に配列に対する畳み込みで見た型になると気付きます。 `foldMap`についてはどうでしょうか。 これは `forall a m. Monoid m => (a -> m) -> Array a -> m`になります。 -この型シグネチャは、型 `m`が `Monoid`型クラスのインスタンスであればどんな型でも返り値の型として選ぶことができると言っています。 -配列の要素をそのモノイドの値へと変換する関数を与えれば、そのモノイドの構造を利用して配列を畳み込み、1つの値にして返すことができます。 +この型シグネチャでは、型`m`が`Monoid`型クラスのインスタンスであれば、返り値の型として任意に選べると書かれています。 +配列の要素をそのモノイドの値へと変える関数を与えられれば、そのモノイドの構造を利用して配列上で累算し、1つの値にして返せます。 それではPSCiで `foldMap`を試してみましょう。 @@ -305,18 +315,20 @@ class Foldable f where "12345" ``` -ここでは繋ぎ合わせるためのモノイドとして文字列を、そして`Int`を文字列として表示する -`show`関数を選びました。そうして数の配列を渡すと、それぞれの数を `show`して1つの文字列へと連結した結果が出力されました。 +ここでは文字列用のモノイドと`show`関数を選んでいます。 +前者は文字列を連結するもので、後者は`Int`を文字列として書き出すものです。 +そうして数の配列を渡すと、それぞれの数を`show`して1つの文字列へと連結した結果を得ました。 -しかし畳み込み可能な型は配列だけではありません。`foldable-traversable`では `Maybe`や `Tuple`のような型の -`Foldable`インスタンスが定義されており、`lists`のような他のライブラリでは、そのライブラリのそれぞれのデータ型に対して -`Foldable`インスタンスが定義されています。`Foldable`は _順序付きコンテナ_ (ordered container) -の概念を見据えたものなのです。 +しかし畳み込み可能な型は配列だけではありません。 +`foldable-traversable`では`Maybe`や`Tuple`のような型にも`Foldable`インスタンスが定義されており、`lists`のような他のライブラリでは、各々のデータ型に対して`Foldable`インスタンスが定義されています。 +`Foldable`は*順序付きコンテナ*の概念を見据えたものなのです。 ### 関手と型クラス則 -PureScriptで副作用を伴う関数型プログラミングのスタイルを可能にするための`Functor`と `Applicative`、 -`Monad`といった型クラスがPreludeでは定義されています。これらの抽象化については後ほど本書で扱いますが、まずは`map`関数の形で既に見てきた`Functor`型クラスの定義を見てみましょう。 +PureScriptでは、副作用を伴う関数型プログラミングのスタイルを可能にするための型クラスの集まりも定義されています。 +`Functor`や`Applicative`、`Monad`といったものです。 +これらの抽象化については後ほど本書で扱いますが、ここでは`Functor`型クラスの定義を見てみましょう。 +既に`map`関数の形で見たものです。 ```haskell class Functor f where @@ -352,8 +364,8 @@ class Functor f where 最初の法則は _恒等射律_ (identity law) です。これは、恒等関数(引数を変えずに返す関数)をその構造まで持ち上げると、元の構造をそのまま返すという意味です。恒等関数は入力を変更しませんから、これは理にかなっています。 -第二の法則は _合成律_ (composition law) -です。構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。 +第2の法則は*合成律*です。 +構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。 「持ち上げ」の一般的な意味が何であれ、データ構造に対する持ち上げ関数の正しい定義はこれらの法則に従っていなければなりません。 @@ -381,7 +393,9 @@ class Functor f where 2. (簡単)`Eq`インスタンスを`Complex`に導出してください。 *補足*:代わりにこのインスタンスを手作業で書いてもよいですが、しなくていいのになぜすることがありましょう。 -3. (普通)`Semiring`インタンスを`Complex`に定義してください。*補足*:[`Data.Newtype`](https://pursuit.purescript.org/packages/purescript-newtype/docs/Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答をつくることができます。もしそうするのでしたら、`Data.Newtype`から`class +3. (普通)`Semiring`インタンスを`Complex`に定義してください。 + *補足*:[`Data.Newtype`](https://pursuit.purescript.org/packages/purescript-newtype/docs/Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答を作れます。 + もしそうするのでしたら、`Data.Newtype`から`class Newtype`をインポートしたり、`Newtype`インスタンスを`Complex`に導出したりする必要も出てくるでしょう。 4. (簡単)(`newtype`を介して)`Ring`インスタンスを`Complex`に導出してください。 @@ -400,9 +414,9 @@ class Functor f where ## 型クラス制約 -型クラスを使うと、関数の型に制約を加えることができます。 +型クラスを使うと、関数の型に制約を加えられます。 例を示しましょう。 -`Eq`型クラスのインスタンスで定義された等値性を使って、3つの値が等しいかどうかを調べる関数を書きたいとします。 +`Eq`型クラスインスタンスを使って定義された等値性を使って、3つの値が等しいかどうかを調べる関数を書きたいとします。 ```haskell threeAreEqual :: forall a. Eq a => a -> a -> a -> Boolean @@ -443,10 +457,12 @@ PSCiで `Semiring`のような標準の型クラスの何れかを使って、 > import Prelude > :type \x -> x + x -forall a. Semiring a => a -> a +forall (a :: Type). Semiring a => a -> a ``` -ここで、この関数には`Int -> Int`または`Number -> Number`と注釈を付けることが考えられますが、最も一般的な型が`Semiring`で動作するため、PSCiでは`Int`と `Number`の両方で関数を実行させることができます。 +ここで、この関数に`Int -> Int`または`Number -> Number`と註釈を付けることはできます。 +しかし、PSCiでは最も一般的な型が`Semiring`で動作することが示されています。 +こうすると`Int`と`Number`の両方で関数を使えます。 ## インスタンスの依存関係 @@ -460,7 +476,7 @@ instance Show a => Show (Array a) where ... ``` -型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置く必要があります。 +型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置くことになります。 ```haskell instance (Show a, Show b) => Show (Either a b) where @@ -481,7 +497,7 @@ instance (Show a, Show b) => Show (Either a b) where ``` `Eq a`と`Eq (Array a)`のインスタンスを再利用し、型`NonEmpty`に`Eq`インスタンスを書いてください。 - *補足*:代わりに`Eq`インスタンスも導出できます。 + *補足*:代わりに`Eq`インスタンスを導出できます。 1. (普通)`Array`の`Semigroup`インスタンスを再利用して、`NonEmpty`への`Semigroup`インスタンスを書いてください。 @@ -499,7 +515,7 @@ instance (Show a, Show b) => Show (Either a b) where *手掛かり*:配列への`Foldable`インスタンスを再利用してください。 1. (難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持っている)ような型構築子 - `f`が与えられたとき、追加の要素を先頭に含めるような新たなコンテナ型を作ることができます。 + `f`が与えられたとき、追加の要素を先頭に含める新たなコンテナ型を作れます。 ```haskell {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:OneMore}} @@ -522,7 +538,8 @@ instance (Show a, Show b) => Show (Either a b) where ## 多変数型クラス -型クラスは必ずしも1つの型だけを型変数としてとるわけではありません。型変数が1つだけなのが最も一般的ですが、実際には型クラスは*ゼロ個以上の*型変数を持つことができます。 +型クラスが引数として1つの型だけを取れるのかというと、そうではありません。 +その場合がほとんどですが、型クラスは*ゼロ個以上の*型変数を持てます。 それでは2つの型引数を持つ型クラスの例を見てみましょう。 @@ -551,7 +568,8 @@ instance Stream String Char where このモジュールでは2つの型クラスインスタンスが定義されています。 `uncons`がパターン照合で配列の先頭の要素を取り除くような配列のインスタンスと、文字列から最初の文字を取り除くような文字列のインスタンスです。 -任意のストリーム上で動作する関数を記述できます。例えば、ストリームの要素に基づいて `Monoid`に結果を累積する関数は次のようになります。 +任意のストリーム上で動作する関数を記述できます。 +例えば、ストリームの要素に基づいて `Monoid`に結果を累算する関数は次のようになります。 ```haskell import Prelude @@ -568,14 +586,14 @@ PSCiで使って、異なる `Stream`の型や異なる `Monoid`の型につい ## 関数従属性 -多変数型クラスは非常に便利ですが、混乱しやすい型や型推論の問題にも繋がります。 -簡単な例として、上記の `Stream`クラスを使って汎用的な`tail`関数をストリームに書くことを考えてみましょう。 +多変数型クラスは非常に便利ですが、紛らわしい型や型推論の問題にも繋がります。 +単純な例として、上記で与えられた`Stream`クラスを使い、ストリームに対して汎用的な`tail`関数を書くことを考えてみましょう。 ```haskell genericTail xs = map _.tail (uncons xs) ``` -これはやや複雑なエラーメッセージを出力します。 +これはやや複雑なエラー文言を出力します。 ```text The inferred type @@ -603,8 +621,8 @@ has type variables which are not mentioned in the body of the type. Consider add ここでは、コンパイラが `streamString`インスタンスを選択することを期待しています。 結局のところ、 `String`は `Char`のストリームであり、他の型のストリームであってはなりません。 -コンパイラは自動的にそう推論できず、`streamString`インスタンスを割り当てることができません。 -しかし、型クラス定義に手掛かりを追加すると、コンパイラを助けることができます。 +コンパイラは自動的にそう推論できず、`streamString`インスタンスに目が向きません。 +しかし、型クラス定義に手掛かりを追加すると、コンパイラを補助できます。 ```haskell class Stream stream element | stream -> element where @@ -617,20 +635,23 @@ class Stream stream element | stream -> element where ```text > :type genericTail -forall stream element. Stream stream element => stream -> Maybe stream +forall (stream :: Type) (element :: Type). Stream stream element => stream -> Maybe stream > genericTail "testing" (Just "esting") ``` -多種の型のクラスを使用して何らかのAPIを設計する場合、関数従属性は非常に有用です。 +多変数の型クラスを使用して何らかのAPIを設計する場合、関数従属性が便利なことがあります。 ## 型変数のない型クラス ゼロ個の型変数を持つ型クラスさえも定義できます。 -これらは関数に対するコンパイル時のアサーションに対応しており、型システム内のコードの大域的な性質を把握できます。 +これらは関数に対するコンパイル時の表明に対応しており、型システム内においてそのコードの大域的な性質を把握できます。 -重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあります。`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。なので配列が空のときに失敗する可能性があります。 +重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあります。 +`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。 +この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。 +そのため配列が空のときに失敗する可能性があります。 ```haskell head :: forall a. Partial => Array a -> a @@ -683,34 +704,34 @@ unsafePartial :: forall a. (Partial => a) -> a そしてクラス定義で逆向きの太い矢印 (`<=`) を使って上位クラス関係を示します。 [既に上位クラスの関係の例を目にしました](#ord)。 -`Eq`クラスは `Ord`の上位クラスですし、`Semigroup`クラスは`Monoid`の上位クラスです。 +`Eq`クラスは`Ord`の上位クラスですし、`Semigroup`クラスは`Monoid`の上位クラスです。 `Ord`クラスの全ての型クラスインスタンスについて、その同じ型に対応する `Eq`インスタンスが存在しなければなりません。 これは理に適っています。 -`compare`関数が2つの値の大小を付けられないと報告した時は、それらが実は同値であるかどうかを判定するために -`Eq`クラスを使いたいことが多いでしょうから。 +多くの場合、`compare`関数が2つの値の大小を付けられないと報告した時は、同値であるかを判定するために`Eq`クラスを使うことでしょう。 -一般に、下位クラスの法則が上位クラスのメンバに言及しているとき、上位クラス関係を定義するのは筋が通っています。 -例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インスタンスの下で同値であるなら、`compare`関数は -`EQ`を返すはずだと見做すのは理に適っています。 -言い換えれば、`a == b`が真であるのはちょうど`compare a b`が`EQ`に評価されるときなのです。 -法則のレベルでのこの関係は`Eq`と`Ord`の間の上位クラス関係の正当性を示します。 +一般に、下位クラスの法則が上位クラスの構成要素に言及しているとき、上位クラス関係を定義するのは筋が通っています。 +例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インスタンスの下で同値であるなら、`compare`関数は`EQ`を返すはずだと推定するのは理に適っています。 +言い換えれば、`a == b`が真であるのは`compare a b`が厳密に`EQ`に評価されるときなのです。 +法則のレベルでのこの関係は、`Eq`と`Ord`の間の上位クラス関係の正当性を示します。 -上位クラス関係を定義する別の理由となるのは、この2つのクラスの間に明らかに "is-a" の関係があることです。 -下位クラスの全てのメンバは、上位クラスのメンバでもあるということです。 +上位クラス関係を定義する別の理由となるのは、この2つのクラスの間に明白な "is-a" の関係があることです。 +下位クラスの全ての構成要素は、上位クラスの構成要素でもあるということです。 ## 演習 -1. (普通)部分関数`unsafeMaximum :: Partial => Array Int -> - Int`を定義してください。この関数は空でない整数の配列の最大値を求めます。`unsafePartial`を使ってPSCiで関数をテストしてください。*手掛かり*:`Data.Foldable`の - `maximum`関数を使います。 +1. (普通)部分関数`unsafeMaximum :: Partial => Array Int -> Int`を定義してください。 + この関数は空でない整数の配列の最大値を求めます。 + `unsafePartial`を使ってPSCiで関数を試してください。 + *手掛かり*:`Data.Foldable`の`maximum`関数を使います。 -1. (普通)次の `Action`クラスは、ある型の別の型での動作 (action) を定義する、多変数型クラスです。 +1. (普通)次の `Action`クラスは、ある型の別の型での動作を定義する、多変数型クラスです。 ```haskell {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Action}} ``` - *動作*はモノイドな値を使って他の型の値を変更する方法を決めるやり方を記述する関数です。`Action`型クラスには2つの法則があります。 + *動作*とは、他の型の値を変更する方法を決めるために使われるモノイドな値を記述する関数です。 + `Action`型クラスには2つの法則があります。 - `act mempty a = a` - `act (m1 <> m2) a = act m1 (act m2 a)` @@ -738,9 +759,9 @@ unsafePartial :: forall a. (Partial => a) -> a インスタンスが上で挙げた法則を見たさなくてはならないことを思い出してください。 -1. (難しい)実は`Action Multiply Int`のインスタンスを実装するには複数の方法があります。 +1. (難しい)`Action Multiply Int`のインスタンスを実装するには複数の方法があります。 どれだけ思い付きますか。 - PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える必要があります。 + PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える必要があるでしょう。 *補足*:テストでは4つの実装を押さえています。 1. (普通)入力の文字列を何回か繰り返す`Action`インスタンスを書いてください。 @@ -751,7 +772,7 @@ unsafePartial :: forall a. (Partial => a) -> a ``` *手掛かり*:Pursuitでシグネチャが[`String -> Int -> String`](https://pursuit.purescript.org/search?q=String%20-%3E%20Int%20-%3E%20String)の補助関数を検索してください。 - なお`String`は(`Monoid`のような)より汎用的な型として現れます。 + なお、`String`は(`Monoid`のような)より汎用的な型として現れます。 このインスタンスは上に挙げた法則を満たすでしょうか。 @@ -776,16 +797,17 @@ unsafePartial :: forall a. (Partial => a) -> a この最後の節では、章の残りを使ってデータ構造をハッシュ化するライブラリを作ります。 -なお、このライブラリの説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は目的としていません。 +> なお、このライブラリは説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は意図していません。 ハッシュ関数に期待される性質とはどのようなものでしょうか。 - ハッシュ関数は決定的でなくてはなりません。 - つまり、同じ値には同じハッシュ値を対応させなければなりません。 + つまり、同じ値は同じハッシュコードに写さなければなりません。 - ハッシュ関数はいろいろなハッシュ値の集合で結果が一様に分布しなければなりません。 -最初の性質はまさに型クラスの法則のように見える一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型システムによって確実に強制できるようなものではなさそうです。 -しかし、これは型クラスについて次のような直感的理解を与えるはずです。 +最初の性質はちゃんとした型クラスの法則のように見えます。 +その一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型システムによって確実に強制できるようなものではなさそうです。 +しかし、これは型クラスから次のような直感が得られるでしょう。 ```haskell {{#include ../exercises/chapter6/src/Data/Hashable.purs:Hashable}} @@ -803,8 +825,8 @@ unsafePartial :: forall a. (Partial => a) -> a `combineHashes`関数は2つのハッシュ値を混ぜて結果を0-65535の間に分布します。 -それでは、入力の種類を制限する `Hashable`制約を使う関数を書いてみましょう。 -ハッシュ関数を必要とするよくある目的としては、2つの値が同じハッシュ値にハッシュ化されるかどうかを決定することです。 +それでは、`Hashable`制約を使って入力の種類を制限する関数を書いてみましょう。 +ハッシュ関数を必要とするよくある目的としては、2つの値が同じハッシュコードにハッシュ化されるかどうかを判定することです。 `hashEqual`関係はそのような機能を提供します。 ```haskell @@ -817,8 +839,8 @@ unsafePartial :: forall a. (Partial => a) -> a 原始型の `Hashable`インスタンスを幾つか書いてみましょう。 まずは整数のインスタンスです。 -`HashCode`は実際には単なる梱包された整数なので、これは簡単です。 -`hashCode`補助関数を使うことができます。 +`HashCode`は実際には単なる梱包された整数なので、単純です。 +`hashCode`補助関数を使えます。 ```haskell {{#include ../exercises/chapter6/src/Data/Hashable.purs:hashInt}} @@ -851,17 +873,17 @@ unsafePartial :: forall a. (Partial => a) -> a ``` これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証明するにはどうしたらいいでしょうか。 -同じ値が等しいハッシュ値を持っていることを確認する必要があります。 -`Int`、 `Char`、 `String`、 -`Boolean`の場合は、`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しないので簡単です。 +同じ値が等しいハッシュコードを持っていることを確認する必要があります。 +`Int`、`Char`、`String`、`Boolean`のような場合は単純です。 +`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しないからです。 もっと面白い型についてはどうでしょうか。 -この場合、配列の長さに関する帰納を使うと、型クラスの法則を証明できます。 +`Array`インスタンスの型クラスの法則を証明するにあたっては、配列の長さに関する帰納を使えます。 長さゼロの唯一の配列は `[]`です。 配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じで配列の残りの部分が等しいとき、またその時に限り等しくなります。 この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし `Hashable -a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値をもつことがわかります。 -したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型クラス法則を満たしています。 +a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を持つことがわかります。 +したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型クラス法則に従います。 この章のソースコードには、 `Maybe`と `Tuple`型のインスタンスなど、他にも `Hashable`インスタンスの例が含まれています。 @@ -869,7 +891,8 @@ a`インスタンスがこの法則を満たすなら、先頭の要素も同じ 1. (簡単)PSCiを使って、定義した各インスタンスのハッシュ関数をテストしてください。 *補足*:この演習には単体試験がありません。 - 1. (普通)ハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうかを調べる関数`arrayHasDuplicates`を書いてください。 + 1. (普通)関数`arrayHasDuplicates`を書いてください。 + この関数はハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうかを調べます。 まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対が見付かったら`==`で値の同値性を確認してください。 *手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるでしょう。 1. (普通)型クラスの法則を満たす、次のnewtypeの `Hashable`インスタンスを書いてください。 @@ -888,9 +911,12 @@ a`インスタンスがこの法則を満たすなら、先頭の要素も同じ ## まとめ -この章では、型に基づく抽象化で、コードの再利用のための強力な形式化を可能にする _型クラス_ -を導入しました。PureScriptの標準ライブラリから標準の型クラスを幾つか見てきました。また、ハッシュ値を計算する型クラスに基づく独自のライブラリを定義しました。 +この章では*型クラス*を導入しました。 +型クラスは型に基づく抽象化で、コードの再利用のために強力な形式化ができます。 +PureScriptの標準ライブラリから標準の型クラスを幾つか見てきました。 +また、ハッシュ値を計算するための型クラスに基づく独自のライブラリを定義しました。 -この章では型クラス法則の考え方も導入しましたが、これは抽象化に型クラスを使うコードについての性質を証明する手法でした。 -型クラス法則は*等式推論*と呼ばれる大きな分野の一部であり、プログラミング言語の性質と型システムがプログラムを論理的に推論するために使われています。 +この章では型クラス法則も導入しましたが、これは抽象化に型クラスを使うコードについての性質を証明する手法でした。 +型クラス法則は*等式推論*と呼ばれるより大きな分野の一部です。 +そちらではプログラミング言語の性質と型システムがプログラムを論理的に追究するために使われています。 これは重要な考え方で、本書では今後あらゆる箇所で立ち返る話題となるでしょう。 diff --git a/text-ja/chapter7.md b/text-ja/chapter7.md index 3f8adef9..6aa28689 100644 --- a/text-ja/chapter7.md +++ b/text-ja/chapter7.md @@ -2,14 +2,18 @@ ## この章の目標 -この章では、`Applicative`型クラスによって表現される _アプリカティブ関手_ (applicative functor) -という重要な抽象化と新たに出会うことになります。名前が難しそうに思えても心配しないでください。フォームデータの検証という実用的な例を使ってこの概念の動機付けをします。アプリカティブ関手を使うと、通常であれば大量の決まり文句を伴うようなコードを、簡潔で宣言的な記述へと変えることができるようになります。 +この章では重要な抽象化と新たに出会うことになります。 +`Applicative`型クラスによって表現される*アプリカティブ関手*です。 +名前が難しそうに思えても心配しないでください。 +フォームデータの検証という実用的な例を使ってこの概念の動機付けをします。 +アプリカティブ関手の技法があることにより、通常であれば大量の決まり文句の検証を伴うようなコードを、簡潔で宣言的なフォームの記述へと変えられます。 また、*巡回可能関手*を表現する`Traversable`という別の型クラスにも出会います。現実の問題への解決策からこの概念が自然に生じることがわかるでしょう。 -この章では第3章に引き続き住所録を例として扱います。 +この章のコードでは第3章に引き続き住所録を例とします。 今回は住所録のデータ型を拡張し、これらの型の値を検証する関数を書きます。 -これらの関数は、例えばデータ入力フォームの一部で、使用者へエラーを表示するwebユーザインターフェースで使われると考えてください。 +これらの関数は、例えばwebユーザインターフェースで使えることが分かります。 +データ入力フォームの一部として、使用者へエラーを表示するのに使われます。 ## プロジェクトの準備 @@ -21,13 +25,14 @@ - `control` - `Applicative`のような、型クラスを使用して制御フローを抽象化する関数が定義されています。 - `validation` - この章の主題である _アプリカティブによる検証_ のための関手が定義されています。 -`Data.AddressBook`モジュールには、このプロジェクトのデータ型とそれらの型に対する`Show`インスタンスが定義されており、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれています。 +`Data.AddressBook`モジュールにはこのプロジェクトのデータ型とそれらの型に対する`Show`インスタンスが定義されています。 +また、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれています。 ## 関数適用の一般化 _アプリカティブ関手_ の概念を理解するために、以前扱った型構築子`Maybe`について考えてみましょう。 -このモジュールのソースコードでは、次のような型を持つ`address`関数が定義されています。 +このモジュールのソースコードでは、次の型を持つ`address`関数が定義されています。 ```haskell {{#include ../exercises/chapter7/src/Data/AddressBook.purs:address_anno}} @@ -62,7 +67,8 @@ with type String ``` -`address`は`Maybe String`型ではなく文字列型の引数を取るので、もちろんこれは期待通り型エラーになります。 +勿論、これは期待通り型エラーになります。 +`address`は`Maybe String`型の値ではなく、文字列を引数として取るためです。 しかし、もし`address`関数を「持ち上げる」ことができれば、`Maybe`型で示される省略可能な値を扱うことができるはずだという予想は理に適っています。実際それは可能で、`Control.Apply`で提供されている関数`lift3`が、まさに求めているものです。 @@ -93,7 +99,7 @@ Just ({ street: "123 Fake St.", city: "Faketown", state: "CA" }) ```text > :type lift3 -forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d +forall (a :: Type) (b :: Type) (c :: Type) (d :: Type) (f :: Type -> Type). Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d ``` 上の`Maybe`の例では型構築子`f`は`Maybe`ですから、`lift3`は次のように特殊化されます。 @@ -102,9 +108,9 @@ forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d forall a b c d. (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> Maybe d ``` -この型が言っているのは、3引数の任意の関数を取り、その関数を引数と返り値が`Maybe`で包まれた新しい関数へと持ち上げる、ということです。 +この型で書かれているのは、3引数の任意の関数を取り、その関数を引数と返り値が`Maybe`で包まれた新しい関数へと持ち上げられる、ということです。 -もちろんどんな型構築子`f`についても持ち上げができるわけではないのですが、それでは`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。 +勿論、どんな型構築子`f`についても持ち上げができるわけではないのですが、それでは`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。 さて、先ほどの型の特殊化では、`f`に対する型クラス制約から`Apply`型クラスを取り除いていました。 `Apply`はPreludeで次のように定義されています。 @@ -118,7 +124,8 @@ class Functor f <= Apply f where `Apply`型クラスは`Functor`の下位クラスであり、追加の関数`apply`を定義しています。`<$>`が`map`の別名として定義されているように、`Prelude`モジュールでは`<*>`を`apply`の別名として定義しています。これから見ていきますが、これら2つの演算子はよく一緒に使われます。 -なおこの[`apply`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Apply#v:apply)は`Data.Function`の[`apply`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Function#v:apply)(中置で`$`)とは異なります。幸いにも後者はほぼ常に中置記法として使われるので、名前の衝突については心配ご無用です。 +なお、この[`apply`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Apply#v:apply)は`Data.Function`の[`apply`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Function#v:apply)(中置で`$`)とは異なります。 +幸いにも後者はほぼ常に中置記法として使われるので、名前の衝突については心配ご無用です。 `apply`の型は`map`の型と実によく似ています。 `map`と`apply`の違いは、`map`がただの関数を引数に取るのに対し、`apply`の最初の引数は型構築子`f`で包まれているという点です。 @@ -134,7 +141,7 @@ instance Apply Maybe where apply _ _ = Nothing ``` -この型クラスのインスタンスで書かれているのは、任意のオプショナルな値にオプショナルな関数を適用でき、その両方が定義されている時に限り結果も定義される、ということです。 +この型クラスのインスタンスで書かれているのは、任意の省略可能な値に省略可能な関数を適用でき、その両方が定義されている時に限り結果も定義される、ということです。 それでは、`map`と`apply`を一緒に使い、引数が任意個の関数を持ち上げる方法を見ていきましょう。 @@ -157,7 +164,7 @@ lift3 :: forall a b c d f lift3 f x y z = f <$> x <*> y <*> z ``` -この式の型がちゃんと整合しているかの確認は、読者への演習として残しておきます。 +> この式に関する型の検証は、読者への演習として残しておきます。 例として、`<$>`と`<*>`をそのまま使うと、`Maybe`上に`address`関数を持ち上げることができます。 @@ -171,9 +178,9 @@ Nothing 同様にして、引数が異なる他のいろいろな関数を`Maybe`上に持ち上げてみてください。 -この代わりにお馴染の _do記法_ に似た見た目の _アプリカティブdo記法_ が同じ目的で使えます。以下では`lift3`に -_アプリカティブdo記法_ -を使っています。なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で`in`が使われています。 +この代わりに、お馴染の*do記法*に似た見た目の*アプリカティブdo記法*が同じ目的で使えます。 +以下では`lift3`に*アプリカティブdo記法*を使っています。 +なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で`in`が使われています。 ```haskell lift3 :: forall a b c d f @@ -209,20 +216,20 @@ instance Applicative Maybe where pure x = Just x ``` -アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、`pure`は引数のない関数の持ち上げだというように考えることができます。 +アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、`pure`は引数のない関数の持ち上げだというように考えられます。 ## アプリカティブに対する直感的理解 PureScriptの関数は純粋であり、副作用は持っていません。Applicative関手は、関手`f`によって表現されるある種の副作用を提供するような、より大きな「プログラミング言語」を扱えるようにします。 -例えば関手`Maybe`はオプショナルな値の副作用を表現しています。 +例えば関手`Maybe`は欠けている可能性がある値の副作用を表現しています。 その他の例としては、型`err`のエラーの可能性の副作用を表す`Either err`や、大域的な構成を読み取る副作用を表すArrow関手 (arrow functor) `r ->`があります。 ここでは`Maybe`関手についてのみ考えることにします。 もし関手`f`が作用を持つ、より大きなプログラミング言語を表すとすると、`Apply`と`Applicative`インスタンスは小さなプログラミング言語 (PureScript) から新しい大きな言語へと値や関数を持ち上げることを可能にします。 -`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数については上で述べた通り`map`と`apply`を使うことができます。 +`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数については上で述べた通り`map`と`apply`を使えます。 ここで疑問が生まれます。 もしPureScriptの関数と値を新たな言語へ埋め込むのに`Applicative`が使えるなら、どうやって新たな言語は大きくなっているというのでしょうか。 @@ -249,9 +256,9 @@ a`の式を見つけたなら、その式はそのより大きな言語だけに Freeman, Phillip A ``` -この関数は、クエリパラメータとして与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装であるとしましょう。 -使用者が3つの引数全てを与えたことを確かめたいので、引数が存在するかどうかを表す`Maybe`型を使うことになるでしょう。 -`fullName`を`Maybe`の上へ持ち上げると、省略された引数を確認するwebサービスを実装できます。 +この関数が、クエリ引数として与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装を形成しているとしましょう。 +使用者が3つの各引数を与えたことを確かめたいので、引数が存在するかどうかを表す`Maybe`型を使うことになるでしょう。 +`fullName`を`Maybe`の上へ持ち上げると、欠けている引数を検査するwebサービスの実装を作成できます。 ```text > import Data.Maybe @@ -288,11 +295,11 @@ Nothing この持ち上げた関数は、引数の何れかが`Nothing`なら`Nothing`を返すことに注意してください。 -これで、もし引数が不正ならWebサービスからエラー応答を送信できるので、なかなかいい感じです。 -しかし、どのフィールドが間違っていたのかを応答で示せると、もっと良くなるでしょう。 +引数が不正のときにwebサービスからエラー応答を送り返せるのは良いことです。 +しかし、どのフィールドが不正確なのかを応答で示せると、もっと良くなるでしょう。 -`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エラーメッセージを返すことができるようになります。 -まずは`Either String`を使ってオプショナルな入力をエラーを発信できる計算に変換する演算子を書きましょう。 +`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エラー文言を返せるようになります。 +まずは`Either String`を使い、省略可能な入力からエラーを発信できる計算に変換する演算子を書きましょう。 ```text > import Data.Either @@ -304,7 +311,7 @@ Nothing *補足*:`Either err`アプリカティブ関手において、`Left`構築子は失敗を表しており、`Right`構築子は成功を表しています。 -これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラーメッセージを提供できるようになります。 +これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー文言を提供できるようになります。 ```text > :paste @@ -330,7 +337,7 @@ Nothing Maybe String -> Maybe String -> Maybe String -> Either String String ``` -これでこの関数は`Maybe`の3つの省略可能な引数を取り、`String`のエラーメッセージか`String`の結果のどちらかを返します。 +これでこの関数は`Maybe`を使う3つの省略可能な引数を取り、`String`のエラー文言か`String`の結果のどちらかを返します。 いろいろな入力でこの関数を試してみましょう。 @@ -345,8 +352,8 @@ Maybe String -> Maybe String -> Maybe String -> Either String String (Left "Last name was missing") ``` -このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラーメッセージが表示されます。 -しかし、もし複数の入力が省略されているとき、最初のエラーしか見ることができません。 +このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラー文言が表示されます。 +しかし、もし複数の入力が省略されているとき、最初のエラーしか見られません。 ```text > fullNameEither Nothing Nothing Nothing @@ -358,7 +365,7 @@ String`よりも強力なものが必要です。この章の後半で解決策 ## 作用の結合 -抽象的にアプリカティブ関手を扱う例として、アプリカティブ関手`f`によって表現された副作用を一般的に組み合わせる関数を書く方法をこの節では示します。 +抽象的にアプリカティブ関手を扱う例として、この節ではアプリカティブ関手`f`によって表現された副作用を一般的に組み合わせる関数を書く方法を示します。 これはどういう意味でしょうか。 何らかの`a`について型`f a`で包まれた引数のリストがあるとしましょう。 @@ -368,10 +375,10 @@ String`よりも強力なものが必要です。この章の後半で解決策 しかし、まだ`f`によって追跡される副作用が残ります。 つまり、元のリストの中の作用を「結合する」ことにより、型`List (f a)`の何かを型`f (List a)`の何かへと変換できると考えられます。 -任意の固定長リストの長さ`n`について、その引数を要素に持った長さ`n`のリストを構築するような`n`引数の関数が存在します。 +任意の固定長リストの長さ`n`について、`n`引数からその引数を要素に持つ長さ`n`のリストを構築する関数が存在します。 例えばもし`n`が`3`なら、関数は`\x y z -> x : y : z : Nil`です。 -この関数の型は`a -> a -> a -> List a`です。 -`Applicative`インスタンスを使うと、この関数を`f`の上へ持ち上げて関数型`f a -> f a -> f a -> f (List a)`を得ることができます。 +この関数は型`a -> a -> a -> List a`を持ちます。 +`Applicative`インスタンスを使うと、この関数を`f`の上へ持ち上げられ、関数型`f a -> f a -> f a -> f (List a)`が得られます。 しかし、いかなる`n`についてもこれが可能なので、いかなる引数の*リスト*についても同じように持ち上げられることが確かめられます。 したがって、次のような関数を書くことができるはずです。 @@ -414,31 +421,31 @@ combineList (Cons x xs) = Cons <$> x <*> combineList xs Nothing ``` -`Meybe`へ特殊化して考えると、リストの全ての要素が`Just`であるときに限りこの関数は`Just`を返しますし、そうでなければ`Nothing`を返します。 -これはオプショナルな値に対応する、より大きな言語に取り組む上での直感から一貫しています。 -オプショナルな結果を返す計算のリストは、全ての計算が結果を持っているならばそれ自身の結果のみを持つのです。 +`Meybe`へ特殊化すると、リストの全ての要素が`Just`であるときに限りこの関数は`Just`を返しますし、そうでなければ`Nothing`を返します。 +これは省略可能な値に対応する、より大きな言語に取り組む上での直感と一貫しています。 +省略可能な結果を生む計算のリストは、全ての計算が結果を持っているならばそれ自身の結果のみを持つのです。 -しかし、`combineList`関数はどんな`Applicative`に対しても機能します。 -`Either err`を使ってエラーを発信する可能性を持たせたり、`r ->`を使って大域的な状態を読み取る計算を連鎖させるときにも使えるのです。 +ところが`combineList`関数はどんな`Applicative`に対しても機能するのです。 +`Either err`を使ってエラーを発信する可能性を持たせたり、`r ->`を使って大域的な構成を読み取る計算を組み合わせるためにも使えます。 `combineList`関数については、後ほど`Traversable`関手について考えるときに再訪します。 ## 演習 - 1. (普通)数値演算子`+`、`-`、`*`、`/`のオプショナル引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返す版を書いてください。 - これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けます。 + 1. (普通)数値演算子`+`、`-`、`*`、`/`の別のバージョンを書いてください。 + ただし省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返します。 + これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けてください。 *手掛かり*:`lift2`を使ってください。 1. (普通)上の演習を(`Maybe`だけでなく)全ての`Apply`型で動くように拡張してください。 これらの新しい関数には`addApply`、`subApply`、`mulApply`、`divApply`と名前を付けます。 - 1. (難しい)型`combineMaybe : forall a f. (Applicative f) => Maybe (f a) -> f - (Maybe a)` - を持つ関数`combineMaybe`を書いてください。 - この関数は副作用をもつオプショナルな計算をとり、オプショナルな結果をもつ副作用のある計算を返します。 + 1. (難しい)型`forall a f. Applicative f => Maybe (f a) -> f (Maybe + a)`を持つ関数`combineMaybe`を書いてください。 + この関数は副作用を持つ省略可能な計算を取り、省略可能な結果を持つ副作用のある計算を返します。 ## アプリカティブによる検証 -この章のソースコードでは住所録アプリケーションで使うことのできるいろいろなデータ型が定義されています。 -詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされる重要な関数は次のような型を持っています。 +この章のソースコードでは住所録アプリケーションで使うであろう幾つかのデータ型が定義されています。 +詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされる鍵となる関数は次のような型を持ちます。 ```haskell {{#include ../exercises/chapter7/src/Data/AddressBook.purs:address_anno}} @@ -454,8 +461,8 @@ Nothing {{#include ../exercises/chapter7/src/Data/AddressBook.purs:PhoneType}} ``` -これらの関数は住所録の項目を表す`Person`を構築するのに使えます。 -例えば、`Data.AddressBook`には次のような値が定義されています。 +これらの関数は住所録の項目を表す`Person`を構築できます。 +例えば、`Data.AddressBook`では以下の値が定義されています。 ```haskell {{#include ../exercises/chapter7/src/Data/AddressBook.purs:examplePerson}} @@ -500,8 +507,9 @@ String`関手の使い方を見ました。例えば、データ構造の2つの {{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson1Ado}} ``` -最初の2行では`nonEmpty`関数を使って空文字列でないことを検証しています。 -もし入力が空なら`nonEMpty`はエラーを返し(`Left`構築子で示されています)、そうでなければ`Right`構築子を使って値を包んで返します。 +最初の2行では`nonEmpty1`関数を使って空文字列でないことを検証しています。 +もし入力が空なら`nonEmpty1`は`Left`構築子で示されるエラーを返します。 +そうでなければ`Right`構築子で包まれた値を返します。 最後の2行では何の検証も実行せず、単に`address`フィールドと`phones`フィールドを残りの引数として`person`関数へと提供しています。 @@ -512,12 +520,13 @@ String`関手の使い方を見ました。例えば、データ構造の2つの (Left "Field cannot be empty") ``` -`Either String`アプリカティブ関手は遭遇した最初のエラーだけを返します。 -でもこの入力では、名前の不足と姓の不足という2つのエラーがわかるようにしたくなるでしょう。 +`Either String`アプリカティブ関手は最初に遭遇したエラーだけを返します。 +仮にこの入力だったとすると、2つのエラーが分かったほうが良いでしょう。 +1つは名前の不足で、2つ目は姓の不足です。 `validation`ライブラリでは別のアプリカティブ関手も提供されています。 -これは単に`V`と呼ばれていて、何らかの*半群*でエラーを返す機能があります。 -例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、`String`の配列をエラーとして返すことができます。 +これは`V`という名前で、何らかの*半群*でエラーを返せます。 +例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、`String`の配列をエラーとして返せます。 `Data.Validation`モジュールは`Data.AddressBook`モジュールのデータ構造を検証するために`V (Array String)`アプリカティブ関手を使っています。 @@ -625,7 +634,7 @@ invalid (["Field 'Number' did not match the required format"]) {{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePersonAdo}} ``` -`validatePhoneNumbers`はこれまでに見たことのない新しい関数、`traverse`を使います。 +`validatePhoneNumbers`はこれまでに見たことのない新しい関数である`traverse`を使っています。 `traverse`は`Data.Traversable`モジュールの`Traversable`型クラスで定義されています。 @@ -638,8 +647,9 @@ class (Functor t, Foldable t) <= Traversable t where `Traversable`は _巡回可能関手_ の型クラスを定義します。これらの関数の型は少し難しそうに見えるかもしれませんが、`validatePerson`は良いきっかけとなる例です。 -全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能関手*は、構造を1つの値へと纏める畳み込み操作を提供する型構築子であったことを思い出してください)。 -それに加えて、`Traversable`関手はその構造に依存した副作用の集まりを連結する機能を提供します。 +全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能関手*は畳み込み操作に対応する型構築子であったことを思い出してください。 +畳み込みとは構造を1つの値へと簡約するものでした)。 +それに加えて、巡回可能関手はその構造に依存した副作用の集まりを組み合わせられます。 複雑そうに聞こえるかもしれませんが、配列の場合に特殊化して簡単にした上で考えてみましょう。配列型構築子は`Traversable`であり、つまりは次のような関数が存在するということです。 @@ -659,12 +669,12 @@ Errors`アプリカティブ関手に特殊化して考えてみましょう。 traverse :: forall a b. (a -> V Errors b) -> Array a -> V Errors (Array b) ``` -この型シグネチャは、型`a`についての検証関数`m`があれば、`traverse m`は型`Array -a`の配列についての検証関数であるということを言っています。 -これはまさに、今必要になっている`Person`データ構造体の`phones`フィールドを検証する検証器そのものです。 -それぞれの要素が成功するかどうかを検証する検証関数を作るために、`validatePhoneNumber`を`traverse`へ渡しています。 +この型シグネチャでは、型`a`についての検証関数`m`があれば、`traverse m`は型`Array +a`の配列についての検証関数であると書かれています。 +ところがこれは正に`Person`データ構造体の`phones`フィールドを検証できるようにするのに必要なものです。 +各要素が成功するかを検証する検証関数を作るために、`validatePhoneNumber`を`traverse`へ渡しています。 -一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算し、結果を累積します。 +一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算し、結果を累算します。 `Traversable`のもう1つの関数、`sequence`の型シグネチャには見覚えがあるかもしれません。 @@ -679,7 +689,11 @@ sequence :: forall a m. Applicative m => t (m a) -> m (t a) combineList :: forall f a. Applicative f => List (f a) -> f (List a) ``` -巡回可能関手は、作用のある計算を集めてその作用を結合するという、データ構造走査の考え方を見据えたものです。実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくらい重要です。これらはお互いがお互いを利用して実装できます。これについては興味ある読者への演習として残しておきます。 +巡回可能関手はデータ構造走査の考え方を見据えたものです。 +これにより作用のある計算の集合を集めてその作用を結合します。 +実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくらい重要です。 +これらはお互いがお互いを利用して実装できます。 +これについては興味ある読者への演習として残しておきます。 `Data.List`で与えられているリストの`Traversable`インスタンスは次の通り。 @@ -692,8 +706,10 @@ traverse f (Cons x xs) = Cons <$> f x <*> traverse f xs (実際の定義は後にスタック安全性を向上するために変更されました。その変更についてより詳しくは[こちら](https://github.com/purescript/purescript-lists/pull/87)で読むことができます) -入力が空のリストのときには、単に`pure`を使って空の配列を返すことができます。配列が空でないときは、関数`f`を使うと先頭の要素から型`f -b`の計算を作成できます。また、配列の残りに対して`traverse`を再帰的に呼び出すことができます。最後に、アプリカティブ関手`m`まで`Cons`構築子を持ち上げて、2つの結果を組み合わせます。 +入力が空のリストのときには、`pure`を使って空のリストを返せます。 +リストが空でないときは、関数`f`を使うと先頭の要素から型`f b`の計算を作成できます。 +また、尾鰭に対して`traverse`を再帰的に呼び出せます。 +最後に、アプリカティブ関手`m`まで`Cons`構築子を持ち上げて、2つの結果を組み合わせられます。 巡回可能関手の例はただの配列やリスト以外にもあります。 以前に見た`Maybe`型構築子も`Traversable`のインスタンスを持っています。 @@ -716,11 +732,12 @@ pure ((Just "Testing")) これらの例では、`Nothing`の値の走査は検証なしで`Nothing`の値を返し、`Just x`を走査すると`x`を検証するのに検証関数が使われるということを示しています。 -要は、`traverse`は型`a`についての検証関数をとり、`Maybe -a`についての検証関数、つまり型`a`のオプショナルな値についての検証関数を返すのです。 +要は、`traverse`は型`a`についての検証関数を取り、`Maybe +a`についての検証関数、つまり型`a`の省略可能な値についての検証関数を返すのです。 -他の巡回可能関手には`Array`、また任意の型`a`について`Tuple a`、`Either -a`が含まれます。一般的に、「容器」のようなデータの型構築子は大抵`Traversable`インスタンスを持っています。例として、演習では二分木の型の`Traversable`インスタンスを書くことになります。 +他の巡回可能関手には、任意の型`a`についての`Array a`、`Tuple a`、`Either a`が含まれます。 +一般に、「容器」のようなほとんどのデータ型構築子は`Traversable`インスタンスを持っています。 +一例として、演習には二分木の型の`Traversable`インスタンスを書くことが含まれます。 ## 演習 @@ -734,7 +751,7 @@ a`が含まれます。一般的に、「容器」のようなデータの型構 `Show`の出力には多くの「正しい」書式の選択肢があります。 この演習のテストでは以下の空白スタイルを期待しています。 - これはたまたま一般化されたshowの既定の書式と合致しているため、このインスタンスを手作業で書くつもりのときだけ、このことを念頭に置いておいてください。 + これは一般化されたshowの既定の書式と合致しているため、このインスタンスを手作業で書くつもりのときだけ、このことを念頭に置いておいてください。 ```haskell (Branch (Branch Leaf 8 Leaf) 42 Leaf) @@ -752,7 +769,7 @@ a`が含まれます。一般的に、「容器」のようなデータの型構 1. (普通)木を帰り掛け順に巡回する関数`traversePostOrder`を書いてください。作用は左右根と実行されます。 - 1. (普通)`homeAddress`フィールドがオプショナル(`Maybe`を使用)な新しい版の`Person`型をつくってください。 + 1. (普通)`homeAddress`フィールドが省略可能(`Maybe`を使用)な新しい版の`Person`型をつくってください。 それからこの新しい`Person`を検証する新しい版の`validatePerson`(`validatePersonOptionalAddress`と改名します)を書いてください。 *手掛かり*:`traverse`を使って型`Maybe a`のフィールドを検証してください。 @@ -770,13 +787,13 @@ a`が含まれます。一般的に、「容器」のようなデータの型構 しかし一般には、アプリカティブ関手はこれよりももっと一般的です。 アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しません。 -実際、並列に副作用を実行するためのアプリカティブ関手というものは妥当になりえます。 +実際、並列に副作用を実行するアプリカティブ関手は妥当でしょう。 -例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだとしてもやはり正常に動き、このときどんな順序でそれぞれの検証器を実行しても問題はありません。 +例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだとしてもやはり正常に動き、このときどんな順序で各検証器を実行しても問題はありません。 データ構造に対して並列にこれの実行さえできるのです。 -別の例として、`parallel`パッケージは、*並列計算*に対応する`Parallel`型クラスを与えます。 -`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入力の計算を*並列に*計算できます。 +2つ目の例として、`parallel`パッケージは*並列計算*に対応する`Parallel`型クラスを提供します。 +`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入力の計算の結果を*並列に*計算します。 ```haskell f <$> parallel computation1 @@ -787,19 +804,21 @@ f <$> parallel computation1 この考え方の詳細は、本書の後半で _コールバック地獄_ の問題に対してアプリカティブ関手を応用するときに見ていきます。 -アプリカティブ関手は並列に結合できる副作用を一纏めにする自然な方法です。 +アプリカティブ関手は並列に結合できる副作用を捉える自然な方法です。 ## まとめ この章では新しい考え方を沢山扱いました。 -- 関数適用の概念を副作用の観念を捉えた型構築子へと一般化する、 _アプリカティブ関手_ の概念を導入しました。 -- データ構造の検証という課題にアプリカティブ関手がどのような解決策を与えるか、どうすれば単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変換できるのかを見てきました。 +- *アプリカティブ関手*の概念を導入しました。 + これは、関数適用の概念から副作用の観念を捉えた型構築子へと一般化するものです。 +- データ構造の検証という課題をアプリカティブ関手やその切り替えで解く方法を見てきました。 + 単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変更できました。 - `Traversable`型クラスに出会いました。*巡回可能関手*の考え方を内包するものであり、要素が副作用を持つ値の結合に使うことができる容れ物でした。 アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化です。 本書を通じて何度も見ることになるでしょう。 -今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、これにより検証器が*どうやって*検証するかではなく、*何を*検証すべきなのかを定義できました。 -一般に、アプリカティブ関手は*領域特化言語*を設計する上で便利な道具になります。 +今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、これにより検証器が*どうやって*検証を実施するかではなく、*何を*検証すべきなのかを定義できました。 +一般にアプリカティブ関手が*領域特化言語*を設計する上で便利な道具になることを見ていきます。 次の章では、これに関連する考え方である*モナド*クラスを見て、アドレス帳の例をブラウザで実行させられるように拡張しましょう。 diff --git a/text-ja/chapter8.md b/text-ja/chapter8.md index 6d26638d..98c02bed 100644 --- a/text-ja/chapter8.md +++ b/text-ja/chapter8.md @@ -2,18 +2,19 @@ ## この章の目標 -前章では、オプショナルな型やエラーメッセージ、データの検証など、 _副作用_ -を扱いを抽象化するアプリカティブ関手を導入しました。この章では、より表現力の高い方法で副作用を扱うための別の抽象化、 _モナド_ を導入します。 +前章では、*副作用*を扱うのに使う抽象化であるアプリカティブ関手を導入しました。 +副作用とは省略可能な値、エラー文言、検証などです。 +この章では、副作用を扱うためのより表現力の高い別の抽象化である*モナド*を導入します。 -この章の目的は、なぜモナドが便利な抽象化なのかということと、 _do記法_ との関係を説明することです。 +この章の目的は、なぜモナドが便利な抽象化なのかということと、*do記法*との関係を説明することです。 ## プロジェクトの準備 このプロジェクトでは、以下の依存関係が追加されています。 -- `effect`: - 章の後半の主題である`Effect`モナドを定義しています。この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存関係にありました)、明示的にインストールしなければいけないことは稀です。 -- `react-basic-hooks`: アドレス帳アプリに使うWebフレームワークです。 +- `effect`: 章の後半の主題である`Effect`モナドを定義しています。 + この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存関係にありました)、明示的にインストールしなければいけないことは稀です。 +- `react-basic-hooks`: アドレス帳アプリに使うwebフレームワークです。 ## モナドとdo記法 @@ -25,9 +26,9 @@ do記法は*配列内包表記*を扱うときに初めて導入されました - 最初の投擲で値 `x`を _選択_ します。 - 2回目の投擲で値 `y`を _選択_ します。 -- もし `x`と `y`の和が `n`なら組 `[x, y]`を返し、そうでなければ失敗します。 +- もし`x`と`y`の和が`n`なら組`[x, y]`を返し、そうでなければ失敗します。 -配列内包表記を使うと、この非決定的アルゴリズムを自然に書くことができます。 +配列内包表記を使うと、この非決定的アルゴリズムを自然に書けます。 ```hs import Prelude @@ -50,14 +51,13 @@ PSCiでこの関数の動作を見てみましょう。 [[6,6]] ``` -前の章では、*オプショナルな値*に対応したより大きなプログラミング言語へとPureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養いました。 +前の章では、*省略可能な値*に対応したより大きなプログラミング言語へとPureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養いました。 同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができます。 -一般に、ある型構築子 `m`のモナドは、型 `m a`の値を持つdo記法を使う手段を提供します。 -上の配列内包表記では、全ての行に何らかの型 `a`についての型 `Array a`の計算が含まれていることに注目してください。 -一般に、do記法ブロックの全ての行は、何らかの型 `a`とモナド `m`について、型 `m a`の計算を含んでいます。 -モナド `m`は全ての行で同じでなければなりません(つまり、副作用の種類は固定されます)が、型 -`a`は異なることもあります(言い換えると、個々の計算は異なる型の結果を持つことができます)。 +一般に、ある型構築子`m`のモナドは、型`m a`の値を持つdo記法を使う手段を提供します。 +上の配列内包表記に注意すると、何らかの型`a`について全行に型`Array a`の計算が含まれています。 +一般に、do記法ブロックの全行は、何らかの型`a`とモナド`m`について、型`m a`の計算を含みます。 +モナド`m`は全行で同じでなければなりません(つまり副作用は固定)が、型`a`は異なることもあります(つまり個々の計算は異なる型の結果にできる)。 以下はdo記法の別の例です。 今回は型構築子 `Maybe`に適用されています。 @@ -81,10 +81,9 @@ userCity root = do pure city ``` -`userCity`関数は子の要素である `profile`を探し、 `profile`要素の中にある `address`要素、最後に -`address`要素から `city`要素を探します。 -これらの要素の何れかが欠落している場合は、返り値は `Nothing`になります。 -そうでなければ、返り値は `city`ノードから `Just`を使って構築されています。 +`userCity`関数は子の`profile`要素、`profile`要素の中にある`address`要素、最後に`address`要素の中にある`city`要素を探します。 +これらの要素の何れかが欠落している場合、返り値は`Nothing`になります。 +そうでなければ、返り値は`city`ノードから`Just`を使って構築されます。 最後の行にある`pure`関数は、全ての`Applicative`関手について定義されているのでした。 `Maybe`の`Applicative`関手の`pure`関数は`Just`として定義されており、最後の行を `Just @@ -103,7 +102,7 @@ class (Applicative m, Bind m) <= Monad m ここで鍵となる関数は `Bind`型クラスで定義されている演算子 `bind`で、`Functor`及び `Apply`型クラスにある `<$>`や `<*>`などの演算子と同様に、`Prelude`では `>>=`として `bind`の中置の別名が定義されています。 -`Monad`型クラスは、既に見てきた `Applicative`型クラスの操作で `Bind`を拡張します。 +`Monad`型クラスは、既に見てきた`Applicative`型クラスの操作で`Bind`を拡張します。 `Bind`型クラスの例を幾つか見てみるのがわかりやすいでしょう。 配列についての `Bind`の妥当な定義は次のようになります。 @@ -125,7 +124,8 @@ instance Bind Maybe where この定義は欠落した値がdo記法ブロックを通じて伝播するという直感的理解を裏付けるものです。 -`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。最初に何らかの計算結果からの値の束縛から始まる簡単なdo記法ブロックについて考えてみましょう。 +`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。 +最初に、何らかの計算結果からの値の束縛から始まる、単純なdo記法ブロックについて考えてみましょう。 ```hs do value <- someComputation @@ -157,7 +157,9 @@ userCity root = pure city ``` -do記法を使って表現されたコードは、`>>=`演算子を使って書かれた同じ意味のコードよりしばしば読みやすくなることも特筆すべき点です。一方で、明示的に `>>=`を使って束縛を書くと、しばしば*ポイントフリー*形式でコードが書けるようになります。ただし、読みやすさにはやはり注意がいります。 +do記法を使って表現されたコードは、`>>=`演算子を使う等価なコードより遥かに読みやすくなることがよくあることも特筆すべき点です。 +しかしながら、明示的に`>>=`を使って束縛を書くと、*ポイントフリー*形式でコードが書けるようになることがよくあります。 +ただし、読みやすさにはやはり注意が要ります。 ## モナド則 @@ -210,10 +212,10 @@ c2 = do m3 ``` -これらの計算にはそれぞれ、3つのモナドの式`m1`、`m2`、`m3`が含まれています。 -どちらの場合でも`m1`の結果は名前`x`に束縛され、`m2`の結果は名前`y`に束縛されます。 +これらの各計算には3つのモナドの式`m1`、`m2`、`m3`が含まれています。 +どちらの場合でも`m1`の結果は結局は名前`x`に束縛され、`m2`の結果は名前`y`に束縛されます。 -`c1`では2つの式 `m1`と `m2`がそれぞれのdo記法ブロック内にグループ化されています。 +`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグループ化されています。 `c2`では`m1`、`m2`、`m3`の3つ全ての式が同じdo記法ブロックに現れています。 @@ -232,10 +234,11 @@ c3 = do ## モナドで畳み込む 抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で機能する関数を紹介していきます。 -これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと対応しているという直感的理解を補強しますし、モナドによるプログラミングがもたらす一般性も示しています。 +これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと対応しているという直感的理解を補強しますし、モナドによるプログラミングが齎す一般性も示しています。 -これから `foldM`と呼ばれる関数を書いてみます。これは以前扱った -`foldl`関数をモナドの文脈へと一般化します。型シグネチャは次のようになっています。 +これから書いていく関数は`foldM`という名前です。 +以前見た`foldl`関数をモナドの文脈へと一般化するものです。 +型シグネチャは以下です。 ```hs foldM :: forall m a b. Monad m => (a -> b -> m a) -> a -> List b -> m a @@ -244,15 +247,14 @@ foldl :: forall a b. (a -> b -> a) -> a -> List b -> a モナド `m`が現れている点を除いて、 `foldl`の型と同じであることに注意しましょう。 -直感的には、 `foldM`はさまざまな副作用の組み合わせに対応した文脈での配列の畳み込みを行うと捉えることができます。 +直感的には、`foldM`は様々な副作用の組み合わせに対応した文脈で配列を畳み込むものと捉えられます。 -例として `m`が `Maybe`であるとすると、この畳み込みはそれぞれの段階で `Nothing`を返すことで失敗させられます。 -それぞれの段階ではオプショナルな結果を返しますから、それゆえ畳み込みの結果もオプショナルになります。 +例として`m`として`Maybe`を選ぶとすると、各段階で`Nothing`を返すことでこの畳み込みを失敗させられます。 +各段階では省略可能な結果を返しますから、それ故畳み込みの結果も省略可能になります。 -もし `m`として配列の型構築子 -`Array`を選ぶとすると、畳み込みのそれぞれの段階で複数の結果を返すことができ、畳み込みは結果それぞれに対して次の手順を継続します。 -最後に、結果の集まりは、可能な経路全ての畳み込みから構成されることになります。 -これはグラフの走査と対応しています。 +もし`m`として型構築子`Array`を選ぶとすると、畳み込みの各段階で0以上の結果を返せるため、畳み込みは各結果に対して独立に次の手順を継続します。 +最後に、結果の集まりは可能な経路の全ての畳み込みから構成されることになります。 +これはグラフの走査と対応していますね。 `foldM`を書くには、単に入力のリストについて場合分けをするだけです。 @@ -262,7 +264,7 @@ foldl :: forall a b. (a -> b -> a) -> a -> List b -> a foldM _ a Nil = pure a ``` -なお`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。 +なお、`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。 リストが空でない場合はどうでしょうか。 その場合、型 `a`の値、型 `b`の値、型 `a -> b -> m a`の関数があります。 @@ -277,10 +279,13 @@ foldM f a (b : bs) = do foldM f a' bs ``` -なお、do記法を除けば、この実装は配列に対する `foldl`の実装とほとんど同じです。 +なお、この実装はリストに対する`foldl`の実装とほとんど同じです。 +ただしdo記法である点を除きます。 -PSCiでこれを定義し、試してみましょう。 -以下では例として、除算可能かどうかを調べて、失敗を示すために `Maybe`型構築子を使う、整数の「安全な除算」関数を定義するとしましょう。 +PSCiでこの関数を定義して試せます。 +以下は一例です。 +整数の「安全な除算」関数を定義するとします。 +0による除算かを確認し、失敗を示すために `Maybe`型構築子を使うのです。 ```hs {{#include ../exercises/chapter8/test/Examples.purs:safeDivide}} @@ -299,8 +304,8 @@ PSCiでこれを定義し、試してみましょう。 Nothing ``` -もし何れかの時点で整数にならない除算が行われようとしたら、`foldM safeDivide`関数は `Nothing`を返します。 -そうでなければ、除算を繰り返した累積の結果を`Just`構築子に包んで返します。 +もし何れかの時点で0による除算が試みられたら、`foldM safeDivide`関数は`Nothing`を返します。 +そうでなければ、累算値を繰り返し除算した結果を`Just`構築子に包んで返します。 ## モナドとアプリカティブ @@ -318,15 +323,16 @@ ap mf ma = do もし`m`に`Monad`型クラスの法則の縛りがあれば、`ap`で与えられる`m`について妥当な `Apply`インスタンスが存在します。 -興味のある読者は、これまで登場した `Array`、 `Maybe`、 `Either e`といったモナドについて、この `ap`が -`apply`と一致することを確かめてみてください。 +興味のある読者はこれまで登場したモナドについてこの`ap`が`apply`として充足することを確かめてみてください。 +モナドは`Array`、`Maybe`、`Either e`といったものです。 もし全てのモナドがアプリカティブ関手でもあるなら、アプリカティブ関手についての直感的理解を全てのモナドについても適用できるはずです。 特に、モナドが更なる副作用の組み合わせで増強された「より大きな言語」でのプログラミングといろいろな意味で一致することを予想するのはもっともです。 `map`と `apply`を使って、引数が任意個の関数をこの新しい言語へと持ち上げることができるはずです。 -しかし、モナドはアプリカティブ関手でできること以上を行うことができ、重要な違いはdo記法の構文で強調されています。 -利用者情報をエンコードしたXML文書から利用者の都市を検索する、`userCity`の例についてもう一度考えてみましょう。 +しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法の構文で強調されています。 +`userCity`の例についてもう一度考えてみましょう。 +利用者情報をエンコードしたXML文書から利用者の市町村を検索するものでした。 ```hs userCity :: XML -> Maybe XML @@ -343,17 +349,17 @@ do記法では2番目の計算が最初の結果 `prof`に依存し、3番目の `pure`と `apply`だけを使って `userCity`を書こうとしてみれば、これが不可能であることがわかるでしょう。 アプリカティブ関手ができるのは関数の互いに独立した引数を持ち上げることだけですが、モナドはもっと興味深いデータの依存関係に関わる計算を書くことを可能にします。 -前の章では `Applicative`型クラスは並列処理を表現できることを見ました。 +前の章では`Applicative`型クラスは並列処理を表現できることを見ました。 持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りです。 -`Monad`型クラスは計算が前の計算の結果に依存できるようにしますから、同じようにはなりません。 -モナドは副作用を順番に組み合わせなければいけません。 +`Monad`型クラスは計算が前の計算の結果に依存できるようになっており、同じようにはなりません。 +つまりモナドは副作用を順番に組み合わせなければならないのです。 ## 演習 1. (簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてください。 関数は適切な`Maybe`型で返します。 *手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数の型を見つけ出してください。 - これらの関数を繋げるには`Maybe`モナドと共にdo記法を使ってください。 + これらの関数を組み合わせるには`Maybe`モナドと共にdo記法を使ってください。 1. (普通)一掴みの硬貨を使ってできる可能な全ての合計を決定する関数 `possibleSums`を、 `foldM`を使って書いてみましょう。 入力の硬貨は、硬貨の価値の配列として与えられます。この関数は次のような結果にならなくてはいけません。 @@ -365,13 +371,14 @@ do記法では2番目の計算が最初の結果 `prof`に依存し、3番目の [0,1,2,3,10,11,12,13] ``` - *手掛かり*:`foldM`を使うと1行でこの関数を書くことが可能です。 - 重複を取り除いたり、結果を並び替えたりするのに、`nub`関数や `sort`関数を使いたくなるかもしれません。 -1. (普通)`Maybe`型構築子について、 `ap`関数と `apply`演算子が一致することを確認してください。 + *手掛かり*:`foldM`を使うと1行でこの関数を書けます。 + 重複を取り除いたり、結果を並び替えたりするのに、`nub`関数や`sort`関数を使うことでしょう。 +1. (普通)`ap`関数と`apply`演算子が`Maybe`モナドを充足することを確かめてください。 *補足*:この演習にはテストがありません。 -1. (普通)`maybe`パッケージで定義されている`Maybe`型についての `Monad`インスタンスが、モナド則を満たしていることを検証してください。 +1. (普通)`Maybe`型についての`Monad`インスタンスが、モナド則を満たしていることを検証してください。 + このインスタンスは`maybe`パッケージで定義されています。 *補足*:この演習にはテストがありません。 -1. (普通)配列上の `filter`の関数を一般化した関数`filterM`を書いてください。 +1. (普通)リスト上の`filter`の関数を一般化した関数`filterM`を書いてください。 この関数は次の型シグネチャを持ちます。 ```hs @@ -392,7 +399,7 @@ do記法では2番目の計算が最初の結果 `prof`に依存し、3番目の lift2 f (pure a) (pure b) = pure (f a b) ``` - ここで、 `Applly`インスタンスは上で定義された `ap`関数を使用しています。 + ここで、`Applly`インスタンスは上で定義された`ap`関数を使用しています。 `lift2`が次のように定義されていたことを思い出してください。 ```hs @@ -404,13 +411,13 @@ do記法では2番目の計算が最初の結果 `prof`に依存し、3番目の ## ネイティブな作用 -ここではPureScriptの中核となる重要なモナド、 `Effect`モナドについて見ていきます。 +ここではPureScriptで中心的な重要性のあるモナドの1つ、`Effect`モナドについて見ていきます。 `Effect`モナドは `Effect`モジュールで定義されています。かつてはいわゆる _ネイティブ_ 副作用を管理していました。Haskellに馴染みがあれば、これは`IO`モナドと同等のものです。 ネイティブな副作用とは何でしょうか。 -この副作用はPureScript特有の式からJavaScriptの式を区別するものです。 +この副作用はPureScript特有の式とJavaScriptの式とを2分するものです。 PureScriptの式は概して副作用とは無縁なのです。 ネイティブな作用の例を以下に示します。 @@ -433,33 +440,37 @@ PureScriptの式は概して副作用とは無縁なのです。 - 配列やリストで表現される多値関数 これらの区別はわかりにくいので注意してください。 -エラーメッセージは例外の形でJavaScriptの式の副作用となることがあります。 -その意味では例外はネイティブな副作用を表していて、 `Effect`を使用して表現できます。 -しかし、 `Either`を使用して実装されたエラーメッセージはJavaScriptランタイムの副作用ではなく、 -`Effect`を使うスタイルでエラーメッセージを実装するのは適切ではありません。 +例えば、エラー文言は例外の形でJavaScriptの式の副作用となることがあると言えます。 +その意味では例外はネイティブな副作用を表していて、`Effect`を使用して表現できます。 +しかし、`Either`を使用して実装されたエラー文言はJavaScript実行時の副作用ではなく、`Effect`を使うスタイルでエラー文言を実装するのは不適切です。 そのため、ネイティブなのは作用自体というより、実行時にどのように実装されているかです。 ## 副作用と純粋性 -PureScriptのような言語が純粋であるとすると、疑問が浮かんできます。副作用がないなら、どうやって役に立つ実際のコードを書くことができるというのでしょうか。 +PureScriptのような純粋な言語では、ある疑問が浮かんできます。 +副作用がないなら、どうやって役に立つ実際のコードを書くことができるのでしょうか。 -その答えはPureScriptの目的は副作用を排除することではないということです。これは、純粋な計算と副作用のある計算とを型システムにおいて区別できるような方法で、副作用を表現することを目的としているのです。この意味で、言語はあくまで純粋だということです。 +その答えはPureScriptの目的は副作用を排除することではないということです。 +純粋な計算と副作用のある計算とを、型システムにおいて区別できるような方法で表現します。 +この意味で、言語はあくまで純粋なのです。 -副作用のある値は、純粋な値とは異なる型を持っています。そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起こらなくなります。 +副作用のある値は、純粋な値とは異なる型を持っています。 +そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起こらなくなります。 -`Effect`モナドで管理された副作用を実行する唯一の方法は、型 `Effect a`の計算をJavaScriptから実行することです。 +`Effect`モナドで管理された副作用を現す手段は、型`Effect a`の計算をJavaScriptから実行することです。 Spagoビルドツール(や他のツール)は早道を用意しており、アプリケーションの起動時に`main`計算を呼び出すための追加のJavaScriptコードを生成します。 -`main`は `Effect`モナドでの計算であることが要求されます。 +`main`は`Effect`モナドでの計算であることが要求されます。 ## 作用モナド `Effect`は副作用のある計算を充分に型付けするAPIを提供すると同時に、効率的なJavaScriptを生成します。 -馴染みのある`log`関数から返る型をもう少し見てみましょう。 +馴染みのある`log`関数から返る型を見てみましょう。 `Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコンソールIOです。 + `Unit`はいかなる*意味のある*データも返らないことを示しています。 -`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられます。 +`Unit`はC、Javaなど他の言語での`void`キーワードと似たものとして考えられます。 ```hs log :: String -> Effect Unit @@ -503,22 +514,24 @@ spago run --main Test.Random コンソールに出力 `0.0`と `1.0`の間で無作為に選ばれた数が表示されるでしょう。 -> 余談:`spago run`は既定で`Main`モジュールとその中の`main`関数を探索します。 -`--main`フラグで代替のモジュールを入口として指定でき、上の例ではそうしています。 -この代替のモジュールもまた`main`関数を含んでいることに注目してください。 +> 余談:`spago run`は既定で`main`関数を`Main`モジュールの中から探索します。 +> `--main`フラグで代替のモジュールを入口として指定することも可能で、上の例ではそうしています。 +> この代替のモジュールにも`main`関数が含まれているようにはしてください。 なお、不浄な作用付きのコードに訴えることなく、「乱択された」(技術的には疑似乱択された)データも生成できます。 この技法は「テストを生成する」章で押さえます。 以前言及したように`Effect`モナドはPureScriptで核心的な重要さがあります。 -なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやりとりする上での常套手段だからです。 +なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りする上での常套手段だからです。 `外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕組みを提供します。 `外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように動作しどう使うのか理解することもまた極めて大事なことですので、実際にPureScriptで何か動かす前にその章を読まれることをお勧めします。 -要は`Effect`モナドは結構単純なのです。幾つかの補助関数がありますが、それを差し置いても副作用を内包すること以外には大したことはしません。 +要は`Effect`モナドは結構単純なのです。 +幾つかの補助関数がありますが、副作用を内包すること以外には大したことはしません。 ## 例外 -2つの _ネイティブな_ 副作用が絡む`node-fs`パッケージの関数を調べましょう。ここでの副作用は可変状態の読み取りと例外です。 +2つの*ネイティブな*副作用が絡む`node-fs`パッケージの関数を調べましょう。 +ここでの副作用は可変状態の読み取りと例外です。 ```hs readTextFile :: Encoding -> String -> Effect String @@ -588,8 +601,8 @@ exceptionHead l = case l of 純粋関数プログラミングを知っているなら、共有される変更可能な状態は問題を引き起こしやすいということも知っているでしょう。 しかし、`ST`作用は型システムを使って安全で*局所的な*状態変化を可能にし、状態の共有を制限するのです。 -`ST`作用は -`Control.Monad.ST`モジュールで定義されています。これがどのように動作するかを確認するには、そのアクションの型を見る必要があります。 +`ST`作用は `Control.Monad.ST`モジュールで定義されています。 +この挙動を確認するには、その動作の型を見る必要があります。 ```hs new :: forall a r. a -> ST r (STRef r a) @@ -601,12 +614,13 @@ write :: forall a r. a -> STRef r a -> ST r a modify :: forall r a. (a -> a) -> STRef r a -> ST r a ``` -`new`は型`STRef r a`の変更可能な参照領域を新しく作るのに使われます。 -`STRef r a`は `read`アクションを使って状態を読み取ったり、`write`アクションや -`modify`アクションで状態を変更するのに使われます。 -型`a`は領域に格納された値の型で、型 `r`は型システムで*メモリ領域*(または*ヒープ*)を表しています。 +`new`は型`STRef r a`の可変参照領域を新規作成するのに使われます。 +この領域は`read`動作を使って読み取ったり、`write`動作や`modify`動作で状態を変更するのに使えます。 +型`a`は領域に格納された値の型を、型`r`は*メモリ領域*(または*ヒープ*)を、それぞれ型システムで表しています。 -例を示します。小さな時間刻みで簡単な更新関数の実行を何度も繰り返すことによって、重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。 +例を示します。 +重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。 +これには小さな時間刻みで簡単な更新関数の実行を何度も繰り返します。 粒子の位置と速度を保持する変更可能な参照領域を作成し、領域に格納された値を更新するのにforループを使うことでこれを実現できます。 @@ -633,8 +647,8 @@ simulate x0 v0 time = do 計算の最後では、参照領域の最終的な値を読み取り、粒子の位置を返しています。 -なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの他の部分で使われるのが許されない限り、これは純粋な関数のままです。 -`ST`作用が禁止するものが正確には何であるのかについては後ほど見ます。 +なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの他の部分での使用が許されない限り、これは純粋な関数のままです。 +このことが正に`ST`作用が禁止するものであることを見ていきます。 `ST`作用付きで計算するには、`run`関数を使用する必要があります。 @@ -643,11 +657,10 @@ run :: forall a. (forall r. ST r a) -> a ``` ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化されているということです。 -`run`に渡したどんなアクションでも、*任意の領域*`r`が何であれ動作するということを意味しています。 +`run`に渡したどんな動作でも、*任意の領域*`r`が何であれ動作するということを意味しています。 -しかし、ひとたび参照領域が -`new`によって作成されると、その領域の型は既に固定されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エラーになるでしょう。 -`run`が安全に `ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由なのです。 +しかし、ひとたび参照領域が`new`によって作成されると、その領域の型は既に固定されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エラーになるでしょう。 +`run`が安全に`ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由なのです。 ```hs simulate' :: Number -> Number -> Int -> Number @@ -694,7 +707,7 @@ simulate x0 v0 time = pure final.x ``` -参照領域はそのスコープから逃れることができないことがコンパイラにわかりますし、安全に`ref`を`var`に変換できます。 +そうして、参照領域はそのスコープから逃れられないことと、安全に`ref`を`var`に変換できることにコンパイラが気付きます。 `run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになります。 ```javascript @@ -722,9 +735,9 @@ var simulate = function (x0) { }; ``` -なおこの結果として得られたJavaScriptは最適化の余地があります。 -詳細は[この課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。 -上記の抜粋はその課題が解決されたら更新されるでしょう。 +> なお、この結果として得られたJavaScriptは最適化の余地があります。 +> 詳細は[こちらの課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。 +> 上記の抜粋はそちらの課題が解決されたら更新されるでしょう。 比較としてこちらが埋め込まれていない形式で生成されたJavaScriptです。 @@ -753,8 +766,8 @@ var simulate = function (x0) { }; ``` -局所的な変更可能状態を扱うとき、特に作用が絡むループを生成する`for`、 `foreach`、 -`while`のようなアクションを一緒に使うときには、`ST`作用は短いJavaScriptを生成する良い方法となります。 +局所的な変更可能状態を扱うとき、`ST`作用は短いJavaScriptを生成する良い方法となります。 +作用を持つ繰り返しを生成する`for`、`foreach`、`while`のような動作を一緒に使うときは特にそうです。 ## 演習 @@ -776,12 +789,11 @@ var simulate = function (x0) { DOMを直接扱ったり、オープンソースのDOMライブラリを扱ったりするPureScriptパッケージが沢山あります。 例えば以下です。 -- [`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3C - のDOM規格に向けた型定義と低水準インターフェース実装を提供します。 +- [`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3CのDOM規格に向けた型定義と低水準インターフェース実装を提供します。 - [`web-html`](https://github.com/purescript-web/purescript-web-html)はW3CのHTML5規格に向けた型定義と低水準インターフェース実装を提供します。 - [`jquery`](http://github.com/paf31/purescript-jquery)は[jQuery](http://jquery.org)ライブラリのバインディングの集まりです。 -上記のライブラリを抽象化するPureScriptライブラリもあります。 +上記のライブラリを土台に抽象化を進めたPureScriptライブラリもあります。 以下のようなものです。 - [`thermite`](https://github.com/paf31/purescript-thermite)は[`react`](https://github.com/purescript-contrib/purescript-react)を土台に構築されています。 @@ -799,12 +811,12 @@ Reactライブラリの完全な入門はこの章の範囲をはるかに超え 目的に応じて、Reactは `Effect`モナドの実用的な例を提供してくれます。 利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。 -フォームには、さまざまなフィールド(姓、名前、都市、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。 -テキストボックスに利用者がテキストを入力すると、検証エラーが更新されます。 +フォームには、様々なフィールド(姓、名、市町村、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。 +テキストボックスに利用者がテキストを入力する度に、検証エラーが更新されます。 簡潔さを保つために、フォームは固定の形状とします。電話番号は種類(自宅、携帯電話、仕事、その他)ごとに別々のテキストボックスへ分けることにします。 -`exercises/chapter8`ディレクトリから以下のコマンドでWebアプリを立ち上げることができます。 +`exercises/chapter8`ディレクトリから以下のコマンドでwebアプリを立ち上げることができます。 ```shell $ npm install @@ -820,7 +832,7 @@ $ npx parcel src/index.html --open また、[`purs ide`](https://github.com/purescript/purescript/tree/master/psc-ide)に対応していたり[`pscid`](https://github.com/kRITZCREEK/pscid)を走らせていたりする[エディタ](https://github.com/purescript/documentation/blob/master/ecosystem/Editor-and-tool-support.md#editors)を使っていれば、ファイルを保存したときに自動的にページが再構築される(そして自動的にページが再読み込みされる)ように設定できます。 -このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上に出力された検証エラーを見ることができるでしょう。 +このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上で出力された検証エラーが見られます。 動作の仕組みを散策しましょう。 @@ -910,7 +922,7 @@ propsからJSXへの関数は単にこうです。 `props`は無視されており、`D.text`は`JSX`を返し、そして`pure`は描画されたJSXに持ち上げます。 これで`component`には`ReactComponent`を生成するのに必要な全てがあります。 -次に完全なアドレス帳コンポーネントにある幾つかの複雑な事柄をもう少し調べていきます。 +次に、完全なアドレス帳コンポーネントにある幾つかの複雑な事柄を調べていきます。 これらは完全なコンポーネントの最初の数行です。 @@ -928,7 +940,7 @@ Tuple person setPerson <- useState examplePerson ``` なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部品に分解することが自在にできます。 -例えば`Person`のそれぞれのレコードフィールドについて分離した状態の部品を使って、このアプリを書き直すことができるでしょう。 +例えば`Person`の各レコードフィールドについて分離した状態の部品を使って、このアプリを書き直すことができるでしょう。 しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいます。 他の例では`Tuple`用の`/\`中置演算子に出喰わすかもしれません。 @@ -962,7 +974,7 @@ setPerson :: (state -> state) -> Effect Unit `state`の限定された型は初期の既定値によって決定されます。 これは`examplePerson`の型なのでこの場合は`Person` `Record`です。 -`person`はそれぞれの再描画の時点で現在の状態にアクセスする方法です。 +`person`は各再描画の時点で現在の状態にアクセスする方法です。 `setPerson`は状態を更新する方法です。 単に現在の状態を新しい状態に変形する方法を記述する関数を提供します。 @@ -1024,7 +1036,10 @@ pure } ``` -ここでDOMの意図した状態を表現する`JSX`を生成しています。このJSXはHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、`label`、`input`)に対応し、典型的には単一のHTML要素を作る関数を適用することで作られます。これらのHTML要素は実はReactコンポーネントそのものによりJSXに変換されます。通常これらの関数にはそれぞれ3つの種類があります。 +ここでDOMの意図した状態を表現する`JSX`を生成しています。 +このJSXは単一のHTML要素を作るHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、`label`、`input`)に対応する関数を適用することで作られるのが普通です。 +これらのHTML要素はそれ自体がReactコンポーネントであり、JSXに変換されます。 +通常これらの関数にはそれぞれ3つの種類があります。 - `div_`: 子要素の配列を受け付けます。 既定の属性を使います。 @@ -1074,7 +1089,8 @@ handler :: forall a. EventFn SyntheticEvent a -> (a -> Effect Unit) -> EventHand targetValue :: EventFn SyntheticEvent (Maybe String) ``` -JavaScriptでは`input`要素の`onChange`イベントは実は`String`値と一緒になっているのですが、JavaScriptの文字列はnullになりえるので、安全のために`Maybe`が使われています。 +JavaScriptでは`input`要素の`onChange`イベントには`String`値が伴います。 +しかし、JavaScriptの文字列はnullになり得るので、安全のために`Maybe`が使われています。 したがって`(a -> Effect Unit)`の`handler`への2つ目の引数は、このシグネチャを持ちます。 @@ -1095,9 +1111,9 @@ onChange: handler targetValue handleValue ``` -`setValue`はそれぞれの`formField`の呼び出しに与えた関数で、文字列を取り`setPerson`フックに適切なレコード更新呼び出しを実施します。 +`setValue`は`formField`の各呼び出しに与えた関数で、文字列を取り`setPerson`フックに適切なレコード更新呼び出しを実施します。 -なお`handleValue`は以下のようにも置き換えられます。 +なお、`handleValue`は以下のようにも置き換えられます。 ```hs onChange: handler targetValue $ traverse_ setValue @@ -1105,7 +1121,8 @@ onChange: handler targetValue $ traverse_ setValue `traverse_`の定義を調査して、両方の形式が確かに等価であることをご確認ください。 -これでコンポーネント実装の基本を押さえました。しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随する出典元をお読みください。 +これでコンポーネント実装の基本を押さえました。 +しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随するソースをお読みください。 明らかに、このユーザーインターフェースには改善すべき点が沢山あります。 演習ではアプリケーションがより使いやすくなるような方法を追究していきます。 @@ -1117,12 +1134,14 @@ onChange: handler targetValue $ traverse_ setValue 1. (簡単)このアプリケーションを変更し、職場の電話番号を入力できるテキストボックスを追加してください。 1. (普通)現時点でアプリケーションは検証エラーを単一の「pink-alert」背景に集めて表示させています。 - 空の線で分割することにより、それぞれの検証エラーにpink-alert背景を持たせるように変更してください。 + 空行で分離することにより、各検証エラーにpink-alert背景を持たせるように変更してください。 - *手掛かり*:リスト中の検証エラーを表示するのに`ul`要素を使う代わりに、コードを変更し、それぞれのエラーに`alert`と`alert-danger`装飾を持つ`div`を作ってください。 -1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。コードを変更してこの問題を解決してください。 + *手掛かり*:リスト中の検証エラーを表示するのに`ul`要素を使う代わりに、コードを変更し、各エラーに`alert`と`alert-danger`装飾を持つ`div`を作ってください。 +1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。 + コードを変更してこの問題を解決してください。 - *手掛かり*:検証器によって返されるエラーの型は、エラーの原因となっているフィールドを示すために拡張する必要があります。次のような変更されたエラー型を使用したくなるでしょう。 + *手掛かり*:検証器によって返されるエラーの型を、エラーの原因となっているフィールドを示すために拡張するべきです。 + 以下の変更されたエラー型を使うと良いでしょう。 ```hs data Field = FirstNameField @@ -1143,12 +1162,13 @@ onChange: handler targetValue $ traverse_ setValue この章ではPureScriptでの副作用の扱いについての多くの考え方を導入しました。 -- `Monad`型クラスとdo記法との関係性に出会いました。 +- `Monad`型クラスとdo記法との関係性を見ました。 - モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。 -- 異なる副作用を扱うコードを書くために、モナドを抽象的に使う方法を見ました。 +- 異なる副作用を扱うコードを書く上で、モナドを抽象的に使う方法を見ました。 - モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算を可能にするのかということ、そして2つの手法の違いを説明しました。 -- ネイティブな作用の概念を定義し、ネイティブな副作用を処理するために使用する `Effect`モナドを導入しました。 -- 乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作といった、さまざまな作用を扱うために +- ネイティブな作用の概念を定義し、`Effect`モナドを見ました。 + これはネイティブな副作用を扱うものでした。 +- 乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作といった、様々な作用を扱うために `Effect`モナドを使いました。 `Effect`モナドは実際のPureScriptコードにおける基本的なツールです。本書ではこのあとも、多くの場面で副作用を処理するために使っていきます。 diff --git a/text-ja/chapter9.md b/text-ja/chapter9.md index b638aeac..ae76c574 100644 --- a/text-ja/chapter9.md +++ b/text-ja/chapter9.md @@ -2,7 +2,10 @@ ## この章の目標 -この章では`Aff`モナドに集中します。これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。ファイルシステムとやりとりしてHTTPリクエストを作る、非同期な例を実演していきます。また非同期作用の直列ないし並列な実行の管理方法も押さえます。 +この章では`Aff`モナドに集中します。 +これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。 +非同期にファイルシステムとやり取りしたりHTTPリクエストしたりする例を実演していきます。 +また非同期作用の直列ないし並列な実行の管理方法も押さえます。 ## プロジェクトの準備 @@ -13,7 +16,7 @@ - `affjax` - AJAXと`Aff`を使ったHTTPリクエスト。 - `parallel` - `Aff`の並列実行。 -(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリは`xhr2`NPMモジュールが必要です。 +(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリには`xhr2`NPMモジュールが必要です。 このモジュールはこの章の`package.json`中の依存関係に挙げられています。 以下を走らせてインストールします。 @@ -58,10 +61,11 @@ PureScriptでの`Aff`モナドはJavaScriptの`async`/`await`構文に似た人 なお、`main`は`Effect Unit`でなければならないので、`launchAff_`を使って`Aff`から`Effect`へと変換せねばなりません。 -上のコード片をコールバックや同期関数を使って書き換えることも可能ですが(例えば`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それらのコーディング形式は推奨されません。 +上のコード片をコールバックや同期関数を使って書き換えることも可能です(例えば`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)。 +しかし、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それらのコーディング形式は推奨されません。 `Aff`を扱う文法は`Effect`を扱うものと大変似ています。 -どちらもモナドですし、したがってdo記法で書くことができます。 +どちらもモナドですし、したがってdo記法で書けます。 例えば`readTextFile`のシグネチャを見れば、これがファイルの内容を`String`とし、`Aff`に包んで返していることがわかります。 @@ -93,7 +97,8 @@ attempt :: forall a. Aff a -> Aff (Either Error a) 1. (簡単)2つのテキストファイルを連結する関数`concatenateFiles`を書いてください。 - 1. (普通)入力ファイル名の配列と出力ファイル名が与えられたとき、複数のテキストファイルを連結する関数`concatenateMany`を書いてください。 + 1. (普通)複数のテキストファイルを連結する関数`concatenateMany`を書いてください。 + 入力ファイル名の配列と出力ファイル名が与えられます。 *手掛かり*:`traverse`を使ってください。 1. (普通)ファイル中の文字数を返すか、エラーがあればそれを返す関数`countCharacters :: FilePath -> Aff @@ -102,7 +107,7 @@ attempt :: forall a. Aff a -> Aff (Either Error a) ## 更なるAffの資料 もしまだ[公式のAffの手引き](https://pursuit.purescript.org/packages/purescript-aff/)を見ていなければ、今ざっと目を通してください。 -この章の残りの演習を完了する上で事前に必要なことではありませんが、Pursuitで何らかの関数を見付けだす助けになるかもしれません。 +この章の残りの演習を完了する上で事前に直接必要なことではありませんが、Pursuitで何らかの関数を見付けだす助けになるかもしれません。 以下の補足資料についてもあたってみるとよいでしょう。しかし繰り返しになりますがこの章の演習はこれらの内容に依りません。 @@ -111,11 +116,12 @@ attempt :: forall a. Aff a -> Aff (Either Error a) ## HTTPクライアント -`affjax`ライブラリは`Aff`で非同期AJAX HTTP要求する便利な手段を提供します。 +`affjax`ライブラリは`Aff`で非同期なAJAXのHTTP要求をする上での便利な手段を提供します。 対象としている環境が何であるかによって、[purescript-affjax-web](https://github.com/purescript-contrib/purescript-affjax-web)または[purescript-affjax-node](https://github.com/purescript-contrib/purescript-affjax-node)のどちらかのライブラリを使う必要があります。 -この章の以降ではNodeを対象としていくので、`purescript-affjax-node`を使います。 + +この章の以降ではnodeを対象としていくので、`purescript-affjax-node`を使います。 より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript.org/packages/purescript-affjax)にあたってください。 -以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例です。 +以下は与えられたURLに向けてHTTPのGET要求をして、応答本文ないしエラー文言を返す例です。 ```hs {{#include ../exercises/chapter9/test/HTTP.purs:getUrl}} @@ -152,7 +158,7 @@ unit `parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義しており、並列実行に対応しています。 以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリカティブ関手がどれほど便利なのかを見ました。 -実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を合成するために使われるアプリカティブ関手`f`との対応関係を定義しているのです。 +実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を組み合わせるために使えるアプリカティブ関手`f`との対応関係を定義しているのです。 ```hs class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where @@ -165,16 +171,16 @@ class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where - `parallel`:モナド`m`中の計算を取り、アプリカティブ関手`f`中の計算に変えます。 - `sequential`:反対方向に変換します。 -`aff`ライブラリは `Aff`モナドの `Parallel`インスタンスを提供します。 -これは、2つの継続 (continuation) のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に -`Aff`アクションを組み合わせます。 -両方の結果が返されたら、最終結果を計算してメインの継続に渡すことができます。 +`aff`ライブラリは`Aff`モナドの`Parallel`インスタンスを提供します。 +これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に`Aff`動作を組み合わせます。 +両方の結果が返されたら、最終結果を計算してメインの継続に渡せます。 アプリカティブ関手では任意個の引数の関数の持ち上げができるので、このアプリカティブコンビネータを使ってより多くの計算を並列に実行できます。 `traverse`や`sequence`といった、アプリカティブ関手を扱う全ての標準ライブラリ関数から恩恵を受けることもできます。 -必要に応じて -`parralel`と`sequential`を使って型構築子を変更することで、do記法ブロック中でアプリカティブコンビネータを使い、直列的なコードの一部で並列計算を結合したり、またはその逆を行ったりできます。 +直列的なコードの一部と並列計算を組み合わせることもできます。 +それにはdo記法ブロック中でアプリカティブコンビネータを使います。 +その逆も然りで、必要に応じて`parralel`と`sequential`を使って型構築子を変更すれば良いのです。 直列実行と並列実行の間の違いを実演するために、100個の10ミリ秒の遅延からなる配列をつくり、それからその遅延を両方の手法で実行します。REPLで試すと`seqDelay`が`parDelay`より遥かに遅いことに気付くでしょう。並列実行が`sequence_`を`parSequence_`で置き換えるだけで有効になるところに注目です。 @@ -229,8 +235,8 @@ unit 1. (難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてください。 一覧にあるファイルを並列に読んでください。 - パスはそのファイルが表れたディレクトリから相対的なものです。 - *手掛かり*:`node_path`モジュールにはディレクトリを扱う上で便利な関数があります。 + パスはそのファイルが現れたディレクトリから相対的なものです。 + *手掛かり*:`node-path`モジュールにはディレクトリを扱う上で便利な関数があります。 例えば次のような`root.txt`ファイルから始まるとします。 @@ -261,8 +267,8 @@ $ cat c/a/a.txt ## まとめ -この章では非同期エフェクトと以下の方法を押さえました。 +この章では非同期作用と以下の方法を押さえました。 - `aff`ライブラリを使って`Aff`モナド中で非同期コードを走らせる。 -- `affjax`ライブラリを使って非同期にHTTPリクエストを行う。 +- `affjax`ライブラリを使って非同期にHTTPリクエストする。 - `parallel`ライブラリを使って並列に非同期コードを走らせる。 diff --git a/text-ja/index.md b/text-ja/index.md index b2a34cad..f3ef8779 100644 --- a/text-ja/index.md +++ b/text-ja/index.md @@ -10,10 +10,10 @@ PureScriptのエコシステムの最新の機能を紹介すべく書き直さ ## 現状 -この本は言語の進化に伴って継続的に更新されているため、内容に関して発見したどんな[問題](https://github.com/purescript-contrib/purescript-book/issues)でもご報告ください。 +本書は言語の進化に伴って継続的に更新されているため、内容に関して発見したどんな[問題](https://github.com/purescript-contrib/purescript-book/issues)でもご報告ください。 より初心者にやさしくできそうな分かりづらい節を指摘するような単純なものであれ、共有いただいたどんなフィードバックにも感謝します。 -それぞれの章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確かめることができます。 +各章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確かめることができます。 テストの最新の状態については[#79](https://github.com/purescript-contrib/purescript-book/issues/79)を見てください。 ## 本書について @@ -25,10 +25,10 @@ Haskellで書かれ、またこの言語から着想を得ています。 JavaScriptでの関数型プログラミングは最近かなりの人気を誇るようになりましたが、コードを書く上で統制された環境が欠けていることが大規模なアプリケーション開発の妨げとなっています。 PureScriptは、強力に型付けされた関数型プログラミングの力をJavaScriptでの開発の世界に持ち込むことにより、この問題の解決を目指しています。 -この本は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。 +本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。 -それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。 -以下はこの本で解いていく課題の幾つかの例です。 +各章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。 +以下は本書で解いていく課題の幾つかの例です。 - マップと畳み込みを使ったデータ構造の変換 - アプリカティブ関手を使ったフォームフィールドの検証 @@ -47,23 +47,13 @@ The text of this book is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License: . -※以降の原文の使用許諾に関する和訳は法的効力を持ちません。
-本書のテキストは表示 - 非営利 - -継承3.0非移植 (CC BY-NC-SA 3.0)のもとに使用が許諾される。
- Some text is derived from the [PureScript Documentation Repo](https://github.com/purescript/documentation), which uses the same license, and is copyright [various contributors](https://github.com/purescript/documentation/blob/master/CONTRIBUTORS.md). -幾つかのテキストは[PureScriptのドキュメントリポジトリ](https://github.com/purescript/documentation)から派生している。 -派生元も同じ使用許諾であり、[様々な形で貢献された方々](https://github.com/purescript/documentation/blob/master/CONTRIBUTORS.md)の著作権が含まれる。 - The exercises are licensed under the MIT license. -演習はMITライセンスの下に使用が許諾される。 - - - - diff --git a/translation/README.md b/translation/README.md index 3c5047c5..2d8bb968 100644 --- a/translation/README.md +++ b/translation/README.md @@ -22,6 +22,9 @@ [po4a]: https://po4a.org/ +翻訳の際には`terms.txt`に挙げた簡単な用語集のメモが役に立つかもしれません。 +追加や変更の提案をいただいても構いません。 + 生成物に対しての自動的な検証を幾つか導入しています。 `npm run lint`で検証します。 diff --git a/translation/all.pot b/translation/all.pot index 85b3a5a7..d6f5439e 100644 --- a/translation/all.pot +++ b/translation/all.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2023-06-22 08:06+0900\n" +"POT-Creation-Date: 2023-08-25 21:33+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -322,7 +322,7 @@ msgstr "" #, markdown-text msgid "" "Libraries such as [UnderscoreJS](https://underscorejs.org) allow the " -"developer to leverage tried-and-trusted functions such as `map`, `filter` " +"developer to leverage tried-and-trusted functions such as `map`, `filter`, " "and `reduce` to create larger programs from smaller programs by composition:" msgstr "" @@ -386,10 +386,10 @@ msgstr "" #: text/chapter1.md:38 #, markdown-text msgid "" -"Functions enable a simple form of abstraction which can yield great " -"productivity gains. However, functional programming in JavaScript has its " -"own disadvantages: JavaScript is verbose, untyped, and lacks powerful forms " -"of abstraction. Unrestricted JavaScript code also makes equational reasoning " +"Functions enable a simple form of abstraction that can yield great " +"productivity gains. However, functional programming in JavaScript has " +"disadvantages: JavaScript is verbose, untyped, and lacks powerful forms of " +"abstraction. Unrestricted JavaScript code also makes equational reasoning " "very difficult." msgstr "" @@ -397,54 +397,62 @@ msgstr "" #: text/chapter1.md:40 #, markdown-text msgid "" -"PureScript is a programming language which aims to address these issues. It " +"PureScript is a programming language that aims to address these issues. It " "features lightweight syntax, which allows us to write very expressive code " "which is still clear and readable. It uses a rich type system to support " "powerful abstractions. It also generates fast, understandable code, which is " -"important when interoperating with JavaScript, or other languages which " +"important when interoperating with JavaScript or other languages that " "compile to JavaScript. All in all, I hope to convince you that PureScript " "strikes a very practical balance between the theoretical power of purely " -"functional programming, and the fast-and-loose programming style of " +"functional programming and the fast-and-loose programming style of " "JavaScript." msgstr "" +#. type: Plain text +#: text/chapter1.md:42 +#, markdown-text, no-wrap +msgid "" +"> Note that PureScript can target other backends, not only JavaScript, but " +"this book focuses on targeting web browser and node environments.\n" +msgstr "" + #. type: Title ## -#: text/chapter1.md:41 +#: text/chapter1.md:43 #, markdown-text, no-wrap msgid "Types and Type Inference" msgstr "" #. type: Plain text -#: text/chapter1.md:44 +#: text/chapter1.md:46 #, markdown-text msgid "" "The debate over statically typed languages versus dynamically typed " "languages is well-documented. PureScript is a _statically typed_ language, " -"meaning that a correct program can be given a _type_ by the compiler which " -"indicates its behavior. Conversely, programs which cannot be given a type " -"are _incorrect programs_, and will be rejected by the compiler. In " -"PureScript, unlike in dynamically typed languages, types exist only at " -"_compile-time_, and have no representation at runtime." +"meaning that a correct program can be given a _type_ by the compiler, which " +"indicates its behavior. Conversely, programs that cannot be given a type are " +"_incorrect programs_, and will be rejected by the compiler. In PureScript, " +"unlike in dynamically typed languages, types exist only at _compile-time_ " +"and have no representation at runtime." msgstr "" #. type: Plain text -#: text/chapter1.md:46 +#: text/chapter1.md:48 #, markdown-text msgid "" -"It is important to note that in many ways, the types in PureScript are " +"It is important to note that, in many ways, the types in PureScript are " "unlike the types that you might have seen in other languages like Java or " "C#. While they serve the same purpose at a high level, the types in " "PureScript are inspired by languages like ML and Haskell. PureScript's types " "are expressive, allowing the developer to assert strong claims about their " "programs. Most importantly, PureScript's type system supports _type " -"inference_ - it requires far fewer explicit type annotations than other " +"inference_ – it requires far fewer explicit type annotations than other " "languages, making the type system a _tool_ rather than a hindrance. As a " "simple example, the following code defines a _number_, but there is no " "mention of the `Number` type anywhere in the code:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter1.md:47 +#: text/chapter1.md:49 #, no-wrap msgid "" "iAmANumber =\n" @@ -453,16 +461,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:54 +#: text/chapter1.md:56 #, markdown-text msgid "" "A more involved example shows that type-correctness can be confirmed without " -"type annotations, even when there exist types which are _unknown to the " +"type annotations, even when there exist types that are _unknown to the " "compiler_:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter1.md:55 +#: text/chapter1.md:57 #, no-wrap msgid "" "iterate f 0 x = x\n" @@ -470,7 +478,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:61 +#: text/chapter1.md:63 #, markdown-text msgid "" "Here, the type of `x` is unknown, but the compiler can still verify that " @@ -479,7 +487,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:63 +#: text/chapter1.md:65 #, markdown-text msgid "" "In this book, I will try to convince you (or reaffirm your belief) that " @@ -492,32 +500,32 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:65 +#: text/chapter1.md:67 #, markdown-text msgid "" "In addition, the safety net provided by a type system enables more advanced " "forms of abstraction. In fact, PureScript provides a powerful form of " -"abstraction which is fundamentally type-driven: type classes, made popular " -"in the functional programming language Haskell." +"abstraction that is fundamentally type-driven: type classes, made popular in " +"the functional programming language Haskell." msgstr "" #. type: Title ## -#: text/chapter1.md:66 +#: text/chapter1.md:68 #, markdown-text, no-wrap msgid "Polyglot Web Programming" msgstr "" #. type: Plain text -#: text/chapter1.md:69 +#: text/chapter1.md:71 #, markdown-text msgid "" -"Functional programming has its success stories - applications where it has " +"Functional programming has its success stories – applications where it has " "been particularly successful: data analysis, parsing, compiler " "implementation, generic programming, parallelism, to name a few." msgstr "" #. type: Plain text -#: text/chapter1.md:71 +#: text/chapter1.md:73 #, markdown-text msgid "" "It would be possible to practice end-to-end application development in a " @@ -528,23 +536,23 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:73 +#: text/chapter1.md:75 #, markdown-text msgid "" "However, one of PureScript's strengths is its interoperability with other " "languages which target JavaScript. Another approach would be to use " -"PureScript for a subset of your application's development, and to use one or " +"PureScript for a subset of your application's development and to use one or " "more other languages to write the rest of the JavaScript." msgstr "" #. type: Plain text -#: text/chapter1.md:75 +#: text/chapter1.md:77 #, markdown-text msgid "Here are some examples:" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:79 +#: text/chapter1.md:81 #, markdown-text msgid "" "Core logic written in PureScript, with the user interface written in " @@ -552,7 +560,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:79 +#: text/chapter1.md:81 #, markdown-text msgid "" "Application written in JavaScript or another compile-to-JS language, with " @@ -560,7 +568,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:79 +#: text/chapter1.md:81 #, markdown-text msgid "" "PureScript used to automate user interface tests for an existing " @@ -568,7 +576,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:81 +#: text/chapter1.md:83 #, markdown-text msgid "" "In this book, we'll focus on solving small problems with PureScript. The " @@ -577,13 +585,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter1.md:82 +#: text/chapter1.md:84 #, markdown-text, no-wrap msgid "Prerequisites" msgstr "" #. type: Plain text -#: text/chapter1.md:85 +#: text/chapter1.md:87 #, markdown-text msgid "" "The software requirements for this book are minimal: the first chapter will " @@ -593,17 +601,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:87 +#: text/chapter1.md:89 #, markdown-text msgid "" -"The PureScript compiler itself can be downloaded as a binary distribution, " -"or built from source on any system running an up-to-date installation of the " +"The PureScript compiler itself can be downloaded as a binary distribution or " +"built from source on any system running an up-to-date installation of the " "GHC Haskell compiler, and we will walk through this process in the next " "chapter." msgstr "" #. type: Plain text -#: text/chapter1.md:90 +#: text/chapter1.md:92 #, markdown-text msgid "" "The code in this version of the book is compatible with versions `0.15.*` of " @@ -611,13 +619,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter1.md:91 +#: text/chapter1.md:93 #, markdown-text, no-wrap msgid "About You" msgstr "" #. type: Plain text -#: text/chapter1.md:94 +#: text/chapter1.md:96 #, markdown-text msgid "" "I will assume that you are familiar with the basics of JavaScript. Any prior " @@ -627,21 +635,21 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:96 +#: text/chapter1.md:98 #, markdown-text msgid "" "No prior knowledge of functional programming is required, but it certainly " "won't hurt. New ideas will be accompanied by practical examples, so you " -"should be able to form an intuition for the concepts from functional " +"should be able to form an intuition for the concepts from the functional " "programming that we will use." msgstr "" #. type: Plain text -#: text/chapter1.md:98 +#: text/chapter1.md:100 #, markdown-text msgid "" "Readers who are familiar with the Haskell programming language will " -"recognize a lot of the ideas and syntax presented in this book, because " +"recognize a lot of the ideas and syntax presented in this book because " "PureScript is heavily influenced by Haskell. However, those readers should " "understand that there are a number of important differences between " "PureScript and Haskell. It is not necessarily always appropriate to try to " @@ -650,16 +658,16 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter1.md:99 +#: text/chapter1.md:101 #, markdown-text, no-wrap msgid "How to Read This Book" msgstr "" #. type: Plain text -#: text/chapter1.md:102 +#: text/chapter1.md:104 #, markdown-text msgid "" -"The chapters in this book are largely self contained. A beginner with little " +"The chapters in this book are largely self-contained. A beginner with little " "functional programming experience would be well-advised, however, to work " "through the chapters in order. The first few chapters lay the groundwork " "required to understand the material later on in the book. A reader who is " @@ -670,11 +678,11 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:104 +#: text/chapter1.md:106 #, markdown-text msgid "" "Each chapter will focus on a single practical example, providing the " -"motivation for any new ideas introduced. Code for each chapter are available " +"motivation for any new ideas introduced. Code for each chapter is available " "from the book's [GitHub " "repository](https://github.com/purescript-contrib/purescript-book). Some " "chapters will include code snippets taken from the chapter's source code, " @@ -685,13 +693,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:106 +#: text/chapter1.md:108 #, markdown-text -msgid "Code samples will appear in a monospaced font, as follows:" +msgid "Code samples will appear in a monospaced font as follows:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter1.md:107 +#: text/chapter1.md:109 #, no-wrap msgid "" "module Example where\n" @@ -702,7 +710,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:116 +#: text/chapter1.md:118 #, markdown-text msgid "" "Commands which should be typed at the command line will be preceded by a " @@ -710,22 +718,22 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter1.md:117 text/chapter3.md:313 +#: text/chapter1.md:119 text/chapter3.md:330 #, no-wrap msgid "$ spago build\n" msgstr "" #. type: Plain text -#: text/chapter1.md:122 +#: text/chapter1.md:124 #, markdown-text msgid "" "Usually, these commands will be tailored to Linux/Mac OS users, so Windows " -"users may need to make small changes such as modifying the file separator, " +"users may need to make small changes, such as modifying the file separator " "or replacing shell built-ins with their Windows equivalents." msgstr "" #. type: Plain text -#: text/chapter1.md:124 +#: text/chapter1.md:126 #, markdown-text msgid "" "Commands which should be typed at the PSCi interactive mode prompt will be " @@ -733,7 +741,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter1.md:125 +#: text/chapter1.md:127 #, no-wrap msgid "" "> 1 + 2\n" @@ -741,33 +749,33 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:131 +#: text/chapter1.md:133 #, markdown-text msgid "" -"Each chapter will contain exercises, labelled with their difficulty " -"level. It is strongly recommended that you attempt the exercises in each " -"chapter to fully understand the material." +"Each chapter will contain exercises labelled with their difficulty level. It " +"is strongly recommended that you attempt the exercises in each chapter to " +"fully understand the material." msgstr "" #. type: Plain text -#: text/chapter1.md:133 +#: text/chapter1.md:135 #, markdown-text msgid "" "This book aims to provide an introduction to the PureScript language for " "beginners, but it is not the sort of book that provides a list of template " "solutions to problems. For beginners, this book should be a fun challenge, " "and you will get the most benefit if you read the material, attempt the " -"exercises, and most importantly of all, try to write some code of your own." +"exercises, and, most importantly of all, try to write some code of your own." msgstr "" #. type: Title ## -#: text/chapter1.md:134 +#: text/chapter1.md:136 #, markdown-text, no-wrap msgid "Getting Help" msgstr "" #. type: Plain text -#: text/chapter1.md:137 +#: text/chapter1.md:139 #, markdown-text msgid "" "If you get stuck at any point, there are a number of resources available " @@ -775,26 +783,24 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [PureScript Discord server](https://discord.gg/vKn9up84bp) is a great " "place to chat about issues you may be having. The server is dedicated to " -"chat about PureScript" +"chatting about PureScript" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [Purescript Discourse Forum](https://discourse.purescript.org/) is " -"another good place to search for solutions to common problems. Questions you " -"ask here will be available to help future readers, whereas on Slack, message " -"history is only kept for approximately 2 weeks." +"another good place to search for solutions to common problems." msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "[PureScript: Jordan's " @@ -805,7 +811,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "[Pursuit](https://pursuit.purescript.org) is a searchable database of " @@ -814,7 +820,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The unofficial [PureScript " @@ -823,61 +829,63 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [PureScript documentation " "repository](https://github.com/purescript/documentation) collects articles " -"and examples on a wide variety of topics, written by PureScript developers " +"and examples on a wide variety of topics written by PureScript developers " "and users." msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [PureScript website](https://www.purescript.org) contains links to " -"several learning resources, including code samples, videos and other " +"several learning resources, including code samples, videos, and other " "resources for beginners." msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" -"[Try PureScript!](https://try.purescript.org) is a website which allows " -"users to compile PureScript code in the web browser, and contains several " -"simple examples of code." +"[Try PureScript!](https://try.purescript.org) is a website that allows users " +"to compile PureScript code in the web browser and contains several simple " +"examples of code." msgstr "" #. type: Plain text -#: text/chapter1.md:148 +#: text/chapter1.md:150 #, markdown-text msgid "" -"If you prefer to learn by reading examples, the `purescript`, " -"`purescript-node` and `purescript-contrib` GitHub organizations contain " -"plenty of examples of PureScript code." +"If you prefer to learn by reading examples, the " +"[purescript](https://github.com/purescript), " +"[purescript-node](https://github.com/purescript-node), and " +"[purescript-contrib](https://github.com/purescript-contrib) GitHub " +"organizations contain plenty of examples of PureScript code." msgstr "" #. type: Title ## -#: text/chapter1.md:149 +#: text/chapter1.md:151 #, markdown-text, no-wrap msgid "About the Author" msgstr "" #. type: Plain text -#: text/chapter1.md:152 +#: text/chapter1.md:154 #, markdown-text msgid "" "I am the original developer of the PureScript compiler. I'm based in Los " "Angeles, California, and started programming at an early age in BASIC on an " -"8-bit personal computer, the Amstrad CPC. Since then I have worked " +"8-bit personal computer, the Amstrad CPC. Since then, I have worked " "professionally in a variety of programming languages (including Java, Scala, " "C#, F#, Haskell and PureScript)." msgstr "" #. type: Plain text -#: text/chapter1.md:154 +#: text/chapter1.md:156 #, markdown-text msgid "" "Not long into my professional career, I began to appreciate functional " @@ -886,7 +894,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter1.md:156 +#: text/chapter1.md:158 #, markdown-text msgid "" "I started working on the PureScript compiler in response to my experience " @@ -895,13 +903,13 @@ msgid "" "environment in which to apply them. Solutions at the time included various " "attempts to compile Haskell to JavaScript while preserving its semantics " "(Fay, Haste, GHCJS), but I was interested to see how successful I could be " -"by approaching the problem from the other side - attempting to keep the " +"by approaching the problem from the other side – attempting to keep the " "semantics of JavaScript, while enjoying the syntax and type system of a " "language like Haskell." msgstr "" #. type: Plain text -#: text/chapter1.md:158 +#: text/chapter1.md:160 #, markdown-text msgid "" "I maintain [a blog](https://blog.functorial.com), and can be [reached on " @@ -909,33 +917,33 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter1.md:159 +#: text/chapter1.md:161 #, markdown-text, no-wrap msgid "Acknowledgements" msgstr "" #. type: Plain text -#: text/chapter1.md:162 +#: text/chapter1.md:164 #, markdown-text msgid "" "I would like to thank the many contributors who helped PureScript to reach " "its current state. Without the huge collective effort which has been made on " -"the compiler, tools, libraries, documentation and tests, the project would " +"the compiler, tools, libraries, documentation, and tests, the project would " "certainly have failed." msgstr "" #. type: Plain text -#: text/chapter1.md:164 +#: text/chapter1.md:166 #, markdown-text msgid "" "The PureScript logo which appears on the cover of this book was created by " -"Gareth Hughes, and is gratefully reused here under the terms of the " -"[Creative Commons Attribution 4.0 " +"Gareth Hughes and is gratefully reused here under the terms of the [Creative " +"Commons Attribution 4.0 " "license](https://creativecommons.org/licenses/by/4.0/)." msgstr "" #. type: Plain text -#: text/chapter1.md:165 +#: text/chapter1.md:167 #, markdown-text msgid "" "Finally, I would like to thank everyone who has given me feedback and " @@ -962,7 +970,7 @@ msgstr "" #, markdown-text msgid "" "This chapter will introduce PureScript's _foreign function interface_ (or " -"_FFI_), which enables communication from PureScript code to JavaScript code, " +"_FFI_), which enables communication from PureScript code to JavaScript code " "and vice versa. We will cover how to:" msgstr "" @@ -1011,10 +1019,10 @@ msgstr "" #: text/chapter10.md:17 #, markdown-text msgid "" -"There is also an addendum which covers some additional topics which are not " -"as commonly sought-after. Feel free to read these sections, but don't let " -"them stand in the way of progressing through the remainder of the book if " -"they're less relevant to your learning objectives:" +"There is also an addendum covering some additional topics that are not as " +"commonly sought-after. Feel free to read these sections, but don't let them " +"stand in the way of progressing through the remainder of the book if they're " +"less relevant to your learning objectives:" msgstr "" #. type: Bullet: '- ' @@ -1043,7 +1051,7 @@ msgstr "" #, markdown-text msgid "" "The source code for this module is a continuation of the source code from " -"chapters 3, 7 and 8. As such, the source tree includes the appropriate " +"chapters 3, 7, and 8. As such, the source tree includes the appropriate " "source files from those chapters." msgstr "" @@ -1086,9 +1094,9 @@ msgid "" "PureScript provides a straightforward foreign function interface to make " "working with JavaScript as simple as possible. However, it should be noted " "that the FFI is an _advanced_ feature of the language. To use it safely and " -"effectively, you should have an understanding of the runtime representation " -"of the data you plan to work with. This chapter aims to impart such an " -"understanding as pertains to code in PureScript's standard libraries." +"effectively, you should understand the runtime representation of the data " +"you plan to work with. This chapter aims to impart such an understanding as " +"pertains to code in PureScript's standard libraries." msgstr "" #. type: Plain text @@ -1096,8 +1104,8 @@ msgstr "" #, markdown-text msgid "" "PureScript's FFI is designed to be very flexible. In practice, this means " -"that developers have a choice, between giving their foreign functions very " -"simple types, or using the type system to protect against accidental misuses " +"that developers have a choice between giving their foreign functions very " +"simple types or using the type system to protect against accidental misuses " "of foreign code. Code in the standard libraries tends to favor the latter " "approach." msgstr "" @@ -1153,7 +1161,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" "This function has the correct runtime representation for the function type " -"`String -> String`, since it takes non-null strings to non-null strings, and " +"`String -> String`, since it takes non-null strings to non-null strings and " "has no other side-effects.\n" msgstr "" @@ -1176,7 +1184,7 @@ msgstr "" #, markdown-text msgid "" "We also need to write a foreign JavaScript module to import it from. A " -"corresponding foreign JavaScript module is one of the same name but " +"corresponding foreign JavaScript module is one of the same name but the " "extension changed from `.purs` to `.js`. If the Purescript module above is " "saved as `URI.purs`, then the foreign JavaScript module is saved as " "`URI.js`. Since `encodeURIComponent` is already defined, we have to export " @@ -1293,7 +1301,7 @@ msgstr "" #, markdown-text msgid "" "Recall that functions in PureScript are _curried_. `diagonal` is a function " -"that takes a `Number` and returns a _function_, that takes a `Number` and " +"that takes a `Number` and returns a _function_ that takes a `Number` and " "returns a `Number`." msgstr "" @@ -1400,8 +1408,8 @@ msgstr "" #: text/chapter10.md:166 #, markdown-text msgid "" -"We can then call it with `runFn2` which takes the uncurried function then " -"the arguments." +"We can then call it with `runFn2`, which takes the uncurried function and " +"then the arguments." msgstr "" #. type: Fenced code block (text) @@ -1434,9 +1442,9 @@ msgstr "" #: text/chapter10.md:181 #, markdown-text msgid "" -"PureScript's curried functions has certain advantages. It allows us to " +"PureScript's curried functions have certain advantages. It allows us to " "partially apply functions, and to give type class instances for function " -"types - but it comes with a performance penalty. For performance critical " +"types – but it comes with a performance penalty. For performance-critical " "code, it is sometimes necessary to define uncurried JavaScript functions " "which accept multiple arguments." msgstr "" @@ -1505,7 +1513,7 @@ msgstr "" #: text/chapter10.md:211 #, markdown-text msgid "" -"and the resulting generated code, which is less compact due to the nested " +"And the resulting generated code, which is less compact due to the nested " "functions:" msgstr "" @@ -1532,7 +1540,7 @@ msgstr "" #: text/chapter10.md:225 #, markdown-text msgid "" -"The arrow function syntax we saw earlier is an ES6 feature, and so it is " +"The arrow function syntax we saw earlier is an ES6 feature, which is " "incompatible with some older browsers (namely IE11). As of writing, it is " "[estimated that arrow functions are unavailable for the 6% of " "users](https://caniuse.com/#feat=arrow-functions) who have not yet updated " @@ -1543,17 +1551,16 @@ msgstr "" #: text/chapter10.md:227 #, markdown-text msgid "" -"In order to be compatible with the most users, the JavaScript code generated " -"by the PureScript compiler does not use arrow functions. It is also " -"recommended to **avoid arrow functions in public libraries** for the same " -"reason." +"To be compatible with the most users, the JavaScript code generated by the " +"PureScript compiler does not use arrow functions. It is also recommended to " +"**avoid arrow functions in public libraries** for the same reason." msgstr "" #. type: Plain text #: text/chapter10.md:229 #, markdown-text msgid "" -"You may still use arrow functions in your own FFI code, but then should " +"You may still use arrow functions in your own FFI code, but then you should " "include a tool such as [Babel](https://github.com/babel/babel#intro) in your " "deployment workflow to convert these back to ES5 compatible functions." msgstr "" @@ -1598,23 +1605,23 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:246 text/chapter10.md:321 text/chapter10.md:476 -#: text/chapter10.md:714 text/chapter10.md:891 text/chapter10.md:1074 -#: text/chapter10.md:1311 text/chapter11.md:140 text/chapter11.md:224 -#: text/chapter11.md:343 text/chapter11.md:549 text/chapter11.md:716 -#: text/chapter11.md:915 text/chapter11.md:960 text/chapter12.md:153 +#: text/chapter10.md:246 text/chapter10.md:321 text/chapter10.md:478 +#: text/chapter10.md:716 text/chapter10.md:893 text/chapter10.md:1076 +#: text/chapter10.md:1313 text/chapter11.md:141 text/chapter11.md:223 +#: text/chapter11.md:342 text/chapter11.md:548 text/chapter11.md:715 +#: text/chapter11.md:914 text/chapter11.md:959 text/chapter12.md:153 #: text/chapter12.md:361 text/chapter12.md:555 text/chapter13.md:90 #: text/chapter13.md:137 text/chapter13.md:244 text/chapter13.md:387 #: text/chapter14.md:249 text/chapter14.md:352 text/chapter14.md:569 -#: text/chapter14.md:704 text/chapter2.md:124 text/chapter3.md:714 +#: text/chapter14.md:704 text/chapter2.md:124 text/chapter3.md:774 #: text/chapter4.md:70 text/chapter4.md:181 text/chapter4.md:363 #: text/chapter4.md:521 text/chapter4.md:615 text/chapter5.md:99 #: text/chapter5.md:228 text/chapter5.md:392 text/chapter5.md:465 #: text/chapter5.md:524 text/chapter6.md:130 text/chapter6.md:321 -#: text/chapter6.md:412 text/chapter6.md:609 text/chapter6.md:743 +#: text/chapter6.md:411 text/chapter6.md:608 text/chapter6.md:742 #: text/chapter7.md:381 text/chapter7.md:540 text/chapter7.md:642 -#: text/chapter8.md:308 text/chapter8.md:666 text/chapter8.md:973 -#: text/chapter9.md:87 text/chapter9.md:133 text/chapter9.md:200 +#: text/chapter8.md:308 text/chapter8.md:667 text/chapter8.md:974 +#: text/chapter9.md:87 text/chapter9.md:134 text/chapter9.md:201 #, markdown-text, no-wrap msgid "Exercises" msgstr "" @@ -1670,10 +1677,9 @@ msgstr "" #, markdown-text msgid "" "To demonstrate passing `Array`s, here's how to call a JavaScript function " -"which takes an `Array` of `Int` and returns the cumulative sum as another " -"array. Recall that, since JavaScript does not have a separate type for " -"`Int`, both `Int` and `Number` in PureScript translate to `Number` in " -"JavaScript." +"that takes an `Array` of `Int` and returns the cumulative sum as another " +"array. Recall that since JavaScript does not have a separate type for `Int`, " +"both `Int` and `Number` in PureScript translate to `Number` in JavaScript." msgstr "" #. type: Fenced code block (hs) @@ -1713,9 +1719,9 @@ msgstr "" #, markdown-text msgid "" "To demonstrate passing `Records`, here's how to call a JavaScript function " -"which takes two `Complex` numbers as records, and returns their sum as " -"another record. Note that a `Record` in PureScript is represented as an " -"`Object` in JavaScript:" +"that takes two `Complex` numbers as records and returns their sum as another " +"record. Note that a `Record` in PureScript is represented as an `Object` in " +"JavaScript:" msgstr "" #. type: Fenced code block (hs) @@ -1758,10 +1764,10 @@ msgstr "" #, markdown-text msgid "" "Note that the above techniques require trusting that JavaScript will return " -"the expected types, as PureScript is not able to apply type checking to " -"JavaScript code. We will describe this type safety concern in more detail " -"later on in the JSON section, as well as cover techniques to protect against " -"type mismatches." +"the expected types, as PureScript cannot apply type checking to JavaScript " +"code. We will describe this type safety concern in more detail later on in " +"the JSON section, as well as cover techniques to protect against type " +"mismatches." msgstr "" #. type: Bullet: '1. ' @@ -1909,42 +1915,52 @@ msgstr "" #. type: Plain text #: text/chapter10.md:387 #, markdown-text -msgid "and not:" +msgid "And not:" msgstr "" #. type: Fenced code block (hs) #: text/chapter10.md:388 #, no-wrap -msgid "forall a. ( a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" +msgid "forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" msgstr "" #. type: Plain text -#: text/chapter10.md:394 +#: text/chapter10.md:393 #, markdown-text msgid "" "While both forms work, the latter is more vulnerable to unwanted inputs in " -"place of `Just` and `Nothing`. For example, in the more vulnerable case we " -"could call it as follows:" +"place of `Just` and `Nothing`." msgstr "" -#. type: Fenced code block (hs) +#. type: Plain text #: text/chapter10.md:395 +#, markdown-text +msgid "For example, in the more vulnerable case, we could call it as follows:" +msgstr "" + +#. type: Fenced code block (hs) +#: text/chapter10.md:396 #, no-wrap msgid "maybeHeadImpl (\\_ -> Just 1000) (Just 1000) [1,2,3]\n" msgstr "" #. type: Plain text #: text/chapter10.md:401 +#, markdown-text +msgid "Which returns `Just 1000` for any array input." +msgstr "" + +#. type: Plain text +#: text/chapter10.md:403 #, markdown-text, no-wrap msgid "" -"which returns `Just 1000` for any array input.\n" "This vulnerability is allowed because `(\\_ -> Just 1000)` and `Just 1000` " -"match the signatures of `(a -> Maybe a)` and `Maybe a` respectively when `a` " -"is `Int` (based on input array).\n" +"match the signatures of `(a -> Maybe a)` and `Maybe a`, respectively, when " +"`a` is `Int` (based on input array).\n" msgstr "" #. type: Plain text -#: text/chapter10.md:404 +#: text/chapter10.md:406 #, markdown-text, no-wrap msgid "" "In the more secure type signature, even when `a` is determined to be `Int` " @@ -1958,22 +1974,22 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:405 +#: text/chapter10.md:407 #, markdown-text, no-wrap msgid "Defining Foreign Types" msgstr "" #. type: Plain text -#: text/chapter10.md:408 +#: text/chapter10.md:410 #, markdown-text msgid "" -"Suppose instead of returning a `Maybe a`, we want to actually return " -"`arr[0]`. We want a type that represents a value either of type `a` or the " -"`undefined` value (but not `null`). We'll call this type `Undefined a`." +"Suppose instead of returning a `Maybe a`, we want to return `arr[0]`. We " +"want a type that represents a value either of type `a` or the `undefined` " +"value (but not `null`). We'll call this type `Undefined a`." msgstr "" #. type: Plain text -#: text/chapter10.md:410 +#: text/chapter10.md:412 #, markdown-text msgid "" "We can define a _foreign type_ using a _foreign type declaration_. The " @@ -1981,13 +1997,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:411 +#: text/chapter10.md:413 #, no-wrap msgid "foreign import data Undefined :: Type -> Type\n" msgstr "" #. type: Plain text -#: text/chapter10.md:416 +#: text/chapter10.md:418 #, markdown-text, no-wrap msgid "" "The `data` keyword here indicates that we are defining a _type_, not a " @@ -1997,13 +2013,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:418 +#: text/chapter10.md:420 #, markdown-text -msgid "We can now simply reuse our original definition for `head`:" +msgid "We can now reuse our original definition for `head`:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:419 +#: text/chapter10.md:421 #, no-wrap msgid "" "export const undefinedHead = arr =>\n" @@ -2011,36 +2027,36 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:425 +#: text/chapter10.md:427 #, markdown-text msgid "And in the PureScript module:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:426 +#: text/chapter10.md:428 #, no-wrap msgid "foreign import undefinedHead :: forall a. Array a -> Undefined a\n" msgstr "" #. type: Plain text -#: text/chapter10.md:431 +#: text/chapter10.md:433 #, markdown-text msgid "" -"The body of the `undefinedHead` function returns `arr[0]` which may be " +"The body of the `undefinedHead` function returns `arr[0]`, which may be " "`undefined`, and the type signature correctly reflects that fact." msgstr "" #. type: Plain text -#: text/chapter10.md:433 +#: text/chapter10.md:435 #, markdown-text msgid "" -"This function has the correct runtime representation for its type, but is " +"This function has the correct runtime representation for its type, but it's " "quite useless since we have no way to use a value of type `Undefined " "a`. Well, not exactly. We can use this type in another FFI!" msgstr "" #. type: Plain text -#: text/chapter10.md:435 +#: text/chapter10.md:437 #, markdown-text msgid "" "We can write a function that will tell us whether a value is undefined or " @@ -2048,19 +2064,19 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:436 +#: text/chapter10.md:438 #, no-wrap msgid "foreign import isUndefined :: forall a. Undefined a -> Boolean\n" msgstr "" #. type: Plain text -#: text/chapter10.md:441 +#: text/chapter10.md:443 #, markdown-text msgid "This is defined in our foreign JavaScript module as follows:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:442 +#: text/chapter10.md:444 #, no-wrap msgid "" "export const isUndefined = value =>\n" @@ -2068,7 +2084,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:448 +#: text/chapter10.md:450 #, markdown-text msgid "" "We can now use `isUndefined` and `undefinedHead` together from PureScript to " @@ -2076,7 +2092,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:449 +#: text/chapter10.md:451 #, no-wrap msgid "" "isEmpty :: forall a. Array a -> Boolean\n" @@ -2084,24 +2100,24 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:455 +#: text/chapter10.md:457 #, markdown-text msgid "" "Here, the foreign function we defined is very simple, which means we can " -"benefit from the use of PureScript's typechecker as much as possible. This " -"is good practice in general: foreign functions should be kept as small as " +"benefit from using PureScript's typechecker as much as possible. This is " +"good practice in general: foreign functions should be kept as small as " "possible, and application logic moved into PureScript code wherever " "possible." msgstr "" #. type: Title ## -#: text/chapter10.md:456 text/chapter8.md:365 text/chapter8.md:443 +#: text/chapter10.md:458 text/chapter8.md:365 text/chapter8.md:444 #, markdown-text, no-wrap msgid "Exceptions" msgstr "" #. type: Plain text -#: text/chapter10.md:459 +#: text/chapter10.md:461 #, markdown-text msgid "" "Another option is to simply throw an exception in the case of an empty " @@ -2111,19 +2127,19 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:460 +#: text/chapter10.md:462 #, no-wrap msgid "foreign import unsafeHead :: forall a. Array a -> a\n" msgstr "" #. type: Plain text -#: text/chapter10.md:465 +#: text/chapter10.md:467 #, markdown-text msgid "In our foreign JavaScript module, we can define `unsafeHead` as follows:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:466 +#: text/chapter10.md:468 #, no-wrap msgid "" "export const unsafeHead = arr => {\n" @@ -2136,7 +2152,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter10.md:479 +#: text/chapter10.md:481 #, markdown-text msgid "" "(Medium) Given a record that represents a quadratic polynomial `a*x^2 + b*x " @@ -2144,7 +2160,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:487 +#: text/chapter10.md:489 #, markdown-text, no-wrap msgid "" " ```hs\n" @@ -2157,7 +2173,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:489 +#: text/chapter10.md:491 #, markdown-text, no-wrap msgid "" " Write a JavaScript function `quadraticRootsImpl` and a wrapper " @@ -2168,7 +2184,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter10.md:491 +#: text/chapter10.md:493 #, markdown-text msgid "" "(Medium) Write the function `toMaybe :: forall a. Undefined a -> Maybe " @@ -2177,13 +2193,13 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter10.md:493 +#: text/chapter10.md:495 #, markdown-text msgid "(Difficult) With `toMaybe` in place, we can rewrite `maybeHead` as" msgstr "" #. type: Plain text -#: text/chapter10.md:498 +#: text/chapter10.md:500 #, markdown-text, no-wrap msgid "" " ```hs\n" @@ -2193,7 +2209,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:500 +#: text/chapter10.md:502 #, markdown-text, no-wrap msgid "" " Is this a better approach than our previous implementation? _Note:_ " @@ -2201,31 +2217,31 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:501 +#: text/chapter10.md:503 #, markdown-text, no-wrap msgid "Using Type Class Member Functions" msgstr "" #. type: Plain text -#: text/chapter10.md:504 +#: text/chapter10.md:506 #, markdown-text msgid "" -"Just like our earlier guide on passing the `Maybe` constructor over FFI, " -"this is another case of writing PureScript that calls JavaScript, which in " -"turn calls PureScript functions again. Here we will explore how to pass type " -"class member functions over the FFI." +"Like our earlier guide on passing the `Maybe` constructor over FFI, this is " +"another case of writing PureScript that calls JavaScript, which calls " +"PureScript functions again. Here we will explore how to pass type class " +"member functions over the FFI." msgstr "" #. type: Plain text -#: text/chapter10.md:506 +#: text/chapter10.md:508 #, markdown-text msgid "" -"We start with writing a foreign JavaScript function which expects the " +"We start with writing a foreign JavaScript function that expects the " "appropriate instance of `show` to match the type of `x`." msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:507 +#: text/chapter10.md:509 #, no-wrap msgid "" "export const boldImpl = show => x =>\n" @@ -2233,25 +2249,25 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:513 +#: text/chapter10.md:515 #, markdown-text msgid "Then we write the matching signature:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:514 +#: text/chapter10.md:516 #, no-wrap msgid "foreign import boldImpl :: forall a. (a -> String) -> a -> String\n" msgstr "" #. type: Plain text -#: text/chapter10.md:519 +#: text/chapter10.md:521 #, markdown-text -msgid "and a wrapper function that passes the correct instance of `show`:" +msgid "And a wrapper function that passes the correct instance of `show`:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:520 +#: text/chapter10.md:522 #, no-wrap msgid "" "bold :: forall a. Show a => a -> String\n" @@ -2259,13 +2275,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:526 +#: text/chapter10.md:528 #, markdown-text -msgid "Alternatively in point-free form:" +msgid "Alternatively, in point-free form:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:527 +#: text/chapter10.md:529 #, no-wrap msgid "" "bold :: forall a. Show a => a -> String\n" @@ -2273,13 +2289,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:533 +#: text/chapter10.md:535 #, markdown-text msgid "We can then call the wrapper:" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:534 +#: text/chapter10.md:536 #, no-wrap msgid "" "$ spago repl\n" @@ -2291,7 +2307,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:544 +#: text/chapter10.md:546 #, markdown-text msgid "" "Here's another example demonstrating passing multiple functions, including a " @@ -2299,7 +2315,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:545 +#: text/chapter10.md:547 #, no-wrap msgid "" "export const showEqualityImpl = eq => show => a => b => {\n" @@ -2312,7 +2328,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:555 +#: text/chapter10.md:557 #, no-wrap msgid "" "foreign import showEqualityImpl :: forall a. (a -> a -> Boolean) -> (a -> " @@ -2323,7 +2339,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:562 +#: text/chapter10.md:564 #, no-wrap msgid "" "$ spago repl\n" @@ -2335,13 +2351,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:571 +#: text/chapter10.md:573 #, markdown-text, no-wrap msgid "Effectful Functions" msgstr "" #. type: Plain text -#: text/chapter10.md:574 +#: text/chapter10.md:576 #, markdown-text msgid "" "Let's extend our `bold` function to log to the console. Logging is an " @@ -2350,7 +2366,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:575 +#: text/chapter10.md:577 #, no-wrap msgid "" "export const yellImpl = show => x => () =>\n" @@ -2358,7 +2374,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:581 +#: text/chapter10.md:583 #, markdown-text msgid "" "The new foreign import is the same as before, except that the return type " @@ -2366,7 +2382,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:582 +#: text/chapter10.md:584 #, no-wrap msgid "" "foreign import yellImpl :: forall a. (a -> String) -> a -> Effect Unit\n" @@ -2376,15 +2392,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:590 +#: text/chapter10.md:592 #, markdown-text msgid "" "When testing this in the repl, notice that the string is printed directly to " -"the console (instead of being quoted) and a `unit` value is returned." +"the console (instead of being quoted), and a `unit` value is returned." msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:591 +#: text/chapter10.md:593 #, no-wrap msgid "" "$ spago repl\n" @@ -2397,7 +2413,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:602 +#: text/chapter10.md:604 #, markdown-text msgid "" "There are also `EffectFn` wrappers from `Effect.Uncurried`. These are " @@ -2407,18 +2423,18 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:604 +#: text/chapter10.md:606 #, markdown-text msgid "" "You'd generally only use these if you want to call existing JavaScript " -"library APIs directly, rather than wrapping those APIs in curried " +"library APIs directly rather than wrapping those APIs in curried " "functions. So it doesn't make much sense to present an example of uncurried " -"`yell`, where the JavaScript relies on PureScript type class members, since " +"`yell`, where the JavaScript relies on PureScript type class members since " "you wouldn't find that in the existing JavaScript ecosystem." msgstr "" #. type: Plain text -#: text/chapter10.md:606 +#: text/chapter10.md:608 #, markdown-text msgid "" "Instead, we'll modify our previous `diagonal` example to include logging in " @@ -2426,7 +2442,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:607 +#: text/chapter10.md:609 #, no-wrap msgid "" "export const diagonalLog = function(w, h) {\n" @@ -2437,13 +2453,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:615 +#: text/chapter10.md:617 #, no-wrap msgid "foreign import diagonalLog :: EffectFn2 Number Number Number\n" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:619 +#: text/chapter10.md:621 #, no-wrap msgid "" "$ spago repl\n" @@ -2456,13 +2472,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:629 +#: text/chapter10.md:631 #, markdown-text, no-wrap msgid "Asynchronous Functions" msgstr "" #. type: Plain text -#: text/chapter10.md:632 +#: text/chapter10.md:634 #, markdown-text msgid "" "Promises in JavaScript translate directly to asynchronous effects in " @@ -2472,7 +2488,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:634 +#: text/chapter10.md:636 #, markdown-text msgid "" "Suppose we want to use this JavaScript `wait` promise (or asynchronous " @@ -2481,13 +2497,13 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:635 +#: text/chapter10.md:637 #, no-wrap msgid "const wait = ms => new Promise(resolve => setTimeout(resolve, ms));\n" msgstr "" #. type: Plain text -#: text/chapter10.md:640 +#: text/chapter10.md:642 #, markdown-text msgid "" "We just need to export it wrapped as an `Effect` (function of zero " @@ -2495,7 +2511,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:641 +#: text/chapter10.md:643 #, no-wrap msgid "" "export const sleepImpl = ms => () =>\n" @@ -2503,13 +2519,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:647 +#: text/chapter10.md:649 #, markdown-text msgid "Then import it as follows:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:648 +#: text/chapter10.md:650 #, no-wrap msgid "" "foreign import sleepImpl :: Int -> Effect (Promise Unit)\n" @@ -2519,13 +2535,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:656 +#: text/chapter10.md:658 #, markdown-text msgid "We can then run this `Promise` in an `Aff` block like so:" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:657 +#: text/chapter10.md:659 #, no-wrap msgid "" "$ spago repl\n" @@ -2546,16 +2562,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:676 +#: text/chapter10.md:678 #, markdown-text msgid "" -"Note that asynchronous logging in the repl just waits to print until the " -"entire block has finished executing. This code behaves more predictably when " -"run with `spago test` where there is a slight delay _between_ prints." +"Note that asynchronous logging in the repl waits to print until the entire " +"block has finished executing. This code behaves more predictably when run " +"with `spago test` where there is a slight delay _between_ prints." msgstr "" #. type: Plain text -#: text/chapter10.md:678 +#: text/chapter10.md:680 #, markdown-text msgid "" "Let's look at another example where we return a value from a promise. This " @@ -2564,7 +2580,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:679 +#: text/chapter10.md:681 #, no-wrap msgid "" "async function diagonalWait(delay, w, h) {\n" @@ -2577,7 +2593,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:690 +#: text/chapter10.md:692 #, markdown-text msgid "" "Since we're returning a `Number`, we represent this type in the `Promise` " @@ -2585,7 +2601,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:691 +#: text/chapter10.md:693 #, no-wrap msgid "" "foreign import diagonalAsyncImpl :: Int -> Number -> Number -> Effect " @@ -2596,7 +2612,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:698 +#: text/chapter10.md:700 #, no-wrap msgid "" "$ spago repl\n" @@ -2615,7 +2631,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:717 +#: text/chapter10.md:719 #, markdown-text msgid "" "Exercises for the above sections are still on the ToDo list. If you have any " @@ -2623,23 +2639,23 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:718 +#: text/chapter10.md:720 #, markdown-text, no-wrap msgid "JSON" msgstr "" #. type: Plain text -#: text/chapter10.md:721 +#: text/chapter10.md:723 #, markdown-text msgid "" -"There are many reasons to use JSON in an application, for example, it's a " +"There are many reasons to use JSON in an application; for example, it's a " "common means of communicating with web APIs. This section will discuss other " -"use-cases too, beginning with a technique to improve type safety when " +"use-cases, too, beginning with a technique to improve type safety when " "passing structural data over the FFI." msgstr "" #. type: Plain text -#: text/chapter10.md:723 +#: text/chapter10.md:725 #, markdown-text msgid "" "Let's revisit our earlier FFI functions `cumulativeSums` and `addComplex` " @@ -2647,7 +2663,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:724 +#: text/chapter10.md:726 #, no-wrap msgid "" "export const cumulativeSumsBroken = arr => {\n" @@ -2670,15 +2686,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:745 +#: text/chapter10.md:747 #, markdown-text msgid "" "We can use the original type signatures, and the code will still compile, " -"despite the fact that the return types are incorrect." +"despite the incorrect return types." msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:746 +#: text/chapter10.md:748 #, no-wrap msgid "" "foreign import cumulativeSumsBroken :: Array Int -> Array Int\n" @@ -2687,7 +2703,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:753 +#: text/chapter10.md:755 #, markdown-text msgid "" "We can even execute the code, which might either produce unexpected results " @@ -2695,7 +2711,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:754 +#: text/chapter10.md:756 #, no-wrap msgid "" "$ spago repl\n" @@ -2722,7 +2738,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:778 +#: text/chapter10.md:780 #, markdown-text msgid "" "For example, our resulting `sums` is no-longer a valid `Array Int`, now that " @@ -2732,7 +2748,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:780 +#: text/chapter10.md:782 #, markdown-text msgid "" "Likewise, there are no errors when calling `addComplexBroken`; however, " @@ -2742,7 +2758,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:782 +#: text/chapter10.md:784 #, markdown-text msgid "" "Let's use JSON to make our PureScript code more impervious to bugs in " @@ -2750,7 +2766,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:784 +#: text/chapter10.md:786 #, markdown-text msgid "" "The `argonaut` library contains the JSON decoding and encoding capabilities " @@ -2760,7 +2776,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:786 +#: text/chapter10.md:788 #, markdown-text msgid "" "If we create an alternate foreign import that defines the return type as " @@ -2768,7 +2784,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:787 +#: text/chapter10.md:789 #, no-wrap msgid "" "foreign import cumulativeSumsJson :: Array Int -> Json\n" @@ -2776,13 +2792,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:793 +#: text/chapter10.md:795 #, markdown-text msgid "Note that we're simply pointing to our existing broken functions:" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:794 +#: text/chapter10.md:796 #, no-wrap msgid "" "export const cumulativeSumsJson = cumulativeSumsBroken\n" @@ -2790,13 +2806,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:800 +#: text/chapter10.md:802 #, markdown-text msgid "And then write a wrapper to decode the returned foreign `Json` value:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:801 +#: text/chapter10.md:803 #, no-wrap msgid "" "{{#include " @@ -2806,7 +2822,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:808 +#: text/chapter10.md:810 #, markdown-text msgid "" "Then any values that can't be successfully decoded to our return type appear " @@ -2814,7 +2830,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:809 +#: text/chapter10.md:811 #, no-wrap msgid "" "$ spago repl\n" @@ -2830,13 +2846,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:822 +#: text/chapter10.md:824 #, markdown-text msgid "If we call the working versions, a `Right` value is returned." msgstr "" #. type: Plain text -#: text/chapter10.md:824 +#: text/chapter10.md:826 #, markdown-text msgid "" "Try this yourself by modifying `test/Examples.js` with the following change " @@ -2844,7 +2860,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:825 +#: text/chapter10.md:827 #, no-wrap msgid "" "export const cumulativeSumsJson = cumulativeSums\n" @@ -2852,7 +2868,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:830 +#: text/chapter10.md:832 #, no-wrap msgid "" "$ spago repl\n" @@ -2867,7 +2883,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:843 +#: text/chapter10.md:845 #, markdown-text msgid "" "Using JSON is also the easiest way to pass other structural types, such as " @@ -2879,7 +2895,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:845 +#: text/chapter10.md:847 #, markdown-text msgid "" "Here's an example of a foreign function signature that modifies a `Map` of " @@ -2888,13 +2904,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:846 +#: text/chapter10.md:848 #, no-wrap msgid "{{#include ../exercises/chapter10/test/Examples.purs:mapSetFooJson}}\n" msgstr "" #. type: Plain text -#: text/chapter10.md:851 +#: text/chapter10.md:853 #, markdown-text msgid "" "Note that this is a prime use case for function composition. Both of these " @@ -2902,7 +2918,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:852 +#: text/chapter10.md:854 #, no-wrap msgid "" "mapSetFoo :: Map String Int -> Either JsonDecodeError (Map String Int)\n" @@ -2913,7 +2929,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:861 +#: text/chapter10.md:863 #, markdown-text msgid "" "Here is the JavaScript implementation. Note the `Array.from` step, which is " @@ -2922,7 +2938,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:862 +#: text/chapter10.md:864 #, no-wrap msgid "" "export const mapSetFooJson = j => {\n" @@ -2933,13 +2949,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:871 +#: text/chapter10.md:873 #, markdown-text msgid "Now we can send and receive a `Map` over the FFI:" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:872 +#: text/chapter10.md:874 #, no-wrap msgid "" "$ spago repl\n" @@ -2962,7 +2978,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 #, markdown-text msgid "" "(Medium) Write a JavaScript function and PureScript wrapper `valuesOfMap :: " @@ -2972,7 +2988,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 #, markdown-text msgid "" "(Easy) Write a new wrapper for the previous JavaScript function with the " @@ -2983,20 +2999,20 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 #, markdown-text msgid "" "(Medium) Rewrite the earlier `quadraticRoots` function as " -"`quadraticRootsSet` which returns the `Complex` roots as a `Set` via JSON " +"`quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON " "(instead of as a `Pair`)." msgstr "" #. type: Plain text -#: text/chapter10.md:900 +#: text/chapter10.md:902 #, markdown-text, no-wrap msgid "" "1. (Difficult) Rewrite the earlier `quadraticRoots` function as " -"`quadraticRootsSafe` which uses JSON to pass the `Pair` of `Complex` roots " +"`quadraticRootsSafe` that uses JSON to pass the `Pair` of `Complex` roots " "over FFI. Don't use the `Pair` constructor in JavaScript, but instead, just " "return the pair in a decoder-compatible format.\n" "_Hint_: You'll need to write a `DecodeJson` instance for `Pair`. Consult the " @@ -3015,7 +3031,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:906 +#: text/chapter10.md:908 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -3026,7 +3042,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:911 +#: text/chapter10.md:913 #, markdown-text, no-wrap msgid "" " Derive generic `EncodeJson` and `DecodeJson` instances for the `Tree` " @@ -3042,7 +3058,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:917 +#: text/chapter10.md:919 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -3053,7 +3069,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:919 +#: text/chapter10.md:921 #, markdown-text, no-wrap msgid "" " Write instances of `EncodeJson` and `DecodeJson` for the `IntOrString` " @@ -3062,22 +3078,22 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:920 +#: text/chapter10.md:922 #, markdown-text, no-wrap msgid "Address book" msgstr "" #. type: Plain text -#: text/chapter10.md:923 +#: text/chapter10.md:925 #, markdown-text msgid "" -"In this section we will apply our newly-acquired FFI and JSON knowledge to " -"build on our address book example from chapter 8. We will add the following " +"In this section, we will apply our newly-acquired FFI and JSON knowledge to " +"build on our address book example from Chapter 8. We will add the following " "features:" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:927 +#: text/chapter10.md:929 #, markdown-text msgid "" "A Save button at the bottom of the form that, when clicked, serializes the " @@ -3085,7 +3101,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:927 +#: text/chapter10.md:929 #, markdown-text msgid "" "Automatic retrieval of the JSON document from local storage upon page " @@ -3093,13 +3109,13 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:927 +#: text/chapter10.md:929 #, markdown-text msgid "A pop-up alert if there is an issue saving or loading the form state." msgstr "" #. type: Plain text -#: text/chapter10.md:929 +#: text/chapter10.md:931 #, markdown-text msgid "" "We'll start by creating FFI wrappers for the following Web Storage APIs in " @@ -3107,7 +3123,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:932 +#: text/chapter10.md:934 #, markdown-text msgid "" "`setItem` takes a key and a value (both strings), and returns a computation " @@ -3115,7 +3131,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:932 +#: text/chapter10.md:934 #, markdown-text msgid "" "`getItem` takes a key, and attempts to retrieve the associated value from " @@ -3124,7 +3140,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:933 +#: text/chapter10.md:935 #, no-wrap msgid "" "foreign import setItem :: String -> String -> Effect Unit\n" @@ -3133,7 +3149,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:940 +#: text/chapter10.md:942 #, markdown-text msgid "" "Here is the corresponding JavaScript implementation of these functions in " @@ -3141,7 +3157,7 @@ msgid "" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:941 +#: text/chapter10.md:943 #, no-wrap msgid "" "export const setItem = key => value => () =>\n" @@ -3152,13 +3168,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:950 +#: text/chapter10.md:952 #, markdown-text msgid "We'll create a save button like so:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:951 +#: text/chapter10.md:953 #, no-wrap msgid "" "saveButton :: R.JSX\n" @@ -3176,7 +3192,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:967 +#: text/chapter10.md:969 #, markdown-text msgid "" "And write our validated `person` as a JSON string with `setItem` in the " @@ -3184,7 +3200,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:968 +#: text/chapter10.md:970 #, no-wrap msgid "" "validateAndSave :: Effect Unit\n" @@ -3199,7 +3215,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:980 +#: text/chapter10.md:982 #, markdown-text msgid "" "Note that if we attempt to compile at this stage, we'll encounter the " @@ -3207,7 +3223,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:981 +#: text/chapter10.md:983 #, no-wrap msgid "" " No type class instance was found for\n" @@ -3215,17 +3231,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:987 +#: text/chapter10.md:989 #, markdown-text msgid "" "This is because `PhoneType` in the `Person` record needs an `EncodeJson` " -"instance. We'll just derive a generic encode instance, and a decode instance " -"too while we're at it. More information how this works is available in the " +"instance. We'll also derive a generic encode instance and a decode instance " +"while we're at it. More information on how this works is available in the " "argonaut docs:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:988 +#: text/chapter10.md:990 #, no-wrap msgid "" "{{#include ../exercises/chapter10/src/Data/AddressBook.purs:import}}\n" @@ -3235,7 +3251,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:995 +#: text/chapter10.md:997 #, markdown-text msgid "" "Now we can save our `person` to local storage, but this isn't very useful " @@ -3243,31 +3259,31 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:997 +#: text/chapter10.md:999 #, markdown-text msgid "We'll start with retrieving the \"person\" string from local storage:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:998 +#: text/chapter10.md:1000 #, no-wrap msgid "item <- getItem \"person\"\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1003 +#: text/chapter10.md:1005 #, markdown-text msgid "" -"Then we'll create a helper function to handle converting the string from " -"local storage to our `Person` record. Note that this string in storage may " -"be `null`, so we represent it as a foreign `Json` until it is successfully " -"decoded as a `String`. There are a number of other conversion steps along " -"the way - each of which return an `Either` value, so it makes sense to " -"organize these together in a `do` block." +"Then we'll create a helper function to convert the string from local storage " +"to our `Person` record. Note that this string in storage may be `null`, so " +"we represent it as a foreign `Json` until it is successfully decoded as a " +"`String`. There are a number of other conversion steps along the way – each " +"of which returns an `Either` value, so it makes sense to organize these " +"together in a `do` block." msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1004 +#: text/chapter10.md:1006 #, no-wrap msgid "" "processItem :: Json -> Either String Person\n" @@ -3278,16 +3294,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1013 +#: text/chapter10.md:1015 #, markdown-text msgid "" -"Then we inspect this result to see if it succeeded. If it failed, we'll log " -"the errors and use our default `examplePerson`, otherwise we'll use the " +"Then we inspect this result to see if it succeeded. If it fails, we'll log " +"the errors and use our default `examplePerson`, otherwise, we'll use the " "person retrieved from local storage." msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1014 +#: text/chapter10.md:1016 #, no-wrap msgid "" "initialPerson <- case processItem item of\n" @@ -3298,7 +3314,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1023 +#: text/chapter10.md:1025 #, markdown-text msgid "" "Finally, we'll pass this `initialPerson` to our component via the `props` " @@ -3306,7 +3322,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1024 +#: text/chapter10.md:1026 #, no-wrap msgid "" "-- Create JSX node from react component.\n" @@ -3314,13 +3330,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1030 +#: text/chapter10.md:1032 #, markdown-text msgid "And pick it up on the other side to use in our state hook:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1031 +#: text/chapter10.md:1033 #, no-wrap msgid "" "mkAddressBookApp :: Effect (ReactComponent { initialPerson :: Person })\n" @@ -3330,7 +3346,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1039 +#: text/chapter10.md:1041 #, markdown-text msgid "" "As a finishing touch, we'll improve the quality of our error messages by " @@ -3338,7 +3354,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1040 +#: text/chapter10.md:1042 #, no-wrap msgid "" "processItem :: Json -> Either String Person\n" @@ -3352,10 +3368,10 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1049 +#: text/chapter10.md:1051 #, markdown-text msgid "" -"Only the first error should ever occur during normal operation of this " +"Only the first error should ever occur during the normal operation of this " "app. You can trigger the other errors by opening your web browser's dev " "tools, editing the saved \"person\" string in local storage, and refreshing " "the page. How you modify the JSON string determines which error is " @@ -3363,25 +3379,24 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1051 +#: text/chapter10.md:1053 #, markdown-text msgid "" -"That covers local storage. Next we'll implement the `alert` action, which is " -"very similar to the `log` action from the `Effect.Console` module. The only " -"difference is that the `alert` action uses the `window.alert` method, " -"whereas the `log` action uses the `console.log` method. As such, `alert` can " -"only be used in environments where `window.alert` is defined, such as a web " -"browser." +"That covers local storage. Next, we'll implement the `alert` action, similar " +"to the `log` action from the `Effect.Console` module. The only difference is " +"that the `alert` action uses the `window.alert` method, whereas the `log` " +"action uses the `console.log` method. As such, `alert` can only be used in " +"environments where `window.alert` is defined, such as a web browser." msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1052 +#: text/chapter10.md:1054 #, no-wrap msgid "foreign import alert :: String -> Effect Unit\n" msgstr "" #. type: Fenced code block (js) -#: text/chapter10.md:1056 +#: text/chapter10.md:1058 #, no-wrap msgid "" "export const alert = msg => () =>\n" @@ -3389,31 +3404,31 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1062 +#: text/chapter10.md:1064 #, markdown-text msgid "We want this alert to appear when either:" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:1065 +#: text/chapter10.md:1067 #, markdown-text msgid "A user attempts to save a form with validation errors." msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:1065 +#: text/chapter10.md:1067 #, markdown-text msgid "The state cannot be retrieved from local storage." msgstr "" #. type: Plain text -#: text/chapter10.md:1067 +#: text/chapter10.md:1069 #, markdown-text msgid "That is accomplished by simply replacing `log` with `alert` on these lines:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter10.md:1068 +#: text/chapter10.md:1070 #, no-wrap msgid "" "Left errs -> alert $ \"There are \" <> show (length errs) <> \" validation " @@ -3423,7 +3438,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 #, markdown-text msgid "" "(Easy) Write a wrapper for the `removeItem` method on the `localStorage` " @@ -3431,7 +3446,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 #, markdown-text msgid "" "(Medium) Add a \"Reset\" button that, when clicked, calls the newly-created " @@ -3439,7 +3454,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 #, markdown-text msgid "" "(Easy) Write a wrapper for the `confirm` method on the JavaScript `Window` " @@ -3447,7 +3462,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 #, markdown-text msgid "" "(Medium) Call this `confirm` function when a users clicks the \"Reset\" " @@ -3455,26 +3470,26 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter10.md:1081 text/chapter11.md:964 text/chapter12.md:594 -#: text/chapter13.md:401 text/chapter14.md:721 text/chapter2.md:129 -#: text/chapter3.md:722 text/chapter4.md:631 text/chapter5.md:529 -#: text/chapter6.md:758 text/chapter7.md:691 text/chapter8.md:1000 -#: text/chapter9.md:237 +#: text/chapter10.md:1083 text/chapter11.md:963 text/chapter12.md:594 +#: text/chapter13.md:401 text/chapter14.md:720 text/chapter2.md:129 +#: text/chapter3.md:782 text/chapter4.md:631 text/chapter5.md:529 +#: text/chapter6.md:757 text/chapter7.md:691 text/chapter8.md:1001 +#: text/chapter9.md:238 #, markdown-text, no-wrap msgid "Conclusion" msgstr "" #. type: Plain text -#: text/chapter10.md:1084 +#: text/chapter10.md:1086 #, markdown-text msgid "" "In this chapter, we've learned how to work with foreign JavaScript code from " -"PureScript and we've seen the issues involved with writing trustworthy code " +"PureScript, and we've seen the issues involved with writing trustworthy code " "using the FFI:" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:1088 +#: text/chapter10.md:1090 #, markdown-text msgid "" "We've seen the importance of ensuring that foreign functions have correct " @@ -3482,43 +3497,43 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:1088 +#: text/chapter10.md:1090 #, markdown-text msgid "" "We learned how to deal with corner cases like null values and other types of " -"JavaScript data, by using foreign types, or the `Json` data type." +"JavaScript data by using foreign types or the `Json` data type." msgstr "" #. type: Bullet: '- ' -#: text/chapter10.md:1088 +#: text/chapter10.md:1090 #, markdown-text msgid "We saw how to safely serialize and deserialize JSON data." msgstr "" #. type: Plain text -#: text/chapter10.md:1090 +#: text/chapter10.md:1092 #, markdown-text msgid "" -"For more examples, the `purescript`, `purescript-contrib` and " +"For more examples, the `purescript`, `purescript-contrib`, and " "`purescript-node` GitHub organizations provide plenty of examples of " -"libraries which use the FFI. In the remaining chapters, we will see some of " +"libraries that use the FFI. In the remaining chapters, we will see some of " "these libraries put to use to solve real-world problems in a type-safe way." msgstr "" #. type: Title ## -#: text/chapter10.md:1091 +#: text/chapter10.md:1093 #, markdown-text, no-wrap msgid "Addendum" msgstr "" #. type: Title ### -#: text/chapter10.md:1093 +#: text/chapter10.md:1095 #, markdown-text, no-wrap msgid "Calling PureScript from JavaScript" msgstr "" #. type: Plain text -#: text/chapter10.md:1096 +#: text/chapter10.md:1098 #, markdown-text msgid "" "Calling a PureScript function from JavaScript is very simple, at least for " @@ -3526,13 +3541,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1098 +#: text/chapter10.md:1100 #, markdown-text msgid "Let's take the following simple module as an example:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1099 +#: text/chapter10.md:1101 #, no-wrap msgid "" "module Test where\n" @@ -3542,11 +3557,11 @@ msgid "" "gcd n 0 = n\n" "gcd n m\n" " | n > m = gcd (n - m) m\n" -" | otherwise = gcd (m - n) n\n" +" | otherwise = gcd (m – n) n\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1111 +#: text/chapter10.md:1113 #, markdown-text msgid "" "This function finds the greatest common divisor of two numbers by repeated " @@ -3558,7 +3573,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1113 +#: text/chapter10.md:1115 #, markdown-text msgid "" "To understand how this function can be called from JavaScript, it is " @@ -3568,7 +3583,7 @@ msgid "" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1114 +#: text/chapter10.md:1116 #, no-wrap msgid "" "import Test from 'Test.js';\n" @@ -3576,17 +3591,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1120 +#: text/chapter10.md:1122 #, markdown-text msgid "" -"Here, I am assuming that the code was compiled with `spago build`, which " -"compiles PureScript modules to ES modules. For that reason, I was able to " -"reference the `gcd` function on the `Test` object, after importing the " -"`Test` module using `import`." +"Here, I assume the code was compiled with `spago build`, which compiles " +"PureScript modules to ES modules. For that reason, I could reference the " +"`gcd` function on the `Test` object, after importing the `Test` module using " +"`import`." msgstr "" #. type: Plain text -#: text/chapter10.md:1122 +#: text/chapter10.md:1124 #, markdown-text msgid "" "You can also use the `spago bundle-app` and `spago bundle-module` commands " @@ -3596,23 +3611,23 @@ msgid "" msgstr "" #. type: Title ### -#: text/chapter10.md:1123 +#: text/chapter10.md:1125 #, markdown-text, no-wrap msgid "Understanding Name Generation" msgstr "" #. type: Plain text -#: text/chapter10.md:1126 +#: text/chapter10.md:1128 #, markdown-text msgid "" "PureScript aims to preserve names during code generation as much as " -"possible. In particular, most identifiers which are neither PureScript nor " +"possible. In particular, most identifiers that are neither PureScript nor " "JavaScript keywords can be expected to be preserved, at least for names of " "top-level declarations." msgstr "" #. type: Plain text -#: text/chapter10.md:1128 +#: text/chapter10.md:1130 #, markdown-text msgid "" "If you decide to use a JavaScript keyword as an identifier, the name will be " @@ -3620,25 +3635,25 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1129 +#: text/chapter10.md:1131 #, no-wrap msgid "null = []\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1134 text/chapter10.md:1146 +#: text/chapter10.md:1136 text/chapter10.md:1148 #, markdown-text -msgid "generates the following JavaScript:" +msgid "Generates the following JavaScript:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1135 +#: text/chapter10.md:1137 #, no-wrap msgid "var $$null = [];\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1140 +#: text/chapter10.md:1142 #, markdown-text msgid "" "In addition, if you would like to use special characters in your identifier " @@ -3646,46 +3661,46 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1141 +#: text/chapter10.md:1143 #, no-wrap msgid "example' = 100\n" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1147 +#: text/chapter10.md:1149 #, no-wrap msgid "var example$prime = 100;\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1152 +#: text/chapter10.md:1154 #, markdown-text msgid "" "Where compiled PureScript code is intended to be called from JavaScript, it " -"is recommended that identifiers only use alphanumeric characters, and avoid " +"is recommended that identifiers only use alphanumeric characters and avoid " "JavaScript keywords. If user-defined operators are provided for use in " "PureScript code, it is good practice to provide an alternative function with " "an alphanumeric name for use in JavaScript." msgstr "" #. type: Title ### -#: text/chapter10.md:1153 +#: text/chapter10.md:1155 #, markdown-text, no-wrap msgid "Runtime Data Representation" msgstr "" #. type: Plain text -#: text/chapter10.md:1156 +#: text/chapter10.md:1158 #, markdown-text msgid "" "Types allow us to reason at compile-time that our programs are \"correct\" " -"in some sense - that is, they will not break at runtime. But what does that " +"in some sense – that is, they will not break at runtime. But what does that " "mean? In PureScript, it means that the type of an expression should be " "compatible with its representation at runtime." msgstr "" #. type: Plain text -#: text/chapter10.md:1158 +#: text/chapter10.md:1160 #, markdown-text msgid "" "For that reason, it is important to understand the representation of data at " @@ -3696,7 +3711,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1160 +#: text/chapter10.md:1162 #, markdown-text msgid "" "The good news is that PureScript expressions have particularly simple " @@ -3705,7 +3720,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1162 +#: text/chapter10.md:1164 #, markdown-text msgid "" "For simple types, the correspondence is almost trivial. For example, if an " @@ -3717,10 +3732,10 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1164 +#: text/chapter10.md:1166 #, markdown-text msgid "" -"A similar law holds for expressions of type `Int`, `Number`, and `String` - " +"A similar law holds for expressions of type `Int`, `Number`, and `String` – " "expressions of type `Int` or `Number` evaluate to non-null JavaScript " "numbers, and expressions of type `String` evaluate to non-null JavaScript " "strings. Expressions of type `Int` will evaluate to integers at runtime, " @@ -3729,45 +3744,44 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1166 +#: text/chapter10.md:1168 #, markdown-text msgid "" "What about `Unit`? Well, since `Unit` has only one inhabitant (`unit`) and " -"its value is not observable, it doesn't actually matter what it's " -"represented with at runtime. Old code tends to represent it using " -"`{}`. Newer code, however, tends to use `undefined`. So, although it doesn't " -"really matter what you use to represent `Unit`, it is recommended to use " -"`undefined` (not returning anything from a function also returns " -"`undefined`)." +"its value is not observable, it doesn't matter what it's represented with at " +"runtime. Old code tends to represent it using `{}`. Newer code, however, " +"tends to use `undefined`. So, although it doesn't matter what you use to " +"represent `Unit`, it is recommended to use `undefined` (not returning " +"anything from a function also returns `undefined`)." msgstr "" #. type: Plain text -#: text/chapter10.md:1168 +#: text/chapter10.md:1170 #, markdown-text msgid "What about some more complex types?" msgstr "" #. type: Plain text -#: text/chapter10.md:1170 +#: text/chapter10.md:1172 #, markdown-text, no-wrap msgid "" "As we have already seen, PureScript functions correspond to JavaScript " "functions of a single argument. More precisely, if an expression `f` has " "type `a -> b` for some types `a` and `b`, and an expression `x` evaluates to " "a value with the correct runtime representation for type `a`, then `f` " -"evaluates to a JavaScript function, which when applied to the result of " +"evaluates to a JavaScript function, which, when applied to the result of " "evaluating `x`, has the correct runtime representation for type `b`. As a " "simple example, an expression of type `String -> String` evaluates to a " -"function which takes non-null JavaScript strings to non-null JavaScript " +"function that takes non-null JavaScript strings to non-null JavaScript " "strings.\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1172 +#: text/chapter10.md:1174 #, markdown-text msgid "" "As you might expect, PureScript's arrays correspond to JavaScript " -"arrays. But remember - PureScript arrays are homogeneous, so every element " +"arrays. But remember – PureScript arrays are homogeneous, so every element " "has the same type. Concretely, if a PureScript expression `e` has type " "`Array a` for some type `a`, then `e` evaluates to a (non-null) JavaScript " "array, all of whose elements have the correct runtime representation for " @@ -3775,52 +3789,52 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1174 +#: text/chapter10.md:1176 #, markdown-text msgid "" "We've already seen that PureScript's records evaluate to JavaScript " -"objects. Just as for functions and arrays, we can reason about the runtime " +"objects. As for functions and arrays, we can reason about the runtime " "representation of data in a record's fields by considering the types " "associated with its labels. Of course, the fields of a record are not " "required to be of the same type." msgstr "" #. type: Title ### -#: text/chapter10.md:1175 +#: text/chapter10.md:1177 #, markdown-text, no-wrap msgid "Representing ADTs" msgstr "" #. type: Plain text -#: text/chapter10.md:1178 +#: text/chapter10.md:1180 #, markdown-text msgid "" "For every constructor of an algebraic data type, the PureScript compiler " "creates a new JavaScript object type by defining a function. Its " -"constructors correspond to functions which create new JavaScript objects " +"constructors correspond to functions that create new JavaScript objects " "based on those prototypes." msgstr "" #. type: Plain text -#: text/chapter10.md:1180 +#: text/chapter10.md:1182 #, markdown-text msgid "For example, consider the following simple ADT:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1181 +#: text/chapter10.md:1183 #, no-wrap msgid "data ZeroOrOne a = Zero | One a\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1186 +#: text/chapter10.md:1188 #, markdown-text msgid "The PureScript compiler generates the following code:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1187 +#: text/chapter10.md:1189 #, no-wrap msgid "" "function One(value0) {\n" @@ -3838,7 +3852,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1203 +#: text/chapter10.md:1205 #, markdown-text msgid "" "Here, we see two JavaScript object types: `Zero` and `One`. It is possible " @@ -3848,7 +3862,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1205 +#: text/chapter10.md:1207 #, markdown-text msgid "" "The PureScript compiler also generates helper functions. For constructors " @@ -3860,29 +3874,29 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1207 +#: text/chapter10.md:1209 #, markdown-text msgid "" "What about constructors with more than one argument? In that case, the " "PureScript compiler also creates a new object type, and a helper " -"function. This time, however, the helper function is curried function of two " -"arguments. For example, this algebraic data type:" +"function. This time, however, the helper function is a curried function of " +"two arguments. For example, this algebraic data type:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1208 +#: text/chapter10.md:1210 #, no-wrap msgid "data Two a b = Two a b\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1213 +#: text/chapter10.md:1215 #, markdown-text -msgid "generates this JavaScript code:" +msgid "Generates this JavaScript code:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1214 +#: text/chapter10.md:1216 #, no-wrap msgid "" "function Two(value0, value1) {\n" @@ -3898,52 +3912,53 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1228 +#: text/chapter10.md:1230 #, markdown-text msgid "" -"Here, values of the object type `Two` can be created using the `new` " -"keyword, or by using the `Two.create` function." +"Here, values of the object type `Two` can be created using the `new` keyword " +"or by using the `Two.create` function." msgstr "" #. type: Plain text -#: text/chapter10.md:1230 +#: text/chapter10.md:1232 #, markdown-text msgid "" "The case of newtypes is slightly different. Recall that a newtype is like an " "algebraic data type, restricted to having a single constructor taking a " "single argument. In this case, the runtime representation of the newtype is " -"actually the same as the type of its argument." +"the same as its argument type." msgstr "" #. type: Plain text -#: text/chapter10.md:1232 +#: text/chapter10.md:1234 #, markdown-text -msgid "For example, this newtype representing telephone numbers:" +msgid "" +"For example, this newtype represents telephone numbers is represented as a " +"JavaScript string at runtime:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1233 +#: text/chapter10.md:1235 #, no-wrap msgid "newtype PhoneNumber = PhoneNumber String\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1238 +#: text/chapter10.md:1240 #, markdown-text msgid "" -"is actually represented as a JavaScript string at runtime. This is useful " -"for designing libraries, since newtypes provide an additional layer of type " -"safety, but without the runtime overhead of another function call." +"This is useful for designing libraries since newtypes provide an additional " +"layer of type safety without the runtime overhead of another function call." msgstr "" #. type: Title ### -#: text/chapter10.md:1239 +#: text/chapter10.md:1241 #, markdown-text, no-wrap msgid "Representing Quantified Types" msgstr "" #. type: Plain text -#: text/chapter10.md:1242 +#: text/chapter10.md:1244 #, markdown-text msgid "" "Expressions with quantified (polymorphic) types have restrictive " @@ -3953,19 +3968,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1244 +#: text/chapter10.md:1246 #, markdown-text msgid "Consider this polymorphic type, for example:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1245 +#: text/chapter10.md:1247 #, no-wrap msgid "forall a. a -> a\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1250 +#: text/chapter10.md:1252 #, markdown-text msgid "" "What sort of functions have this type? Well, there is certainly one function " @@ -3973,7 +3988,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1251 +#: text/chapter10.md:1253 #, no-wrap msgid "" "identity :: forall a. a -> a\n" @@ -3981,7 +3996,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1257 +#: text/chapter10.md:1259 #, markdown-text, no-wrap msgid "" "> Note that the actual " @@ -3990,7 +4005,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1259 +#: text/chapter10.md:1261 #, markdown-text msgid "" "In fact, the `identity` function is the _only_ (total) function with this " @@ -4001,7 +4016,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1261 +#: text/chapter10.md:1263 #, markdown-text, no-wrap msgid "" "What is the runtime representation of a quantified type `forall a. t`? Well, " @@ -4014,19 +4029,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1263 +#: text/chapter10.md:1265 #, markdown-text msgid "" -"But that is not enough - the runtime representation of a quantified type is " +"But that is not enough – the runtime representation of a quantified type is " "more strict than this. We require any expression to be _parametrically " -"polymorphic_ - that is, it cannot use any information about the type of its " +"polymorphic_ – that is, it cannot use any information about the type of its " "argument in its implementation. This additional condition prevents " "problematic implementations such as the following JavaScript function from " "inhabiting a polymorphic type:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1264 +#: text/chapter10.md:1266 #, no-wrap msgid "" "function invalid(a) {\n" @@ -4039,62 +4054,62 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1275 +#: text/chapter10.md:1277 #, markdown-text, no-wrap msgid "" "Certainly, this function takes strings to strings, numbers to numbers, " -"etc. but it does not meet the additional condition, since it inspects the " +"etc. But it does not meet the additional condition, since it inspects the " "(runtime) type of its argument, so this function would not be a valid " "inhabitant of the type `forall a. a -> a`.\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1277 +#: text/chapter10.md:1279 #, markdown-text, no-wrap msgid "" "Without being able to inspect the runtime type of our function argument, our " -"only option is to return the argument unchanged, and so `identity` is indeed " -"the only inhabitant of the type `forall a. a -> a`.\n" +"only option is to return the argument unchanged. So `identity` is indeed the " +"only inhabitant of the type `forall a. a -> a`.\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1279 +#: text/chapter10.md:1281 #, markdown-text msgid "" "A full discussion of _parametric polymorphism_ and _parametricity_ is beyond " -"the scope of this book. Note however, that since PureScript's types are " +"the scope of this book. Note, however, that since PureScript's types are " "_erased_ at runtime, a polymorphic function in PureScript _cannot_ inspect " -"the runtime representation of its arguments (without using the FFI), and so " -"this representation of polymorphic data is appropriate." +"the runtime representation of its arguments (without using the FFI), so this " +"representation of polymorphic data is appropriate." msgstr "" #. type: Title ### -#: text/chapter10.md:1280 +#: text/chapter10.md:1282 #, markdown-text, no-wrap msgid "Representing Constrained Types" msgstr "" #. type: Plain text -#: text/chapter10.md:1283 +#: text/chapter10.md:1285 #, markdown-text msgid "" "Functions with a type class constraint have an interesting representation at " -"runtime. Because the behavior of the function might depend on the type class " +"runtime. Because the function's behavior might depend on the type class " "instance chosen by the compiler, the function is given an additional " "argument, called a _type class dictionary_, which contains the " "implementation of the type class functions provided by the chosen instance." msgstr "" #. type: Plain text -#: text/chapter10.md:1285 +#: text/chapter10.md:1287 #, markdown-text msgid "" "For example, here is a simple PureScript function with a constrained type " -"which uses the `Show` type class:" +"that uses the `Show` type class:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1286 +#: text/chapter10.md:1288 #, no-wrap msgid "" "shout :: forall a. Show a => a -> String\n" @@ -4102,13 +4117,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1292 +#: text/chapter10.md:1294 #, markdown-text msgid "The generated JavaScript looks like this:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1293 +#: text/chapter10.md:1295 #, no-wrap msgid "" "var shout = function (dict) {\n" @@ -4119,7 +4134,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1302 +#: text/chapter10.md:1304 #, markdown-text msgid "" "Notice that `shout` is compiled to a (curried) function of two arguments, " @@ -4129,7 +4144,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1304 +#: text/chapter10.md:1306 #, markdown-text msgid "" "We can call this function from JavaScript by passing an explicit type class " @@ -4137,7 +4152,7 @@ msgid "" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1305 +#: text/chapter10.md:1307 #, no-wrap msgid "" "import { showNumber } from 'Data.Show'\n" @@ -4146,13 +4161,13 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1314 +#: text/chapter10.md:1316 #, markdown-text msgid "(Easy) What are the runtime representations of these types?" msgstr "" #. type: Plain text -#: text/chapter10.md:1320 +#: text/chapter10.md:1322 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4163,7 +4178,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1323 +#: text/chapter10.md:1325 #, markdown-text, no-wrap msgid "" " What can you say about the expressions which have these types?\n" @@ -4175,24 +4190,24 @@ msgid "" msgstr "" #. type: Title ### -#: text/chapter10.md:1324 +#: text/chapter10.md:1326 #, markdown-text, no-wrap msgid "Representing Side Effects" msgstr "" #. type: Plain text -#: text/chapter10.md:1327 +#: text/chapter10.md:1329 #, markdown-text msgid "" "The `Effect` monad is also defined as a foreign type. Its runtime " -"representation is quite simple - an expression of type `Effect a` should " +"representation is quite simple – an expression of type `Effect a` should " "evaluate to a JavaScript function of **no arguments**, which performs any " "side-effects and returns a value with the correct runtime representation for " "type `a`." msgstr "" #. type: Plain text -#: text/chapter10.md:1329 +#: text/chapter10.md:1331 #, markdown-text msgid "" "The definition of the `Effect` type constructor is given in the `Effect` " @@ -4200,13 +4215,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1330 +#: text/chapter10.md:1332 #, no-wrap msgid "foreign import data Effect :: Type -> Type\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1335 +#: text/chapter10.md:1337 #, markdown-text msgid "" "As a simple example, consider the `random` function defined in the `random` " @@ -4214,35 +4229,35 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1336 +#: text/chapter10.md:1338 #, no-wrap msgid "foreign import random :: Effect Number\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1341 +#: text/chapter10.md:1343 #, markdown-text msgid "The definition of the `random` function is given here:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1342 +#: text/chapter10.md:1344 #, no-wrap msgid "export const random = Math.random;\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1347 +#: text/chapter10.md:1349 #, markdown-text msgid "" "Notice that the `random` function is represented at runtime as a function of " -"no arguments. It performs the side effect of generating a random number, and " +"no arguments. It performs the side effect of generating a random number, " "returns it, and the return value matches the runtime representation of the " "`Number` type: it is a non-null JavaScript number." msgstr "" #. type: Plain text -#: text/chapter10.md:1349 +#: text/chapter10.md:1351 #, markdown-text msgid "" "As a slightly more interesting example, consider the `log` function defined " @@ -4251,19 +4266,19 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter10.md:1350 +#: text/chapter10.md:1352 #, no-wrap msgid "foreign import log :: String -> Effect Unit\n" msgstr "" #. type: Plain text -#: text/chapter10.md:1355 +#: text/chapter10.md:1357 #, markdown-text msgid "And here is its definition:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1356 +#: text/chapter10.md:1358 #, no-wrap msgid "" "export const log = function (s) {\n" @@ -4274,7 +4289,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1365 +#: text/chapter10.md:1367 #, markdown-text msgid "" "The representation of `log` at runtime is a JavaScript function of a single " @@ -4283,7 +4298,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1367 +#: text/chapter10.md:1369 #, markdown-text msgid "" "Expressions of type `Effect a` can be invoked from JavaScript like regular " @@ -4292,7 +4307,7 @@ msgid "" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter10.md:1368 +#: text/chapter10.md:1370 #, no-wrap msgid "" "import { main } from 'Main'\n" @@ -4301,11 +4316,11 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:1374 +#: text/chapter10.md:1376 #, markdown-text msgid "" "When using `spago bundle-app --to` or `spago run`, this call to `main` is " -"generated automatically, whenever the `Main` module is defined." +"generated automatically whenever the `Main` module is defined." msgstr "" #. type: Title # @@ -4320,7 +4335,7 @@ msgstr "" msgid "" "The goal of this chapter will be to learn about _monad transformers_, which " "provide a way to combine side-effects provided by different monads. The " -"motivating example will be a text adventure game which can be played on the " +"motivating example will be a text adventure game that can be played on the " "console in NodeJS. The various side-effects of the game (logging, state, and " "configuration) will all be provided by a monad transformer stack." msgstr "" @@ -4358,7 +4373,7 @@ msgstr "" #: text/chapter11.md:15 #, markdown-text msgid "" -"`optparse`, which provides applicative parsers for processing command line " +"`optparse`, which provides applicative parsers for processing command-line " "arguments" msgstr "" @@ -4377,7 +4392,7 @@ msgstr "" #. type: Plain text #: text/chapter11.md:21 #, markdown-text -msgid "By default you will see a usage message:" +msgid "By default, you will see a usage message:" msgstr "" #. type: Fenced code block (text) @@ -4397,23 +4412,23 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:35 -#, markdown-text, no-wrap +#: text/chapter11.md:36 +#, markdown-text msgid "" "To provide command line arguments, you can either call `spago run` with the " -"`-a` option to pass additional arguments directly to your application, or " -"you can call `spago bundle-app`, which will create an index.js file that can " -"be run directly with `node`. \n" +"`-a` option to pass additional arguments directly to your application or " +"call `spago bundle-app`, which will create an index.js file that can be run " +"directly with `node`." msgstr "" #. type: Plain text -#: text/chapter11.md:37 +#: text/chapter11.md:38 #, markdown-text msgid "For example, to provide the player name using the `-p` option:" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:38 +#: text/chapter11.md:39 #, no-wrap msgid "" "$ spago run -a \"-p Phil\"\n" @@ -4421,7 +4436,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:43 +#: text/chapter11.md:44 #, no-wrap msgid "" "$ spago bundle-app \n" @@ -4430,34 +4445,34 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:50 +#: text/chapter11.md:51 #, markdown-text msgid "" "From the prompt, you can enter commands like `look`, `inventory`, `take`, " "`use`, `north`, `south`, `east`, and `west`. There is also a `debug` " -"command, which can be used to print the game state when the `--debug` " -"command line option is provided." +"command, which can print the game state when the `--debug` command line " +"option is provided." msgstr "" #. type: Plain text -#: text/chapter11.md:52 +#: text/chapter11.md:53 #, markdown-text msgid "" "The game is played on a two-dimensional grid, and the player moves by " "issuing commands `north`, `south`, `east`, and `west`. The game contains a " -"collection of items which can either be in the player's possession (in the " -"user's _inventory_), or on the game grid at some location. Items can be " -"picked up by the player, using the `take` command." +"collection of items that can either be in the player's possession (in the " +"user's _inventory_) or on the game grid at some location. Items can be " +"picked up by the player using the `take` command." msgstr "" #. type: Plain text -#: text/chapter11.md:54 +#: text/chapter11.md:55 #, markdown-text msgid "For reference, here is a complete walkthrough of the game:" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:55 +#: text/chapter11.md:56 #, no-wrap msgid "" "$ spago run -a \"-p Phil\"\n" @@ -4490,22 +4505,22 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:86 +#: text/chapter11.md:87 #, markdown-text msgid "" "The game is very simple, but the aim of the chapter is to use the " -"`transformers` package to build a library which will enable rapid " -"development of this type of game." +"`transformers` package to build a library that will enable rapid development " +"of this type of game." msgstr "" #. type: Title ## -#: text/chapter11.md:87 +#: text/chapter11.md:88 #, markdown-text, no-wrap msgid "The State Monad" msgstr "" #. type: Plain text -#: text/chapter11.md:90 +#: text/chapter11.md:91 #, markdown-text msgid "" "We will start by looking at some of the monads provided by the " @@ -4513,32 +4528,32 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:92 +#: text/chapter11.md:93 #, markdown-text msgid "" "The first example is the `State` monad, which provides a way to model " -"_mutable state_ in pure code. We have already seen an approach to mutable " +"_mutable state_ in pure code. We have already seen an approach to a mutable " "state provided by the `Effect` monad. `State` provides an alternative." msgstr "" #. type: Plain text -#: text/chapter11.md:94 +#: text/chapter11.md:95 #, markdown-text msgid "" "The `State` type constructor takes two type parameters: the type `s` of the " -"state, and the return type `a`. Even though we speak of the \"`State` " +"state and the return type `a`. Even though we speak of the \"`State` " "monad\", the instance of the `Monad` type class is actually provided for the " -"`State s` type constructor, for any type `s`." +"`State s` type constructor for any type `s`." msgstr "" #. type: Plain text -#: text/chapter11.md:96 +#: text/chapter11.md:97 #, markdown-text msgid "The `Control.Monad.State` module provides the following API:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:97 +#: text/chapter11.md:98 #, no-wrap msgid "" "get :: forall s. State s s\n" @@ -4549,27 +4564,28 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:106 +#: text/chapter11.md:107 #, markdown-text msgid "" "Note that these API signatures are presented in a simplified form using the " -"`State` type constructor for now. The actual API involves `MonadState` which " -"we'll cover in the later \"Type Classes\" section of this chapter, so don't " -"worry if you see different signatures in your IDE tooltips or on Pursuit." +"`State` type constructor for now. The actual API involves `MonadState`, " +"which we'll cover in the later \"Type Classes\" section of this chapter, so " +"don't worry if you see different signatures in your IDE tooltips or on " +"Pursuit." msgstr "" #. type: Plain text -#: text/chapter11.md:108 +#: text/chapter11.md:109 #, markdown-text msgid "" "Let's see an example. One use of the `State` monad might be to add the " "values in an array of integers to the current state. We could do that by " -"choosing `Int` as the state type `s`, and using `traverse_` to traverse the " +"choosing `Int` as the state type `s` and using `traverse_` to traverse the " "array, with a call to `modify` for each array element:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:109 +#: text/chapter11.md:110 #, no-wrap msgid "" "import Data.Foldable (traverse_)\n" @@ -4581,7 +4597,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:119 +#: text/chapter11.md:120 #, markdown-text msgid "" "The `Control.Monad.State` module provides three functions for running a " @@ -4589,7 +4605,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:120 +#: text/chapter11.md:121 #, no-wrap msgid "" "evalState :: forall s a. State s a -> s -> a\n" @@ -4598,17 +4614,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:127 +#: text/chapter11.md:128 #, markdown-text msgid "" -"Each of these functions takes an initial state of type `s` and a computation " -"of type `State s a`. `evalState` only returns the return value, `execState` " -"only returns the final state, and `runState` returns both, expressed as a " -"value of type `Tuple a s`." +"Each function takes an initial state of type `s` and a computation of type " +"`State s a`. `evalState` only returns the return value, `execState` only " +"returns the final state, and `runState` returns both, expressed as a value " +"of type `Tuple a s`." msgstr "" #. type: Plain text -#: text/chapter11.md:129 +#: text/chapter11.md:130 #, markdown-text msgid "" "Given the `sumArray` function above, we could use `execState` in PSCi to sum " @@ -4616,7 +4632,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:130 +#: text/chapter11.md:131 #, no-wrap msgid "" "> :paste\n" @@ -4636,14 +4652,13 @@ msgid "" "`evalState` in our example above?" msgstr "" -#. type: Plain text +#. type: Bullet: ' 1. ' #: text/chapter11.md:145 -#, markdown-text, no-wrap +#, markdown-text msgid "" -" 1. (Medium) A string of parentheses is _balanced_ if it is obtained by " -"either concatenating zero-or-more shorter balanced\n" -" strings, or by wrapping a shorter balanced string in a pair of " -"parentheses.\n" +"(Medium) A string of parentheses is _balanced_ if it is obtained by either " +"concatenating zero-or-more shorter balanced strings or wrapping a shorter " +"balanced string in a pair of parentheses." msgstr "" #. type: Plain text @@ -4664,16 +4679,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:154 +#: text/chapter11.md:153 #, markdown-text, no-wrap msgid "" -" which tests whether or not a `String` of parentheses is balanced, by " -"keeping track of the number of opening parentheses\n" -" which have not been closed. Your function should work as follows:\n" +" which tests whether or not a `String` of parentheses is balanced by " +"keeping track of the number of opening parentheses that have not been " +"closed. Your function should work as follows:\n" msgstr "" #. type: Plain text -#: text/chapter11.md:158 +#: text/chapter11.md:157 #, markdown-text, no-wrap msgid "" " ```text\n" @@ -4682,7 +4697,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:161 +#: text/chapter11.md:160 #, markdown-text, no-wrap msgid "" " > testParens \"(()(())())\"\n" @@ -4690,7 +4705,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:164 +#: text/chapter11.md:163 #, markdown-text, no-wrap msgid "" " > testParens \")\"\n" @@ -4698,7 +4713,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:168 +#: text/chapter11.md:167 #, markdown-text, no-wrap msgid "" " > testParens \"(()()\"\n" @@ -4707,7 +4722,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:170 +#: text/chapter11.md:169 #, markdown-text, no-wrap msgid "" " _Hint_: you may like to use the `toCharArray` function from the " @@ -4716,13 +4731,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter11.md:171 +#: text/chapter11.md:170 #, markdown-text, no-wrap msgid "The Reader Monad" msgstr "" #. type: Plain text -#: text/chapter11.md:174 +#: text/chapter11.md:173 #, markdown-text msgid "" "Another monad provided by the `transformers` package is the `Reader` " @@ -4733,7 +4748,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:176 +#: text/chapter11.md:175 #, markdown-text msgid "" "The `Reader` type constructor takes two type arguments: a type `r` which " @@ -4741,13 +4756,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:178 +#: text/chapter11.md:177 #, markdown-text msgid "The `Control.Monad.Reader` module provides the following API:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:179 +#: text/chapter11.md:178 #, no-wrap msgid "" "ask :: forall r. Reader r r\n" @@ -4755,7 +4770,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:185 +#: text/chapter11.md:184 #, markdown-text msgid "" "The `ask` action can be used to read the current configuration, and the " @@ -4764,7 +4779,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:187 +#: text/chapter11.md:186 #, markdown-text msgid "" "For example, suppose we were developing an application controlled by " @@ -4774,7 +4789,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:188 +#: text/chapter11.md:187 #, no-wrap msgid "" "hasPermission :: String -> Permissions -> Boolean\n" @@ -4782,7 +4797,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:194 +#: text/chapter11.md:193 #, markdown-text msgid "" "Whenever we wanted to check if the user had a particular permission, we " @@ -4791,7 +4806,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:195 +#: text/chapter11.md:194 #, no-wrap msgid "" "createUser :: Reader Permissions (Maybe User)\n" @@ -4803,7 +4818,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:205 +#: text/chapter11.md:204 #, markdown-text msgid "" "To elevate the user's permissions, we might use the `local` action to modify " @@ -4811,7 +4826,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:206 +#: text/chapter11.md:205 #, no-wrap msgid "" "runAsAdmin :: forall a. Reader Permissions a -> Reader Permissions a\n" @@ -4819,7 +4834,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:212 +#: text/chapter11.md:211 #, markdown-text msgid "" "Then we could write a function to create a new user, even if the user did " @@ -4827,7 +4842,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:213 +#: text/chapter11.md:212 #, no-wrap msgid "" "createUserAsAdmin :: Reader Permissions (Maybe User)\n" @@ -4835,7 +4850,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:219 +#: text/chapter11.md:218 #, markdown-text msgid "" "To run a computation in the `Reader` monad, the `runReader` function can be " @@ -4843,13 +4858,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:220 +#: text/chapter11.md:219 #, no-wrap msgid "runReader :: forall r a. Reader r a -> r -> a\n" msgstr "" #. type: Plain text -#: text/chapter11.md:227 +#: text/chapter11.md:226 #, markdown-text, no-wrap msgid "" " In these exercises, we will use the `Reader` monad to build a small library " @@ -4858,7 +4873,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:228 +#: text/chapter11.md:227 #, no-wrap msgid "" "type Level = Int\n" @@ -4867,15 +4882,15 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:235 +#: text/chapter11.md:234 #, markdown-text msgid "" -"(Easy) Write a function `line` which renders a function at the current " +"(Easy) Write a function `line` that renders a function at the current " "indentation level. Your function should have the following type:" msgstr "" #. type: Plain text -#: text/chapter11.md:239 +#: text/chapter11.md:238 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4884,7 +4899,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:242 +#: text/chapter11.md:241 #, markdown-text, no-wrap msgid "" " _Hint_: use the `ask` function to read the current indentation " @@ -4893,7 +4908,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:246 +#: text/chapter11.md:245 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4902,7 +4917,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:249 +#: text/chapter11.md:248 #, markdown-text, no-wrap msgid "" " which increases the indentation level for a block of code.\n" @@ -4911,7 +4926,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:253 +#: text/chapter11.md:252 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4920,7 +4935,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:256 +#: text/chapter11.md:255 #, markdown-text, no-wrap msgid "" " which concatenates a collection of documents, separating them with new " @@ -4929,7 +4944,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:260 +#: text/chapter11.md:259 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4938,21 +4953,21 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:262 +#: text/chapter11.md:261 #, markdown-text, no-wrap msgid " which renders a document as a String.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:264 +#: text/chapter11.md:263 #, markdown-text, no-wrap msgid "" -" You should now be able to use your library to write simple documents, as " +" You should now be able to use your library to write simple documents as " "follows:\n" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:265 +#: text/chapter11.md:264 #, no-wrap msgid "" " render $ cat\n" @@ -4966,53 +4981,52 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter11.md:276 +#: text/chapter11.md:275 #, markdown-text, no-wrap msgid "The Writer Monad" msgstr "" #. type: Plain text -#: text/chapter11.md:279 +#: text/chapter11.md:278 #, markdown-text msgid "" -"The `Writer` monad provides the ability to accumulate a secondary value in " -"addition to the return value of a computation." +"The `Writer` monad allows accumulating a secondary value in addition to the " +"return value of a computation." msgstr "" #. type: Plain text -#: text/chapter11.md:281 +#: text/chapter11.md:280 #, markdown-text msgid "" "A common use case is to accumulate a log of type `String` or `Array String`, " -"but the `Writer` monad is more general than this. It can actually be used to " -"accumulate a value in any monoid, so it might be used to keep track of an " -"integer total using the `Additive Int` monoid, or to track whether any of " -"several intermediate `Boolean` values were true, using the `Disj Boolean` " -"monoid." +"but the `Writer` monad is more general than this. It can accumulate a value " +"in any monoid, so it might be used to keep track of an integer total using " +"the `Additive Int` monoid or to track whether any of several intermediate " +"`Boolean` values were true using the `Disj Boolean` monoid." msgstr "" #. type: Plain text -#: text/chapter11.md:283 +#: text/chapter11.md:282 #, markdown-text msgid "" -"The `Writer` type constructor takes two type arguments: a type `w` which " +"The `Writer` type constructor takes two type arguments: a type `w` that " "should be an instance of the `Monoid` type class, and the return type `a`." msgstr "" #. type: Plain text -#: text/chapter11.md:285 +#: text/chapter11.md:284 #, markdown-text msgid "The key element of the `Writer` API is the `tell` function:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:286 +#: text/chapter11.md:285 #, no-wrap msgid "tell :: forall w a. Monoid w => w -> Writer w Unit\n" msgstr "" #. type: Plain text -#: text/chapter11.md:291 +#: text/chapter11.md:290 #, markdown-text msgid "" "The `tell` action appends the provided value to the current accumulated " @@ -5020,16 +5034,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:293 +#: text/chapter11.md:292 #, markdown-text msgid "" -"As an example, let's add a log to an existing function by using the `Array " +"As an example, let's add a log to an existing function using the `Array " "String` monoid. Consider our previous implementation of the _greatest common " "divisor_ function:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:294 +#: text/chapter11.md:293 #, no-wrap msgid "" "gcd :: Int -> Int -> Int\n" @@ -5041,7 +5055,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:304 +#: text/chapter11.md:303 #, markdown-text msgid "" "We could add a log to this function by changing the return type to `Writer " @@ -5049,7 +5063,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:305 +#: text/chapter11.md:304 #, no-wrap msgid "" "import Control.Monad.Writer\n" @@ -5059,7 +5073,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:313 +#: text/chapter11.md:312 #, markdown-text msgid "" "We only have to change our function slightly to log the two inputs at each " @@ -5067,7 +5081,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:314 +#: text/chapter11.md:313 #, no-wrap msgid "" " gcdLog n 0 = pure n\n" @@ -5080,7 +5094,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:325 +#: text/chapter11.md:324 #, markdown-text msgid "" "We can run a computation in the `Writer` monad by using either of the " @@ -5088,7 +5102,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:326 +#: text/chapter11.md:325 #, no-wrap msgid "" "execWriter :: forall w a. Writer w a -> w\n" @@ -5096,7 +5110,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:332 +#: text/chapter11.md:331 #, markdown-text msgid "" "Just like in the case of the `State` monad, `execWriter` only returns the " @@ -5104,13 +5118,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:334 +#: text/chapter11.md:333 #, markdown-text msgid "We can test our modified function in PSCi:" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:335 +#: text/chapter11.md:334 #, no-wrap msgid "" "> import Control.Monad.Writer\n" @@ -5122,7 +5136,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:347 +#: text/chapter11.md:346 #, markdown-text msgid "" "(Medium) Rewrite the `sumArray` function above using the `Writer` monad and " @@ -5130,16 +5144,16 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:347 +#: text/chapter11.md:346 #, markdown-text msgid "" "(Medium) The _Collatz_ function is defined on natural numbers `n` as `n / 2` " -"when `n` is even, and `3 * n + 1` when `n` is odd. For example, the iterated " +"when `n` is even and `3 * n + 1` when `n` is odd. For example, the iterated " "Collatz sequence starting at `10` is as follows:" msgstr "" #. type: Plain text -#: text/chapter11.md:351 +#: text/chapter11.md:350 #, markdown-text, no-wrap msgid "" " ```text\n" @@ -5148,7 +5162,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:353 +#: text/chapter11.md:352 #, markdown-text, no-wrap msgid "" " It is conjectured that the iterated Collatz sequence always reaches `1` " @@ -5156,15 +5170,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:355 +#: text/chapter11.md:354 #, markdown-text, no-wrap msgid "" -" Write a function which uses recursion to calculate how many iterations " +" Write a function that uses recursion to calculate how many iterations " "of the Collatz function are required before the sequence reaches `1`.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:357 +#: text/chapter11.md:356 #, markdown-text, no-wrap msgid "" " Modify your function to use the `Writer` monad to log each application " @@ -5172,22 +5186,22 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter11.md:358 +#: text/chapter11.md:357 #, markdown-text, no-wrap msgid "Monad Transformers" msgstr "" #. type: Plain text -#: text/chapter11.md:361 +#: text/chapter11.md:360 #, markdown-text msgid "" -"Each of the three monads above: `State`, `Reader` and `Writer`, are also " +"Each of the three monads above: `State`, `Reader`, and `Writer`, are also " "examples of so-called _monad transformers_. The equivalent monad " -"transformers are called `StateT`, `ReaderT`, and `WriterT` respectively." +"transformers are called `StateT`, `ReaderT`, and `WriterT`, respectively." msgstr "" #. type: Plain text -#: text/chapter11.md:363 +#: text/chapter11.md:362 #, markdown-text msgid "" "What is a monad transformer? Well, as we have seen, a monad augments " @@ -5203,25 +5217,25 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:365 +#: text/chapter11.md:364 #, markdown-text msgid "" -"Note that we have already seen that the `Effect` monad provides a partial " -"solution to this problem. Monad transformers provide another solution, and " -"each approach has its own benefits and limitations." +"Note that we have already seen that the `Effect` monad partially solves this " +"problem. Monad transformers provide another solution, and each approach has " +"its own benefits and limitations." msgstr "" #. type: Plain text -#: text/chapter11.md:367 +#: text/chapter11.md:366 #, markdown-text msgid "" -"A monad transformer is a type constructor which is parameterized not only by " -"a type, but by another type constructor. It takes one monad and turns it " -"into another monad, adding its own variety of side-effects." +"A monad transformer is a type constructor parameterized by a type and " +"another type constructor. It takes one monad and turns it into another " +"monad, adding its own variety of side-effects." msgstr "" #. type: Plain text -#: text/chapter11.md:369 +#: text/chapter11.md:368 #, markdown-text msgid "" "Let's see an example. The monad transformer version of the `State` monad is " @@ -5230,7 +5244,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:370 +#: text/chapter11.md:369 #, no-wrap msgid "" "> import Control.Monad.State.Trans\n" @@ -5239,7 +5253,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:377 +#: text/chapter11.md:376 #, markdown-text msgid "" "This looks quite confusing, but we can apply `StateT` one argument at a time " @@ -5247,7 +5261,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:379 +#: text/chapter11.md:378 #, markdown-text msgid "" "The first type argument is the type of the state we wish to use, as was the " @@ -5255,7 +5269,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:380 +#: text/chapter11.md:379 #, no-wrap msgid "" "> :kind StateT String\n" @@ -5263,7 +5277,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:386 +#: text/chapter11.md:385 #, markdown-text, no-wrap msgid "" "The next argument is a type constructor of kind `Type -> Type`. It " @@ -5273,7 +5287,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:387 +#: text/chapter11.md:386 #, no-wrap msgid "" "> :kind StateT String (Either String)\n" @@ -5281,7 +5295,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:393 +#: text/chapter11.md:392 #, markdown-text msgid "" "We are left with a type constructor. The final argument represents the " @@ -5289,7 +5303,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:394 +#: text/chapter11.md:393 #, no-wrap msgid "" "> :kind StateT String (Either String) Number\n" @@ -5297,34 +5311,34 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:400 +#: text/chapter11.md:399 #, markdown-text msgid "" -"Finally we are left with something of kind `Type`, which means we can try to " -"find values of this type." +"Finally, we are left with something of kind `Type`, which means we can try " +"to find values of this type." msgstr "" #. type: Plain text -#: text/chapter11.md:402 +#: text/chapter11.md:401 #, markdown-text msgid "" -"The monad we have constructed - `StateT String (Either String)` - represents " -"computations which can fail with an error, and which can use mutable state." +"The monad we have constructed – `StateT String (Either String)` – represents " +"computations that can fail with an error and use mutable state." msgstr "" #. type: Plain text -#: text/chapter11.md:404 +#: text/chapter11.md:403 #, markdown-text msgid "" "We can use the actions of the outer `StateT String` monad (`get`, `put`, and " -"`modify`) directly, but in order to use the effects of the wrapped monad " -"(`Either String`), we need to \"lift\" them over the monad transformer. The " +"`modify`) directly, but to use the effects of the wrapped monad (`Either " +"String`), we need to \"lift\" them over the monad transformer. The " "`Control.Monad.Trans` module defines the `MonadTrans` type class, which " "captures those type constructors which are monad transformers, as follows:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:405 +#: text/chapter11.md:404 #, no-wrap msgid "" "class MonadTrans t where\n" @@ -5332,12 +5346,12 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:411 +#: text/chapter11.md:410 #, markdown-text msgid "" "This class contains a single member, `lift`, which takes computations in any " "underlying monad `m` and lifts them into the wrapped monad `t m`. In our " -"case, the type constructor `t` is `StateT String`, and `m` is the `Either " +"case, the type constructor `t` is `StateT String`, `m` is the `Either " "String` monad, so `lift` provides a way to lift computations of type `Either " "String a` to computations of type `StateT String (Either String) a`. This " "means that we can use the effects of `StateT String` and `Either String` " @@ -5346,15 +5360,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:413 +#: text/chapter11.md:412 #, markdown-text msgid "" -"For example, the following computation reads the underlying state, and then " +"For example, the following computation reads the underlying state and then " "throws an error if the state is the empty string:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:414 +#: text/chapter11.md:413 #, no-wrap msgid "" "import Data.String (drop, take)\n" @@ -5370,22 +5384,22 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:428 +#: text/chapter11.md:427 #, markdown-text msgid "" "If the state is not empty, the computation uses `put` to update the state to " -"`drop 1 s` (that is, `s` with the first character removed), and returns " -"`take 1 s` (that is, the first character of `s`)." +"`drop 1 s` (that is, `s` with the first character removed) and returns `take " +"1 s` (that is, the first character of `s`)." msgstr "" #. type: Plain text -#: text/chapter11.md:430 +#: text/chapter11.md:429 #, markdown-text msgid "Let's try this in PSCi:" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:431 +#: text/chapter11.md:430 #, no-wrap msgid "" "> runStateT split \"test\"\n" @@ -5396,10 +5410,10 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:440 +#: text/chapter11.md:439 #, markdown-text msgid "" -"This is not very remarkable, since we could have implemented this without " +"This is not very remarkable since we could have implemented this without " "`StateT`. However, since we are working in a monad, we can use do notation " "or applicative combinators to build larger computations from smaller " "ones. For example, we can apply `split` twice to read the first two " @@ -5407,7 +5421,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:441 +#: text/chapter11.md:440 #, no-wrap msgid "" "> runStateT ((<>) <$> split <*> split) \"test\"\n" @@ -5415,34 +5429,32 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:447 +#: text/chapter11.md:446 #, markdown-text msgid "" "We can use the `split` function with a handful of other actions to build a " "basic parsing library. In fact, this is the approach taken by the `parsing` " -"library. This is the power of monad transformers - we can create " -"custom-built monads for a variety of problems, choosing the side-effects " -"that we need, and keeping the expressiveness of do notation and applicative " -"combinators." +"library. This is the power of monad transformers – we can create " +"custom-built monads for various problems, choose the side-effects we need, " +"and keep the expressiveness of do notation and applicative combinators." msgstr "" #. type: Title ## -#: text/chapter11.md:448 +#: text/chapter11.md:447 #, markdown-text, no-wrap msgid "The ExceptT Monad Transformer" msgstr "" #. type: Plain text -#: text/chapter11.md:451 +#: text/chapter11.md:450 #, markdown-text msgid "" "The `transformers` package also defines the `ExceptT e` monad transformer, " -"which is the transformer corresponding to the `Either e` monad. It provides " -"the following API:" +"corresponding to the `Either e` monad. It provides the following API:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:452 +#: text/chapter11.md:451 #, no-wrap msgid "" "class MonadError e m where\n" @@ -5455,18 +5467,18 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:463 +#: text/chapter11.md:462 #, markdown-text msgid "" -"The `MonadError` class captures those monads which support throwing and " -"catching of errors of some type `e`, and an instance is provided for the " -"`ExceptT e` monad transformer. The `throwError` action can be used to " -"indicate failure, just like `Left` in the `Either e` monad. The `catchError` " -"action allows us to continue after an error is thrown using `throwError`." +"The `MonadError` class captures those monads that support throwing and " +"catching errors of some type `e`, and an instance is provided for the " +"`ExceptT e` monad transformer. The `throwError` action can indicate failure, " +"like `Left` in the `Either e` monad. The `catchError` action allows us to " +"continue after an error is thrown using `throwError`." msgstr "" #. type: Plain text -#: text/chapter11.md:465 +#: text/chapter11.md:464 #, markdown-text msgid "" "The `runExceptT` handler is used to run a computation of type `ExceptT e m " @@ -5474,7 +5486,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:467 +#: text/chapter11.md:466 #, markdown-text msgid "" "This API is similar to that provided by the `exceptions` package and the " @@ -5482,7 +5494,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter11.md:470 +#: text/chapter11.md:469 #, markdown-text msgid "" "`Exception` uses actual JavaScript exceptions, whereas `ExceptT` models " @@ -5490,7 +5502,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter11.md:470 +#: text/chapter11.md:469 #, markdown-text msgid "" "The `Exception` effect only supports exceptions of one type, namely " @@ -5499,7 +5511,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:472 +#: text/chapter11.md:471 #, markdown-text msgid "" "Let's try out `ExceptT` by using it to wrap the `Writer` monad. Again, we " @@ -5508,7 +5520,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:473 +#: text/chapter11.md:472 #, no-wrap msgid "" "import Control.Monad.Except\n" @@ -5523,7 +5535,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:486 +#: text/chapter11.md:485 #, markdown-text msgid "" "If we test this function in PSCi, we can see how the two effects of " @@ -5534,7 +5546,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:487 +#: text/chapter11.md:486 #, no-wrap msgid "" "> runWriter $ runExceptT writerAndExceptT\n" @@ -5542,56 +5554,56 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:493 +#: text/chapter11.md:492 #, markdown-text msgid "" -"Note that only those log messages which were written before the error was " -"thrown actually get appended to the log." +"Note that only those log messages that were written before the error was " +"thrown get appended to the log." msgstr "" #. type: Title ## -#: text/chapter11.md:494 +#: text/chapter11.md:493 #, markdown-text, no-wrap msgid "Monad Transformer Stacks" msgstr "" #. type: Plain text -#: text/chapter11.md:497 +#: text/chapter11.md:496 #, markdown-text msgid "" "As we have seen, monad transformers can be used to build new monads on top " "of existing monads. For some monad transformer `t1` and some monad `m`, the " -"application `t1 m` is also a monad. That means that we can apply a _second_ " -"monad transformer `t2` to the result `t1 m` to construct a third monad `t2 " -"(t1 m)`. In this way, we can construct a _stack_ of monad transformers, " -"which combine the side-effects provided by their constituent monads." +"application `t1 m` is also a monad. That means we can apply a _second_ monad " +"transformer `t2` to the result `t1 m` to construct a third monad `t2 (t1 " +"m)`. In this way, we can construct a _stack_ of monad transformers, which " +"combine the side-effects provided by their constituent monads." msgstr "" #. type: Plain text -#: text/chapter11.md:499 +#: text/chapter11.md:498 #, markdown-text msgid "" "In practice, the underlying monad `m` is either the `Effect` monad, if " "native side-effects are required, or the `Identity` monad, defined in the " "`Data.Identity` module. The `Identity` monad adds no new side-effects, so " "transforming the `Identity` monad only provides the effects of the monad " -"transformer. In fact, the `State`, `Reader` and `Writer` monads are " -"implemented by transforming the `Identity` monad with `StateT`, `ReaderT` " -"and `WriterT` respectively." +"transformer. The `State`, `Reader`, and `Writer` monads are implemented by " +"transforming the `Identity` monad with `StateT`, `ReaderT`, and `WriterT`, " +"respectively." msgstr "" #. type: Plain text -#: text/chapter11.md:501 +#: text/chapter11.md:500 #, markdown-text msgid "" "Let's see an example in which three side effects are combined. We will use " -"the `StateT`, `WriterT` and `ExceptT` effects, with the `Identity` monad on " +"the `StateT`, `WriterT`, and `ExceptT` effects, with the `Identity` monad on " "the bottom of the stack. This monad transformer stack will provide the side " "effects of mutable state, accumulating a log, and pure errors." msgstr "" #. type: Plain text -#: text/chapter11.md:503 +#: text/chapter11.md:502 #, markdown-text msgid "" "We can use this monad transformer stack to reproduce our `split` action with " @@ -5599,7 +5611,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:504 +#: text/chapter11.md:503 #, no-wrap msgid "" "type Errors = Array String\n" @@ -5620,7 +5632,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:523 +#: text/chapter11.md:522 #, markdown-text msgid "" "If we test this computation in PSCi, we see that the state is appended to " @@ -5628,18 +5640,18 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:525 +#: text/chapter11.md:524 #, markdown-text msgid "" "Note that we have to remove the side-effects in the order in which they " -"appear in the monad transformer stack: first we use `runStateT` to remove " +"appear in the monad transformer stack: first, we use `runStateT` to remove " "the `StateT` type constructor, then `runWriterT`, then " "`runExceptT`. Finally, we run the computation in the `Identity` monad by " "using `unwrap`." msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:526 +#: text/chapter11.md:525 #, no-wrap msgid "" "> runParser p s = unwrap $ runExceptT $ runWriterT $ runStateT p s\n" @@ -5653,7 +5665,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:537 +#: text/chapter11.md:536 #, markdown-text msgid "" "However, if the parse is unsuccessful because the state is empty, then no " @@ -5661,7 +5673,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:538 +#: text/chapter11.md:537 #, no-wrap msgid "" "> runParser split \"\"\n" @@ -5669,31 +5681,31 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:544 +#: text/chapter11.md:543 #, markdown-text msgid "" -"This is because of the way in which the side-effects provided by the " -"`ExceptT` monad transformer interact with the side-effects provided by the " -"`WriterT` monad transformer. We can address this by changing the order in " -"which the monad transformer stack is composed. If we move the `ExceptT` " -"transformer to the top of the stack, then the log will contain all messages " -"written up until the first error, as we saw earlier when we transformed " -"`Writer` with `ExceptT`." +"This is because of how the side-effects provided by the `ExceptT` monad " +"transformer interact with the side-effects provided by the `WriterT` monad " +"transformer. We can address this by changing the order in which the monad " +"transformer stack is composed. If we move the `ExceptT` transformer to the " +"top of the stack, then the log will contain all messages written up until " +"the first error, as we saw earlier when we transformed `Writer` with " +"`ExceptT`." msgstr "" #. type: Plain text -#: text/chapter11.md:546 +#: text/chapter11.md:545 #, markdown-text msgid "" "One problem with this code is that we have to use the `lift` function " -"multiple times to lift computations over multiple monad transformers: for " +"multiple times to lift computations over multiple monad transformers; for " "example, the call to `throwError` has to be lifted twice, once over " "`WriterT` and a second time over `StateT`. This is fine for small monad " -"transformer stacks, but quickly becomes inconvenient." +"transformer stacks but quickly becomes inconvenient." msgstr "" #. type: Plain text -#: text/chapter11.md:548 +#: text/chapter11.md:547 #, markdown-text msgid "" "Fortunately, as we will see, we can use the automatic code generation " @@ -5702,7 +5714,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:553 +#: text/chapter11.md:552 #, markdown-text msgid "" "(Easy) Use the `ExceptT` monad transformer over the `Identity` functor to " @@ -5711,13 +5723,13 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:553 +#: text/chapter11.md:552 #, markdown-text msgid "(Medium) Write a parser" msgstr "" #. type: Plain text -#: text/chapter11.md:557 +#: text/chapter11.md:556 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -5726,21 +5738,21 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:559 +#: text/chapter11.md:558 #, markdown-text, no-wrap msgid "" -" which matches a string as a prefix of the current state, or fails with " +" which matches a string as a prefix of the current state or fails with " "an error message.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:561 +#: text/chapter11.md:560 #, markdown-text, no-wrap msgid " Your parser should work as follows:\n" msgstr "" #. type: Plain text -#: text/chapter11.md:566 +#: text/chapter11.md:565 #, markdown-text, no-wrap msgid "" " ```text\n" @@ -5750,18 +5762,18 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:569 +#: text/chapter11.md:568 #, markdown-text, no-wrap msgid "" " _Hint_: you can use the implementation of `split` as a starting " "point. You might find the `stripPrefix` function useful.\n" " 1. (Difficult) Use the `ReaderT` and `WriterT` monad transformers to " -"reimplement the document printing library which we wrote earlier using the " +"reimplement the document printing library, which we wrote earlier using the " "`Reader` monad.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:571 +#: text/chapter11.md:570 #, markdown-text, no-wrap msgid "" " Instead of using `line` to emit strings and `cat` to concatenate " @@ -5771,13 +5783,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter11.md:572 +#: text/chapter11.md:571 #, markdown-text, no-wrap msgid "Type Classes to the Rescue!" msgstr "" #. type: Plain text -#: text/chapter11.md:575 +#: text/chapter11.md:574 #, markdown-text msgid "" "When we looked at the `State` monad at the start of this chapter, I gave the " @@ -5785,7 +5797,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:576 +#: text/chapter11.md:575 #, no-wrap msgid "" "get :: forall s. State s s\n" @@ -5794,7 +5806,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:583 +#: text/chapter11.md:582 #, markdown-text msgid "" "In reality, the types given in the `Control.Monad.State.Class` module are " @@ -5802,7 +5814,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:584 +#: text/chapter11.md:583 #, no-wrap msgid "" "get :: forall m s. MonadState s m => m s\n" @@ -5811,7 +5823,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:591 +#: text/chapter11.md:590 #, markdown-text msgid "" "The `Control.Monad.State.Class` module defines the `MonadState` " @@ -5822,71 +5834,71 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:593 +#: text/chapter11.md:592 #, markdown-text msgid "" "In particular, there are instances of `MonadState` for the `WriterT`, " -"`ReaderT` and `ExceptT` monad transformers, provided in the `transformers` " -"package. Each of these monad transformers has an instance for `MonadState` " -"whenever the underlying `Monad` does. In practice, this means that as long " -"as `StateT` appears _somewhere_ in the monad transformer stack, and " -"everything above `StateT` is an instance of `MonadState`, then we are free " -"to use `get`, `put` and `modify` directly, without the need to use `lift`." +"`ReaderT`, and `ExceptT` monad transformers provided in the `transformers` " +"package. Each has an instance for `MonadState` whenever the underlying " +"`Monad` does. In practice, this means that as long as `StateT` appears " +"_somewhere_ in the monad transformer stack, and everything above `StateT` is " +"an instance of `MonadState`, then we are free to use `get`, `put`, and " +"`modify` directly without the need to use `lift`." msgstr "" #. type: Plain text -#: text/chapter11.md:595 +#: text/chapter11.md:594 #, markdown-text msgid "" "Indeed, the same is true of the actions we covered for the `ReaderT`, " "`WriterT`, and `ExceptT` transformers. `transformers` defines a type class " -"for each of the major transformers, allowing us to abstract over monads " -"which support their operations." +"for each of the major transformers, allowing us to abstract over monads that " +"support their operations." msgstr "" #. type: Plain text -#: text/chapter11.md:597 +#: text/chapter11.md:596 #, markdown-text msgid "" "In the case of the `split` function above, the monad stack we constructed is " -"an instance of each of the `MonadState`, `MonadWriter` and `MonadError` type " -"classes. This means that we don't need to call `lift` at all! We can just " -"use the actions `get`, `put`, `tell` and `throwError` as if they were " +"an instance of each of the `MonadState`, `MonadWriter`, and `MonadError` " +"type classes. This means that we don't need to call `lift` at all! We can " +"just use the actions `get`, `put`, `tell`, and `throwError` as if they were " "defined on the monad stack itself:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:598 +#: text/chapter11.md:597 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Split.purs:split}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:603 +#: text/chapter11.md:602 #, markdown-text msgid "" -"This computation really looks like we have extended our programming language " -"to support the three new side-effects of mutable state, logging and error " +"This computation looks like we have extended our programming language to " +"support the three new side-effects of mutable state, logging, and error " "handling. However, everything is still implemented using pure functions and " "immutable data under the hood." msgstr "" #. type: Title ## -#: text/chapter11.md:604 +#: text/chapter11.md:603 #, markdown-text, no-wrap msgid "Alternatives" msgstr "" #. type: Plain text -#: text/chapter11.md:607 +#: text/chapter11.md:606 #, markdown-text msgid "" "The `control` package defines a number of abstractions for working with " -"computations which can fail. One of these is the `Alternative` type class:" +"computations that can fail. One of these is the `Alternative` type class:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:608 +#: text/chapter11.md:607 #, no-wrap msgid "" "class Functor f <= Alt f where\n" @@ -5899,17 +5911,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:619 +#: text/chapter11.md:618 #, markdown-text, no-wrap msgid "" "`Alternative` provides two new combinators: the `empty` value, which " "provides a prototype for a failing computation, and the `alt` function (and " -"its alias, `<|>`) which provides the ability to fall back to an " +"its alias, `<|>`), which provides the ability to fall back to an " "_alternative_ computation in the case of an error.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:621 +#: text/chapter11.md:620 #, markdown-text msgid "" "The `Data.Array` module provides two useful functions for working with type " @@ -5917,7 +5929,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:622 +#: text/chapter11.md:621 #, no-wrap msgid "" "many :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array " @@ -5927,22 +5939,22 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:628 +#: text/chapter11.md:627 #, markdown-text msgid "There is also an equivalent `many` and `some` for `Data.List`" msgstr "" #. type: Plain text -#: text/chapter11.md:630 +#: text/chapter11.md:629 #, markdown-text msgid "" "The `many` combinator uses the `Alternative` type class to repeatedly run a " -"computation _zero-or-more_ times. The `some` combinator is similar, but " +"computation _zero-or-more_ times. The `some` combinator is similar but " "requires at least the first computation to succeed." msgstr "" #. type: Plain text -#: text/chapter11.md:632 +#: text/chapter11.md:631 #, markdown-text msgid "" "In the case of our `Parser` monad transformer stack, there is an instance of " @@ -5953,7 +5965,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:633 +#: text/chapter11.md:632 #, no-wrap msgid "" "> import Data.Array (many)\n" @@ -5968,7 +5980,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:646 +#: text/chapter11.md:645 #, markdown-text msgid "" "Here, the input string `\"test\"` has been repeatedly split to return an " @@ -5977,13 +5989,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter11.md:647 +#: text/chapter11.md:646 #, markdown-text, no-wrap msgid "Monad Comprehensions" msgstr "" #. type: Plain text -#: text/chapter11.md:650 +#: text/chapter11.md:649 #, markdown-text msgid "" "The `Control.MonadPlus` module defines a subclass of the `Alternative` type " @@ -5992,35 +6004,35 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:651 +#: text/chapter11.md:650 #, no-wrap msgid "class (Monad m, Alternative m) <= MonadPlus m\n" msgstr "" #. type: Plain text -#: text/chapter11.md:656 +#: text/chapter11.md:655 #, markdown-text msgid "In particular, our `Parser` monad is an instance of `MonadPlus`." msgstr "" #. type: Plain text -#: text/chapter11.md:658 +#: text/chapter11.md:657 #, markdown-text msgid "" "When we covered array comprehensions earlier in the book, we introduced the " "`guard` function, which could be used to filter out unwanted results. In " -"fact, the `guard` function is more general, and can be used for any monad " +"fact, the `guard` function is more general and can be used for any monad, " "which is an instance of `MonadPlus`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:659 +#: text/chapter11.md:658 #, no-wrap msgid "guard :: forall m. Alternative m => Boolean -> m Unit\n" msgstr "" #. type: Plain text -#: text/chapter11.md:664 +#: text/chapter11.md:663 #, markdown-text, no-wrap msgid "" "The `<|>` operator allows us to backtrack in case of failure. To see how " @@ -6029,29 +6041,29 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:665 +#: text/chapter11.md:664 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Split.purs:upper}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:670 +#: text/chapter11.md:669 #, markdown-text msgid "" "Here, we use a `guard` to fail if the string is not upper case. Note that " -"this code looks very similar to the array comprehensions we saw earlier - " +"this code looks very similar to the array comprehensions we saw earlier – " "using `MonadPlus` in this way, we sometimes refer to constructing _monad " "comprehensions_." msgstr "" #. type: Title ## -#: text/chapter11.md:671 +#: text/chapter11.md:670 #, markdown-text, no-wrap msgid "Backtracking" msgstr "" #. type: Plain text -#: text/chapter11.md:674 +#: text/chapter11.md:673 #, markdown-text, no-wrap msgid "" "We can use the `<|>` operator to backtrack to another alternative in case of " @@ -6060,13 +6072,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:675 +#: text/chapter11.md:674 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Split.purs:lower}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:680 +#: text/chapter11.md:679 #, markdown-text msgid "" "With this, we can define a parser which eagerly matches many upper case " @@ -6075,19 +6087,19 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:681 +#: text/chapter11.md:680 #, no-wrap msgid "> upperOrLower = some upper <|> some lower\n" msgstr "" #. type: Plain text -#: text/chapter11.md:686 +#: text/chapter11.md:685 #, markdown-text msgid "This parser will match characters until the case changes:" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:687 +#: text/chapter11.md:686 #, no-wrap msgid "" "> runParser upperOrLower \"abcDEF\"\n" @@ -6099,7 +6111,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:697 +#: text/chapter11.md:696 #, markdown-text msgid "" "We can even use `many` to fully split a string into its lower and upper case " @@ -6107,7 +6119,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:698 +#: text/chapter11.md:697 #, no-wrap msgid "" "> components = many upperOrLower\n" @@ -6127,49 +6139,48 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:715 +#: text/chapter11.md:714 #, markdown-text msgid "" "Again, this illustrates the power of reusability that monad transformers " -"bring - we were able to write a backtracking parser in a declarative style " +"bring – we were able to write a backtracking parser in a declarative style " "with only a few lines of code, by reusing standard abstractions!" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 #, markdown-text msgid "" "(Easy) Remove the calls to the `lift` function from your implementation of " "the `string` parser. Verify that the new implementation type checks, and " -"convince yourself that it should." +"convince yourself it should." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 #, markdown-text msgid "" "(Medium) Use your `string` parser with the `some` combinator to write a " -"parser `asFollowedByBs` which recognizes strings consisting of several " -"copies of the string `\"a\"` followed by several copies of the string " -"`\"b\"`." +"parser `asFollowedByBs` that recognizes strings consisting of several copies " +"of the string `\"a\"` followed by several copies of the string `\"b\"`." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 #, markdown-text msgid "" -"(Medium) Use the `<|>` operator to write a parser `asOrBs` which recognizes " +"(Medium) Use the `<|>` operator to write a parser `asOrBs` that recognizes " "strings of the letters `a` or `b` in any order." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 #, markdown-text msgid "(Difficult) The `Parser` monad might also be defined as follows:" msgstr "" #. type: Plain text -#: text/chapter11.md:726 +#: text/chapter11.md:725 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -6178,30 +6189,30 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:728 +#: text/chapter11.md:727 #, markdown-text, no-wrap msgid " What effect does this change have on our parsing functions?\n" msgstr "" #. type: Title ## -#: text/chapter11.md:729 +#: text/chapter11.md:728 #, markdown-text, no-wrap msgid "The RWS Monad" msgstr "" #. type: Plain text -#: text/chapter11.md:732 +#: text/chapter11.md:731 #, markdown-text msgid "" "One particular combination of monad transformers is so common that it is " "provided as a single monad transformer in the `transformers` package. The " -"`Reader`, `Writer` and `State` monads are combined into the " -"_reader-writer-state_ monad, or more simply the `RWS` monad. This monad has " -"a corresponding monad transformer called the `RWST` monad transformer." +"`Reader`, `Writer`, and `State` monads are combined into the " +"_reader-writer-state_ or simply `RWS` monad. This monad has a corresponding " +"monad transformer called the `RWST` monad transformer." msgstr "" #. type: Plain text -#: text/chapter11.md:734 +#: text/chapter11.md:733 #, markdown-text msgid "" "We will use the `RWS` monad to model the game logic for our text adventure " @@ -6209,7 +6220,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:736 +#: text/chapter11.md:735 #, markdown-text msgid "" "The `RWS` monad is defined in terms of three type parameters (in addition to " @@ -6217,31 +6228,30 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:737 +#: text/chapter11.md:736 #, no-wrap msgid "type RWS r w s = RWST r w s Identity\n" msgstr "" #. type: Plain text -#: text/chapter11.md:742 +#: text/chapter11.md:741 #, markdown-text msgid "" -"Notice that the `RWS` monad is defined in terms of its own monad " -"transformer, by setting the base monad to `Identity` which provides no " -"side-effects." +"Notice that the `RWS` monad is defined as its own monad transformer by " +"setting the base monad to `Identity`, which provides no side-effects." msgstr "" #. type: Plain text -#: text/chapter11.md:744 +#: text/chapter11.md:743 #, markdown-text msgid "" "The first type parameter, `r`, represents the global configuration type. The " -"second, `w`, represents the monoid which we will use to accumulate a log, " -"and the third, `s` is the type of our mutable state." +"second, `w`, represents the monoid, which we will use to accumulate a log, " +"and the third, `s`, is the type of our mutable state." msgstr "" #. type: Plain text -#: text/chapter11.md:746 +#: text/chapter11.md:745 #, markdown-text msgid "" "In the case of our game, our global configuration is defined in a type " @@ -6249,22 +6259,22 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:747 +#: text/chapter11.md:746 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Data/GameEnvironment.purs:env}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:752 +#: text/chapter11.md:751 #, markdown-text msgid "" -"It defines the player name, and a flag which indicates whether or not the " -"game is running in debug mode. These options will be set from the command " -"line when we come to run our monad transformer." +"It defines the player name and a flag that indicates whether or not the game " +"is running in debug mode. These options will be set from the command line " +"when we come to run our monad transformer." msgstr "" #. type: Plain text -#: text/chapter11.md:754 +#: text/chapter11.md:753 #, markdown-text msgid "" "The mutable state is defined in a type called `GameState` in the " @@ -6272,7 +6282,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:755 +#: text/chapter11.md:754 #, no-wrap msgid "" "{{#include ../exercises/chapter11/src/Data/GameState.purs:imports}}\n" @@ -6281,7 +6291,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:762 +#: text/chapter11.md:761 #, markdown-text msgid "" "The `Coords` data type represents points on a two-dimensional grid, and the " @@ -6289,17 +6299,17 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:763 +#: text/chapter11.md:762 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Data/GameItem.purs:GameItem}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:768 +#: text/chapter11.md:767 #, markdown-text msgid "" "The `GameState` type uses two new data structures: `Map` and `Set`, which " -"represent sorted maps and sorted sets respectively. The `items` property is " +"represent sorted maps and sorted sets, respectively. The `items` property is " "a mapping from coordinates of the game grid to sets of game items at that " "location. The `player` property stores the current coordinates of the " "player, and the `inventory` property stores a set of game items currently " @@ -6307,16 +6317,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:770 +#: text/chapter11.md:769 #, markdown-text msgid "" -"The `Map` and `Set` data structures are sorted by their keys, can be used " -"with any key type in the `Ord` type class. This means that the keys in our " -"data structures should be totally ordered." +"The `Map` and `Set` data structures are sorted by their keys, and can be " +"used with any key type in the `Ord` type class. This means that the keys in " +"our data structures should be totally ordered." msgstr "" #. type: Plain text -#: text/chapter11.md:772 +#: text/chapter11.md:771 #, markdown-text msgid "" "We will see how the `Map` and `Set` structures are used as we write the " @@ -6324,7 +6334,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:774 +#: text/chapter11.md:773 #, markdown-text msgid "" "For our log, we will use the `List String` monoid. We can define a type " @@ -6332,30 +6342,30 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:775 +#: text/chapter11.md:774 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:Game}}\n" msgstr "" #. type: Title ## -#: text/chapter11.md:779 +#: text/chapter11.md:778 #, markdown-text, no-wrap msgid "Implementing Game Logic" msgstr "" #. type: Plain text -#: text/chapter11.md:782 +#: text/chapter11.md:781 #, markdown-text msgid "" -"Our game is going to be built from simple actions defined in the `Game` " -"monad, by reusing the actions from the `Reader`, `Writer` and `State` " -"monads. At the top level of our application, we will run the pure " -"computations in the `Game` monad, and use the `Effect` monad to turn the " -"results into observable side-effects, such as printing text to the console." +"Our game will be built from simple actions defined in the `Game` monad by " +"reusing the actions from the `Reader`, `Writer`, and `State` monads. At the " +"top level of our application, we will run the pure computations in the " +"`Game` monad and use the `Effect` monad to turn the results into observable " +"side-effects, such as printing text to the console." msgstr "" #. type: Plain text -#: text/chapter11.md:784 +#: text/chapter11.md:783 #, markdown-text msgid "" "One of the simplest actions in our game is the `has` action. This action " @@ -6364,23 +6374,23 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:785 +#: text/chapter11.md:784 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:has}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:790 +#: text/chapter11.md:789 #, markdown-text msgid "" "This function uses the `get` action defined in the `MonadState` type class " -"to read the current game state, and then uses the `member` function defined " +"to read the current game state and then uses the `member` function defined " "in `Data.Set` to test whether the specified `GameItem` appears in the `Set` " "of inventory items." msgstr "" #. type: Plain text -#: text/chapter11.md:792 +#: text/chapter11.md:791 #, markdown-text msgid "" "Another action is the `pickUp` action. It adds a game item to the player's " @@ -6390,13 +6400,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:793 +#: text/chapter11.md:792 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_start}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:798 +#: text/chapter11.md:797 #, markdown-text msgid "" "Next, `pickUp` looks up the set of items in the current room. It does this " @@ -6404,23 +6414,23 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:799 +#: text/chapter11.md:798 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_case}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:804 +#: text/chapter11.md:803 #, markdown-text msgid "" "The `lookup` function returns an optional result indicated by the `Maybe` " "type constructor. If the key does not appear in the map, the `lookup` " -"function returns `Nothing`, otherwise it returns the corresponding value in " +"function returns `Nothing`; otherwise, it returns the corresponding value in " "the `Just` constructor." msgstr "" #. type: Plain text -#: text/chapter11.md:806 +#: text/chapter11.md:805 #, markdown-text msgid "" "We are interested in the case where the corresponding item set contains the " @@ -6428,62 +6438,62 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:807 +#: text/chapter11.md:806 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:812 +#: text/chapter11.md:811 #, markdown-text msgid "" -"In this case, we can use `put` to update the game state, and `tell` to add a " +"In this case, we can use `put` to update the game state and `tell` to add a " "message to the log:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:813 +#: text/chapter11.md:812 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_body}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:818 +#: text/chapter11.md:817 #, markdown-text msgid "" -"Note that there is no need to `lift` either of the two computations here, " +"Note that there is no need to `lift` either of the two computations here " "because there are appropriate instances for both `MonadState` and " "`MonadWriter` for our `Game` monad transformer stack." msgstr "" #. type: Plain text -#: text/chapter11.md:820 +#: text/chapter11.md:819 #, markdown-text msgid "" "The argument to `put` uses a record update to modify the game state's " -"`items` and `inventory` fields. We use the `update` function from `Data.Map` " -"which modifies a value at a particular key. In this case, we modify the set " -"of items at the player's current location, using the `delete` function to " -"remove the specified item from the set. `inventory` is also updated, using " -"`insert` to add the new item to the player's inventory set." +"`items` and `inventory` fields. We use the `update` function from " +"`Data.Map`, which modifies a value at a particular key. In this case, we " +"modify the set of items at the player's current location, using the `delete` " +"function to remove the specified item from the set. `inventory` is also " +"updated, using `insert` to add the new item to the player's inventory set." msgstr "" #. type: Plain text -#: text/chapter11.md:822 +#: text/chapter11.md:821 #, markdown-text msgid "" -"Finally, the `pickUp` function handles the remaining cases, by notifying the " +"Finally, the `pickUp` function handles the remaining cases by notifying the " "user using `tell`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:823 +#: text/chapter11.md:822 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_err}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:828 +#: text/chapter11.md:827 #, markdown-text msgid "" "As an example of using the `Reader` monad, we can look at the code for the " @@ -6492,54 +6502,54 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:829 +#: text/chapter11.md:828 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:debug}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:834 +#: text/chapter11.md:833 #, markdown-text msgid "" "Here, we use the `ask` action to read the game configuration. Again, note " "that we don't need to `lift` any computation, and we can use actions defined " -"in the `MonadState`, `MonadReader` and `MonadWriter` type classes in the " +"in the `MonadState`, `MonadReader`, and `MonadWriter` type classes in the " "same do notation block." msgstr "" #. type: Plain text -#: text/chapter11.md:836 +#: text/chapter11.md:835 #, markdown-text msgid "" -"If the `debugMode` flag is set, then the `tell` action is used to write the " -"state to the log. Otherwise, an error message is added." +"If the `debugMode` flag is set, the `tell` action is used to write the state " +"to the log. Otherwise, an error message is added." msgstr "" #. type: Plain text -#: text/chapter11.md:838 +#: text/chapter11.md:837 #, markdown-text msgid "" "The remainder of the `Game` module defines a set of similar actions, each " -"using only the actions defined by the `MonadState`, `MonadReader` and " +"using only the actions defined by the `MonadState`, `MonadReader`, and " "`MonadWriter` type classes." msgstr "" #. type: Title ## -#: text/chapter11.md:839 +#: text/chapter11.md:838 #, markdown-text, no-wrap msgid "Running the Computation" msgstr "" #. type: Plain text -#: text/chapter11.md:842 +#: text/chapter11.md:841 #, markdown-text msgid "" "Since our game logic runs in the `RWS` monad, it is necessary to run the " -"computation in order to respond to the user's commands." +"computation to respond to the user's commands." msgstr "" #. type: Plain text -#: text/chapter11.md:844 +#: text/chapter11.md:843 #, markdown-text msgid "" "The front-end of our game is built using two packages: `optparse`, which " @@ -6549,7 +6559,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:846 +#: text/chapter11.md:845 #, markdown-text msgid "" "The interface to our game logic is provided by the function `game` in the " @@ -6557,21 +6567,21 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:847 +#: text/chapter11.md:846 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:game_sig}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:852 +#: text/chapter11.md:851 #, markdown-text msgid "" "To run this computation, we pass a list of words entered by the user as an " -"array of strings, and run the resulting `RWS` computation using `runRWS`:" +"array of strings and run the resulting `RWS` computation using `runRWS`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:853 +#: text/chapter11.md:852 #, no-wrap msgid "" "data RWSResult state result writer = RWSResult state result writer\n" @@ -6580,17 +6590,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:860 +#: text/chapter11.md:859 #, markdown-text msgid "" -"`runRWS` looks like a combination of `runReader`, `runWriter` and " +"`runRWS` looks like a combination of `runReader`, `runWriter`, and " "`runState`. It takes a global configuration and an initial state as an " -"argument, and returns a data structure containing the log, the result and " +"argument and returns a data structure containing the log, the result, and " "the final state." msgstr "" #. type: Plain text -#: text/chapter11.md:862 +#: text/chapter11.md:861 #, markdown-text msgid "" "The front-end of our application is defined by a function `runGame`, with " @@ -6598,13 +6608,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:863 +#: text/chapter11.md:862 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_sig}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:868 +#: text/chapter11.md:867 #, markdown-text msgid "" "This function interacts with the user via the console (using the " @@ -6613,16 +6623,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:870 +#: text/chapter11.md:869 #, markdown-text msgid "" "The `node-readline` package provides the `LineHandler` type, which " -"represents actions in the `Effect` monad which handle user input from the " +"represents actions in the `Effect` monad, which handle user input from the " "terminal. Here is the corresponding API:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:871 +#: text/chapter11.md:870 #, no-wrap msgid "" "type LineHandler a = String -> Effect a\n" @@ -6635,16 +6645,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:882 +#: text/chapter11.md:881 #, markdown-text msgid "" -"The `Interface` type represents a handle for the console, and is passed as " -"an argument to the functions which interact with it. An `Interface` can be " +"The `Interface` type represents a handle for the console and is passed as an " +"argument to the functions which interact with it. An `Interface` can be " "created using the `createConsoleInterface` function:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:883 +#: text/chapter11.md:882 #, no-wrap msgid "" "{{#include ../exercises/chapter11/src/Main.purs:import_RL}}\n" @@ -6653,7 +6663,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:890 +#: text/chapter11.md:889 #, markdown-text msgid "" "The first step is to set the prompt at the console. We pass the `interface` " @@ -6661,13 +6671,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:891 +#: text/chapter11.md:890 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_prompt}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:896 +#: text/chapter11.md:895 #, markdown-text msgid "" "In our case, we are interested in implementing the line handler " @@ -6676,13 +6686,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:897 +#: text/chapter11.md:896 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_lineHandler}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:902 +#: text/chapter11.md:901 #, markdown-text msgid "" "The `let` binding is closed over both the game configuration, named `env`, " @@ -6690,7 +6700,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:904 +#: text/chapter11.md:903 #, markdown-text msgid "" "Our handler takes an additional first argument, the game state. This is " @@ -6699,7 +6709,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:906 +#: text/chapter11.md:905 #, markdown-text msgid "" "The first thing this action does is to break the user input into words using " @@ -6709,7 +6719,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:908 +#: text/chapter11.md:907 #, markdown-text msgid "" "Having run the game logic, which is a pure computation, we need to print any " @@ -6721,21 +6731,21 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:910 +#: text/chapter11.md:909 #, markdown-text msgid "" "The `runGame` function finally attaches the initial line handler to the " -"console interface, and displays the initial prompt:" +"console interface and displays the initial prompt:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:911 +#: text/chapter11.md:910 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_attach_handler}}\n" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:919 +#: text/chapter11.md:918 #, markdown-text msgid "" "(Medium) Implement a new command `cheat`, which moves all game items from " @@ -6744,7 +6754,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:919 +#: text/chapter11.md:918 #, markdown-text msgid "" "(Difficult) The `Writer` component of the `RWS` monad is currently used for " @@ -6753,22 +6763,22 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:921 +#: text/chapter11.md:920 #, markdown-text, no-wrap msgid "" " Refactor the code to use the `ExceptT` monad transformer to handle the " -"error messages, and `RWS` to handle informational messages. _Note:_ There " -"are no tests for this exercise.\n" +"error messages and `RWS` to handle informational messages. _Note:_ There are " +"no tests for this exercise.\n" msgstr "" #. type: Title ## -#: text/chapter11.md:922 +#: text/chapter11.md:921 #, markdown-text, no-wrap msgid "Handling Command Line Options" msgstr "" #. type: Plain text -#: text/chapter11.md:925 +#: text/chapter11.md:924 #, markdown-text msgid "" "The final piece of the application is responsible for parsing command line " @@ -6777,7 +6787,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:927 +#: text/chapter11.md:926 #, markdown-text msgid "" "`optparse` is an example of _applicative command line option " @@ -6791,13 +6801,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:928 +#: text/chapter11.md:927 #, no-wrap msgid "customExecParser :: forall a. ParserPrefs → ParserInfo a → Effect a\n" msgstr "" #. type: Plain text -#: text/chapter11.md:933 +#: text/chapter11.md:932 #, markdown-text msgid "" "This is best illustrated by example. The application's `main` function is " @@ -6805,13 +6815,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:934 +#: text/chapter11.md:933 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:main}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:939 +#: text/chapter11.md:938 #, markdown-text msgid "" "The first argument is used to configure the `optparse` library. In our case, " @@ -6822,13 +6832,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:941 +#: text/chapter11.md:940 #, markdown-text msgid "The second argument is the complete description of our parser program:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:942 +#: text/chapter11.md:941 #, no-wrap msgid "" "{{#include ../exercises/chapter11/src/Main.purs:argParser}}\n" @@ -6837,75 +6847,75 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:949 +#: text/chapter11.md:948 #, markdown-text, no-wrap msgid "" "Here `OP.info` combines a `Parser` with a set of options for how the help " "message is formatted. `env <**> OP.helper` takes any command line argument " -"`Parser` named `env` and adds a `--help` option to it automatically. Options " -"for the help message are of type `InfoMod`, which is a monoid, so we can use " -"the `fold` function to add several options together.\n" +"`Parser` named `env` and automatically adds a `--help` option. Options for " +"the help message are of type `InfoMod`, which is a monoid, so we can use the " +"`fold` function to add several options together.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:951 +#: text/chapter11.md:950 #, markdown-text msgid "The interesting part of our parser is constructing the `GameEnvironment`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter11.md:952 +#: text/chapter11.md:951 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:env}}\n" msgstr "" #. type: Plain text -#: text/chapter11.md:957 +#: text/chapter11.md:956 #, markdown-text, no-wrap msgid "" "`player` and `debug` are both `Parser`s, so we can use our applicative " "operators `<$>` and `<*>` to lift our `gameEnvironment` function, which has " "the type `PlayerName -> Boolean -> GameEnvironment` over " "`Parser`. `OP.strOption` constructs a command line option that expects a " -"string value, and is configured via a collection of `Mod`s folded " -"together. `OP.flag` works similarly, but doesn't expect an associated " +"string value and is configured via a collection of `Mod`s folded " +"together. `OP.flag` works similarly but doesn't expect an associated " "value. `optparse` offers extensive " "[documentation](https://pursuit.purescript.org/packages/purescript-optparse) " "on different modifiers available to build various command line parsers.\n" msgstr "" #. type: Plain text -#: text/chapter11.md:959 +#: text/chapter11.md:958 #, markdown-text, no-wrap msgid "" -"Notice how we were able to use the notation afforded by the applicative " -"operators to give a compact, declarative specification of our command line " -"interface. In addition, it is simple to add new command line arguments, " -"simply by adding a new function argument to `runGame`, and then using `<*>` " -"to lift `runGame` over an additional argument in the definition of `env`.\n" +"Notice how we used the notation afforded by the applicative operators to " +"give a compact, declarative specification of our command line interface. In " +"addition, it is simple to add new command line arguments by adding a new " +"function argument to `runGame` and then using `<*>` to lift `runGame` over " +"an additional argument in the definition of `env`.\n" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter11.md:963 +#: text/chapter11.md:962 #, markdown-text msgid "" "(Medium) Add a new Boolean-valued property `cheatMode` to the " "`GameEnvironment` record. Add a new command line flag `-c` to the `optparse` " -"configuration which enables cheat mode. The `cheat` command from the " -"previous exercise should be disallowed if cheat mode is not enabled." +"configuration, enabling cheat mode. The `cheat` command from the previous " +"exercise should be disallowed if cheat mode is not enabled." msgstr "" #. type: Plain text -#: text/chapter11.md:967 +#: text/chapter11.md:966 #, markdown-text msgid "" "This chapter was a practical demonstration of the techniques we've learned " -"so far, using monad transformers to build a pure specification of our game, " +"so far, using monad transformers to build a pure specification of our game " "and the `Effect` monad to build a front-end using the console." msgstr "" #. type: Plain text -#: text/chapter11.md:969 +#: text/chapter11.md:968 #, markdown-text msgid "" "Because we separated our implementation from the user interface, it would be " @@ -6915,23 +6925,23 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:971 +#: text/chapter11.md:970 #, markdown-text msgid "" "We have seen how monad transformers allow us to write safe code in an " -"imperative style, where effects are tracked by the type system. In addition, " -"type classes provide a powerful way to abstract over the actions provided by " -"a monad, enabling code reuse. We were able to use standard abstractions like " -"`Alternative` and `MonadPlus` to build useful monads by combining standard " -"monad transformers." +"imperative style, where the type system tracks effects. In addition, type " +"classes provide a powerful way to abstract over the actions provided by a " +"monad, enabling code reuse. We used standard abstractions like `Alternative` " +"and `MonadPlus` to build useful monads by combining standard monad " +"transformers." msgstr "" #. type: Plain text -#: text/chapter11.md:972 +#: text/chapter11.md:971 #, markdown-text msgid "" -"Monad transformers are an excellent demonstration of the sort of expressive " -"code that can be written by relying on advanced type system features such as " +"Monad transformers are an excellent demonstration of expressive code that " +"can be written by relying on advanced type system features such as " "higher-kinded polymorphism and multi-parameter type classes." msgstr "" @@ -6980,8 +6990,8 @@ msgid "" "The HTML file `html/index.html` contains a single `canvas` element which " "will be used in each example, and a `script` element to load the compiled " "PureScript code. To test the code for each section, open the HTML file in " -"your browser. Because most exercises target the browser, there are no unit " -"tests for this chapter." +"your browser. Because most exercises target the browser, this chapter has no " +"unit tests." msgstr "" #. type: Title ## @@ -7006,7 +7016,7 @@ msgstr "" #, markdown-text msgid "" "The `main` action starts, like in the other modules, by using the " -"`getCanvasElementById` action to get a reference to the canvas object, and " +"`getCanvasElementById` action to get a reference to the canvas object and " "the `getContext2D` action to access the 2D rendering context for the canvas:" msgstr "" @@ -7015,7 +7025,7 @@ msgstr "" #, markdown-text msgid "" "The `void` function takes a functor and replaces its value with `Unit`. In " -"the example it is used to make `main` conform with its signature." +"the example, it is used to make `main` conform with its signature." msgstr "" #. type: Fenced code block (haskell) @@ -7065,7 +7075,7 @@ msgstr "" #: text/chapter12.md:43 #, markdown-text msgid "" -"The graphics context `ctx` manages the state of the canvas, and provides " +"The graphics context `ctx` manages the state of the canvas and provides " "methods to render primitive shapes, set styles and colors, and apply " "transformations." msgstr "" @@ -7113,9 +7123,9 @@ msgstr "" #: text/chapter12.md:59 #, markdown-text msgid "" -"`fillPath` takes a graphics context and another action which builds the path " +"`fillPath` takes a graphics context and another action that builds the path " "to render. To build a path, we can use the `rect` action. `rect` takes a " -"graphics context, and a record which provides the position and size of the " +"graphics context and a record that provides the position and size of the " "rectangle:" msgstr "" @@ -7158,16 +7168,16 @@ msgstr "" #, markdown-text msgid "" "There are other ways to render paths. The `arc` function renders an arc " -"segment, and the `moveTo`, `lineTo` and `closePath` functions can be used to " -"render piecewise-linear paths." +"segment, and the `moveTo`, `lineTo`, and `closePath` functions can render " +"piecewise-linear paths." msgstr "" #. type: Plain text #: text/chapter12.md:77 #, markdown-text msgid "" -"The `Shapes.purs` file renders three shapes: a rectangle, an arc segment and " -"a triangle." +"The `Shapes.purs` file renders three shapes: a rectangle, an arc segment, " +"and a triangle." msgstr "" #. type: Plain text @@ -7195,7 +7205,7 @@ msgstr "" #, markdown-text msgid "" "The `x` and `y` properties represent the location of the top-left corner, " -"while the `w` and `h` properties represent the width and height " +"while the `w` and `h` properties represent the width and height, " "respectively." msgstr "" @@ -7225,7 +7235,7 @@ msgstr "" #, markdown-text msgid "" "Here, the `x` and `y` properties represent the center point, `r` is the " -"radius, and `start` and `end` represent the endpoints of the arc in radians." +"radius, `start` and `end` represent the endpoints of the arc in radians." msgstr "" #. type: Plain text @@ -7234,7 +7244,7 @@ msgstr "" msgid "" "For example, this code fills an arc segment centered at `(300, 300)` with " "radius `50`. The arc completes 2/3rds of a rotation. Note that the unit " -"circle is flipped vertically, since the y-axis increases towards the bottom " +"circle is flipped vertically since the y-axis increases towards the bottom " "of the canvas:" msgstr "" @@ -7257,15 +7267,15 @@ msgstr "" msgid "" "Notice that both the `Rectangle` and `Arc` record types contain `x` and `y` " "properties of type `Number`. In both cases, this pair represents a " -"point. This means that we can write row-polymorphic functions which can act " -"on either type of record." +"point. This means we can write row-polymorphic functions acting on either " +"type of record." msgstr "" #. type: Plain text #: text/chapter12.md:120 #, markdown-text msgid "" -"For example, the `Shapes` module defines a `translate` function which " +"For example, the `Shapes` module defines a `translate` function that " "translates a shape by modifying its `x` and `y` properties:" msgstr "" @@ -7301,7 +7311,7 @@ msgstr "" #, markdown-text msgid "" "The `translate` function can be used with both the `Rectangle` and `Arc` " -"records, as can be seen in the `Shapes` example." +"records, as seen in the `Shapes` example." msgstr "" #. type: Plain text @@ -7379,19 +7389,18 @@ msgstr "" #, markdown-text msgid "" "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " -"each of the examples so far." +"each example so far." msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 #, markdown-text msgid "" -"(Easy) The `fillPath` and `strokePath` functions can be used to render " -"complex paths with a common style by using a do notation block inside the " -"function argument. Try changing the `Rectangle` example to render two " -"rectangles side-by-side using the same call to `fillPath`. Try rendering a " -"sector of a circle by using a combination of a piecewise-linear path and an " -"arc segment." +"(Easy) The `fillPath` and `strokePath` functions can render complex paths " +"with a common style using a do notation block inside the function " +"argument. Try changing the `Rectangle` example to render two rectangles " +"side-by-side using the same call to `fillPath`. Try rendering a sector of a " +"circle by using a combination of a piecewise-linear path and an arc segment." msgstr "" #. type: Bullet: ' 1. ' @@ -7449,7 +7458,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" " which takes a `Number` between `0` and `1` as its argument and returns " -"a `Point`, write an action which plots `f` by using your `renderPath` " +"a `Point`, write an action that plots `f` by using your `renderPath` " "function. Your action should approximate the path by sampling `f` at a " "finite set of points.\n" msgstr "" @@ -7470,17 +7479,17 @@ msgstr "" #: text/chapter12.md:185 #, markdown-text msgid "" -"The `Example/Random.purs` file contains an example which uses the `Effect` " -"monad to interleave two different types of side-effect: random number " -"generation, and canvas manipulation. The example renders one hundred " -"randomly generated circles onto the canvas." +"The `Example/Random.purs` file contains an example that uses the `Effect` " +"monad to interleave two types of side-effect: random number generation and " +"canvas manipulation. The example renders one hundred randomly generated " +"circles onto the canvas." msgstr "" #. type: Plain text #: text/chapter12.md:187 #, markdown-text msgid "" -"The `main` action obtains a reference to the graphics context as before, and " +"The `main` action obtains a reference to the graphics context as before and " "then sets the stroke and fill styles:" msgstr "" @@ -7510,7 +7519,7 @@ msgstr "" msgid "" "On each iteration, the do notation block starts by generating three random " "numbers distributed between `0` and `1`. These numbers represent the `x` and " -"`y` coordinates, and the radius of a circle:" +"`y` coordinates and the radius of a circle:" msgstr "" #. type: Fenced code block (haskell) @@ -7564,7 +7573,7 @@ msgstr "" #, markdown-text msgid "" "There is more to the canvas than just rendering simple shapes. Every canvas " -"maintains a transformation which is used to transform shapes before " +"maintains a transformation that is used to transform shapes before " "rendering. Shapes can be translated, rotated, scaled, and skewed." msgstr "" @@ -7609,8 +7618,8 @@ msgstr "" #: text/chapter12.md:245 #, markdown-text msgid "" -"The `rotate` action performs a rotation around the origin, through some " -"number of radians specified by the first argument." +"The `rotate` action rotates around the origin through some number of radians " +"specified by the first argument." msgstr "" #. type: Plain text @@ -7679,7 +7688,7 @@ msgstr "" #, markdown-text msgid "" "A common use case is to render some subset of the scene using a " -"transformation, and then to reset the transformation afterwards." +"transformation and then reset the transformation." msgstr "" #. type: Plain text @@ -7720,7 +7729,7 @@ msgid "" "This allows us to save the current state, apply some styles and " "transformations, render some primitives, and finally restore the original " "transformation and state. For example, the following function performs some " -"canvas action, but applies a rotation before doing so, and restores the " +"canvas action but applies a rotation before doing so and restores the " "transformation afterwards:" msgstr "" @@ -7791,7 +7800,7 @@ msgstr "" #, markdown-text msgid "" "The `Effect.Ref` module provides a type constructor for global mutable " -"references, and an associated effect:" +"references and an associated effect:" msgstr "" #. type: Fenced code block (text) @@ -7817,7 +7826,7 @@ msgstr "" #: text/chapter12.md:327 #, markdown-text msgid "" -"The `Example/Refs.purs` file contains an example which uses a `Ref` to track " +"The `Example/Refs.purs` file contains an example that uses a `Ref` to track " "mouse clicks on the `canvas` element." msgstr "" @@ -7825,7 +7834,7 @@ msgstr "" #: text/chapter12.md:329 #, markdown-text msgid "" -"The code starts by creating a new reference containing the value `0`, by " +"The code starts by creating a new reference containing the value `0` by " "using the `new` action:" msgstr "" @@ -7867,7 +7876,7 @@ msgstr "" #: text/chapter12.md:347 #, markdown-text msgid "" -"This action uses `withContext` to preserve the original transformation, and " +"This action uses `withContext` to preserve the original transformation and " "then applies the following sequence of transformations (remember that " "transformations are applied bottom-to-top):" msgstr "" @@ -7876,8 +7885,8 @@ msgstr "" #: text/chapter12.md:352 #, markdown-text msgid "" -"The rectangle is translated through `(-100, -100)` so that its center lies " -"at the origin." +"The rectangle is translated through `(-100, -100)`, so its center lies at " +"the origin." msgstr "" #. type: Bullet: '- ' @@ -7898,8 +7907,8 @@ msgstr "" #: text/chapter12.md:352 #, markdown-text msgid "" -"The rectangle is translated through `(300, 300)` so that it center lies at " -"the center of the canvas." +"The rectangle is translated through `(300, 300)`, so its center lies at the " +"center of the canvas." msgstr "" #. type: Plain text @@ -7926,16 +7935,16 @@ msgstr "" #: text/chapter12.md:366 #, markdown-text msgid "" -"(Easy) Write a higher-order function which strokes and fills a path " -"simultaneously. Rewrite the `Random.purs` example using your function." +"(Easy) Write a higher-order function that simultaneously strokes and fills a " +"path. Rewrite the `Random.purs` example using your function." msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 #, markdown-text msgid "" -"(Medium) Use `Random` and `Dom` to create an application which renders a " -"circle with random position, color and radius to the canvas when the mouse " +"(Medium) Use `Random` and `Dom` to create an application that renders a " +"circle with random position, color, and radius to the canvas when the mouse " "is clicked." msgstr "" @@ -7943,7 +7952,7 @@ msgstr "" #: text/chapter12.md:366 #, markdown-text msgid "" -"(Medium) Write a function which transforms the scene by rotating it around a " +"(Medium) Write a function that transforms the scene by rotating it around a " "point with specified coordinates. _Hint_: use a translation to first " "translate the scene to the origin." msgstr "" @@ -7969,7 +7978,7 @@ msgid "" "An L-system is defined by an _alphabet_, an initial sequence of letters from " "the alphabet, and a set of _production rules_. Each production rule takes a " "letter of the alphabet and returns a sequence of replacement letters. This " -"process is iterated some number of times starting with the initial sequence " +"process is iterated some number of times, starting with the initial sequence " "of letters." msgstr "" @@ -7987,7 +7996,7 @@ msgstr "" #, markdown-text msgid "" "For example, suppose the alphabet consists of the letters `L` (turn left), " -"`R` (turn right) and `F` (move forward). We might define the following " +"`R` (turn right), and `F` (move forward). We might define the following " "production rules:" msgstr "" @@ -8022,8 +8031,8 @@ msgstr "" #, markdown-text msgid "" "and so on. Plotting a piecewise-linear path corresponding to this set of " -"instruction approximates a curve called the _Koch curve_. Increasing the " -"number of iterations increases the resolution of the curve." +"instructions approximates the _Koch curve_. Increasing the number of " +"iterations increases the resolution of the curve." msgstr "" #. type: Plain text @@ -8091,10 +8100,10 @@ msgstr "" #: text/chapter12.md:420 #, markdown-text msgid "" -"Now we can implement a function `lsystem` which will take a specification in " -"this form, and render it to the canvas. What type should `lsystem` have? " +"Now we can implement a function `lsystem` that will take a specification in " +"this form and render it to the canvas. What type should `lsystem` have? " "Well, it needs to take values like `initial` and `productions` as arguments, " -"as well as a function which can render a letter of the alphabet to the " +"as well as a function that can render a letter of the alphabet to the " "canvas." msgstr "" @@ -8127,11 +8136,11 @@ msgstr "" #: text/chapter12.md:434 #, markdown-text msgid "" -"The third argument represents a function which takes a letter of the " -"alphabet and _interprets_ it by performing some actions on the canvas. In " -"our example, this would mean turning left in the case of the letter `L`, " -"turning right in the case of the letter `R`, and moving forward in the case " -"of a letter `F`." +"The third argument represents a function that takes a letter of the alphabet " +"and _interprets_ it by performing some actions on the canvas. In our " +"example, this would mean turning left in the case of the letter `L`, turning " +"right in the case of the letter `R`, and moving forward in the case of a " +"letter `F`." msgstr "" #. type: Plain text @@ -8167,12 +8176,12 @@ msgstr "" #: text/chapter12.md:448 #, markdown-text msgid "" -"The second observation is that, in order to implement instructions like " -"\"turn left\" and \"turn right\", we will need to maintain some state, " -"namely the direction in which the path is moving at any time. We need to " -"modify our function to pass the state through the computation. Again, the " -"`lsystem` function should work for any type of state, so we will represent " -"it using the type variable `s`." +"The second observation is that, to implement instructions like \"turn left\" " +"and \"turn right\", we will need to maintain some state, namely the " +"direction in which the path is moving at any time. We need to modify our " +"function to pass the state through the computation. Again, the `lsystem` " +"function should work for any type of state, so we will represent it using " +"the type variable `s`." msgstr "" #. type: Plain text @@ -8284,19 +8293,18 @@ msgstr "" #, markdown-text msgid "" "The `go` function works by recursion on its second argument. There are two " -"cases: when `n` is zero, and when `n` is non-zero." +"cases: when `n` is zero and `n` is non-zero." msgstr "" #. type: Plain text #: text/chapter12.md:496 #, markdown-text, no-wrap msgid "" -"In the first case, the recursion is complete, and we simply need to " -"interpret the current sentence according to the interpretation function. We " -"have a sentence of type `Array a`, a state of type `s`, and a function of " -"type `s -> a -> Effect s`. This sounds like a job for the `foldM` function " -"which we defined earlier, and which is available from the `control` " -"package:\n" +"In the first case, the recursion is complete, and we need to interpret the " +"current sentence according to the interpretation function. We have a " +"sentence of type `Array a`, a state of type `s`, and a function of type `s " +"-> a -> Effect s`. This sounds like a job for the `foldM` function which we " +"defined earlier, and which is available from the `control` package:\n" msgstr "" #. type: Fenced code block (haskell) @@ -8328,7 +8336,7 @@ msgstr "" #: text/chapter12.md:508 #, markdown-text msgid "" -"That's it! Note how the use of higher order functions like `foldM` and " +"That's it! Note how using higher-order functions like `foldM` and " "`concatMap` allowed us to communicate our ideas concisely." msgstr "" @@ -8362,9 +8370,9 @@ msgstr "" msgid "" "We can understand this type as saying that our interpretation function is " "free to have any side-effects at all, captured by the monad `m`. It might " -"render to the canvas, or print information to the console, or support " -"failure or multiple return values. The reader is encouraged to try writing " -"L-systems which use these various types of side-effect." +"render to the canvas, print information to the console, or support failure " +"or multiple return values. The reader is encouraged to try writing L-systems " +"that use these various types of side-effect." msgstr "" #. type: Plain text @@ -8372,11 +8380,11 @@ msgstr "" #, markdown-text msgid "" "This function is a good example of the power of separating data from " -"implementation. The advantage of this approach is that we gain the freedom " -"to interpret our data in multiple different ways. We might even factor " -"`lsystem` into two smaller functions: the first would build the sentence " -"using repeated application of `concatMap`, and the second would interpret " -"the sentence using `foldM`. This is also left as an exercise for the reader." +"implementation. The advantage of this approach is that we can interpret our " +"data in multiple ways. We might even factor `lsystem` into two smaller " +"functions: the first would build the sentence using repeated application of " +"`concatMap`, and the second would interpret the sentence using `foldM`. This " +"is also left as an exercise for the reader." msgstr "" #. type: Plain text @@ -8419,7 +8427,7 @@ msgstr "" #, markdown-text msgid "" "To interpret the letter `F` (move forward), we can calculate the new " -"position of the path, render a line segment, and update the state, as " +"position of the path, render a line segment, and update the state as " "follows:" msgstr "" @@ -8485,7 +8493,7 @@ msgstr "" #: text/chapter12.md:562 #, markdown-text msgid "" -"(Easy) Try changing the various numerical constants in the code, to " +"(Easy) Try changing the various numerical constants in the code to " "understand their effect on the rendered system." msgstr "" @@ -8502,9 +8510,9 @@ msgstr "" #: text/chapter12.md:562 #, markdown-text msgid "" -"(Medium) Add a drop shadow to the filled shape, by using the " -"`setShadowOffsetX`, `setShadowOffsetY`, `setShadowBlur` and `setShadowColor` " -"actions. _Hint_: use PSCi to find the types of these functions." +"(Medium) Add a drop shadow to the filled shape using the `setShadowOffsetX`, " +"`setShadowOffsetY`, `setShadowBlur`, and `setShadowColor` actions. _Hint_: " +"use PSCi to find the types of these functions." msgstr "" #. type: Bullet: ' 1. ' @@ -8540,7 +8548,7 @@ msgid "" "interesting shapes?\n" " 1. (Difficult) An L-system is given by an alphabet with four letters: `L` " "(turn left through 60 degrees), `R` (turn right through 60 degrees), `F` " -"(move forward) and `M` (also move forward).\n" +"(move forward), and `M` (also move forward).\n" msgstr "" #. type: Plain text @@ -8572,7 +8580,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" " Render this L-system. _Note_: you will need to decrease the number of " -"iterations of the production rules, since the size of the final sentence " +"iterations of the production rules since the size of the final sentence " "grows exponentially with the number of iterations.\n" msgstr "" @@ -8612,7 +8620,7 @@ msgstr "" msgid "" "In this chapter, we learned how to use the HTML5 Canvas API from PureScript " "by using the `canvas` library. We also saw a practical demonstration of many " -"of the techniques we have learned already: maps and folds, records and row " +"techniques we have learned already: maps and folds, records and row " "polymorphism, and the `Effect` monad for handling side-effects." msgstr "" @@ -8644,8 +8652,8 @@ msgstr "" #, markdown-text msgid "" "This approach is taken in the `drawing` package, and it brings the " -"flexibility of being able to manipulate the scene as data in various ways " -"before rendering." +"flexibility of manipulating the scene as data in various ways before " +"rendering." msgstr "" #. type: Plain text @@ -8728,7 +8736,7 @@ msgstr "" #: text/chapter13.md:24 #, markdown-text msgid "" -"`merge` takes two sorted arrays of integers, and merges their elements so " +"`merge` takes two sorted arrays of integers and merges their elements so " "that the result is also sorted. For example:" msgstr "" @@ -8747,7 +8755,7 @@ msgstr "" #, markdown-text msgid "" "In a typical test suite, we might test `merge` by generating a few small " -"test cases like this by hand, and asserting that the results were equal to " +"test cases like this by hand and asserting that the results were equal to " "the appropriate values. However, everything we need to know about the " "`merge` function can be summarized by this property:" msgstr "" @@ -8764,8 +8772,8 @@ msgstr "" #: text/chapter13.md:37 #, markdown-text msgid "" -"`quickcheck` allows us to test this property directly, by generating random " -"test cases. We simply state the properties that we want our code to have, as " +"`quickcheck` allows us to test this property directly by generating random " +"test cases. We state the properties we want our code to have as " "functions. In this case, we have a single property:" msgstr "" @@ -8783,11 +8791,10 @@ msgstr "" #, markdown-text msgid "" "When we run this code, `quickcheck` will attempt to disprove the properties " -"we claimed, by generating random inputs `xs` and `ys`, and passing them to " -"our functions. If our function returns `false` for any inputs, the property " -"will be incorrect, and the library will raise an error. Fortunately, the " -"library is unable to disprove our properties after generating 100 random " -"test cases:" +"we claimed by generating random inputs `xs` and `ys` and passing them to our " +"functions. If our function returns `false` for any inputs, the property will " +"be incorrect, and the library will raise an error. Fortunately, the library " +"is unable to disprove our properties after generating 100 random test cases:" msgstr "" #. type: Fenced code block (text) @@ -8887,11 +8894,10 @@ msgstr "" #: text/chapter13.md:94 #, markdown-text msgid "" -"(Easy) Write a property which asserts that merging an array with the empty " -"array does not modify the original array. _Note_: This new property is " -"redundant, since this situation is already covered by our existing " -"property. We're just trying to give you readers a simple way to practice " -"using quickCheck." +"(Easy) Write a property that asserts that merging an array with an empty one " +"does not modify the original array. _Note_: This new property is redundant " +"since this situation is already covered by our existing property. We're just " +"trying to give readers a simple way to practice using quickCheck." msgstr "" #. type: Bullet: ' 1. ' @@ -8948,7 +8954,7 @@ msgstr "" #, markdown-text msgid "" "This error message indicates that the compiler could not generate random " -"test cases, because it did not know what type of elements we wanted our " +"test cases because it did not know what type of elements we wanted our " "arrays to have. In these sorts of cases, we can use type annotations to " "force the compiler to infer a particular type, such as `Array Int`:" msgstr "" @@ -8965,9 +8971,9 @@ msgstr "" #: text/chapter13.md:122 #, markdown-text msgid "" -"We can alternatively use a helper function to specify type, which may result " -"in cleaner code. For example, if we define a function `ints` as a synonym " -"for the identity function:" +"We can alternatively use a helper function to specify the type, which may " +"result in cleaner code. For example, if we define a function `ints` as a " +"synonym for the identity function:" msgstr "" #. type: Fenced code block (haskell) @@ -8998,17 +9004,17 @@ msgstr "" #: text/chapter13.md:136 #, markdown-text msgid "" -"Here, `xs` and `ys` both have type `Array Int`, since the `ints` function " -"has been used to disambiguate the unknown type." +"Here, `xs` and `ys` have type `Array Int` since the `ints` function has been " +"used to disambiguate the unknown type." msgstr "" #. type: Bullet: ' 1. ' #: text/chapter13.md:141 #, markdown-text msgid "" -"(Easy) Write a function `bools` which forces the types of `xs` and `ys` to " -"be `Array Boolean`, and add additional properties which test `mergePoly` at " -"that type." +"(Easy) Write a function `bools` that forces the types of `xs` and `ys` to be " +"`Array Boolean`, and add additional properties that test `mergePoly` at that " +"type." msgstr "" #. type: Bullet: ' 1. ' @@ -9031,8 +9037,8 @@ msgstr "" #: text/chapter13.md:145 #, markdown-text msgid "" -"Now we will see how the `quickcheck` library is able to randomly generate " -"test cases for our properties." +"Now we will see how the `quickcheck` library can randomly generate test " +"cases for our properties." msgstr "" #. type: Plain text @@ -9076,9 +9082,9 @@ msgstr "" #, markdown-text msgid "" "For example, we can use the `Arbitrary` instance for the `Int` type, " -"provided in the `quickcheck` library, to create a distribution on the 256 " -"byte values, using the `Functor` instance for `Gen` to map a function from " -"integers to bytes over arbitrary integer values:" +"provided in the `quickcheck` library, to create a distribution on the " +"256-byte values, using the `Functor` instance for `Gen` to map a function " +"from integers to bytes over arbitrary integer values:" msgstr "" #. type: Fenced code block (haskell) @@ -9124,8 +9130,8 @@ msgstr "" msgid "" "In this test, we generated arbitrary arrays `xs` and `ys`, but had to sort " "them, since `merge` expects sorted input. On the other hand, we could create " -"a newtype representing sorted arrays, and write an `Arbitrary` instance " -"which generates sorted data:" +"a newtype representing sorted arrays and write an `Arbitrary` instance that " +"generates sorted data:" msgstr "" #. type: Fenced code block (haskell) @@ -9161,8 +9167,8 @@ msgstr "" #, markdown-text msgid "" "This may look like a small change, but the types of `xs` and `ys` have " -"changed to `Sorted Int`, instead of just `Array Int`. This communicates our " -"_intent_ in a clearer way - the `mergePoly` function takes sorted " +"changed to `Sorted Int` instead of just `Array Int`. This communicates our " +"_intent_ in a clearer way – the `mergePoly` function takes sorted " "input. Ideally, the type of the `mergePoly` function itself would be updated " "to use the `Sorted` type constructor." msgstr "" @@ -9204,9 +9210,8 @@ msgstr "" #: text/chapter13.md:217 #, markdown-text msgid "" -"The `insert` function is used to insert a new element into a sorted tree, " -"and the `member` function can be used to query a tree for a particular " -"value. For example:" +"The `insert` function inserts a new element into a sorted tree, and the " +"`member` function can query a tree for a particular value. For example:" msgstr "" #. type: Fenced code block (text) @@ -9226,9 +9231,8 @@ msgstr "" #: text/chapter13.md:229 #, markdown-text msgid "" -"The `toArray` and `fromArray` functions can be used to convert sorted trees " -"to and from arrays. We can use `fromArray` to write an `Arbitrary` instance " -"for trees:" +"The `toArray` and `fromArray` functions can convert sorted trees to and from " +"arrays. We can use `fromArray` to write an `Arbitrary` instance for trees:" msgstr "" #. type: Fenced code block (haskell) @@ -9243,7 +9247,7 @@ msgstr "" #: text/chapter13.md:236 #, markdown-text msgid "" -"We can now use `Tree a` as the type of an argument to our test properties, " +"We can now use `Tree a` as the type of an argument to our test properties " "whenever there is an `Arbitrary` instance available for the type `a`. For " "example, we can test that the `member` test always returns `true` after " "inserting a value:" @@ -9279,7 +9283,7 @@ msgstr "" #: text/chapter13.md:248 #, markdown-text msgid "" -"(Difficult) Write a property which asserts that a value inserted into a tree " +"(Difficult) Write a property that asserts that a value inserted into a tree " "is still a member of that tree after arbitrarily many more insertions." msgstr "" @@ -9293,19 +9297,19 @@ msgstr "" #: text/chapter13.md:252 #, markdown-text msgid "" -"The `Merge` module defines another generalization of the `merge` function - " -"the `mergeWith` function takes an additional function as an argument which " -"is used to determine the order in which elements should be merged. That is, " -"`mergeWith` is a higher-order function." +"The `Merge` module defines another generalization of the `merge` function – " +"the `mergeWith` function takes an additional function as an argument to " +"determine the order in which elements should be merged. That is, `mergeWith` " +"is a higher-order function." msgstr "" #. type: Plain text #: text/chapter13.md:254 #, markdown-text msgid "" -"For example, we can pass the `length` function as the first argument, to " -"merge two arrays which are already in length-increasing order. The result " -"should also be in length-increasing order:" +"For example, we can pass the `length` function as the first argument to " +"merge two arrays already in length-increasing order. The result should also " +"be in length-increasing order:" msgstr "" #. type: Fenced code block (haskell) @@ -9326,14 +9330,14 @@ msgstr "" #, markdown-text msgid "" "How might we test such a function? Ideally, we would like to generate values " -"for all three arguments, including the first argument which is a function." +"for all three arguments, including the first argument, which is a function." msgstr "" #. type: Plain text #: text/chapter13.md:268 #, markdown-text msgid "" -"There is a second type class which allows us to create randomly-generated " +"There is a second type class that allows us to create randomly-generated " "functions. It is called `Coarbitrary`, and it is defined as follows:" msgstr "" @@ -9349,8 +9353,8 @@ msgstr "" #: text/chapter13.md:275 #, markdown-text msgid "" -"The `coarbitrary` function takes a function argument of type `t`, and a " -"random generator for a function result of type `r`, and uses the function " +"The `coarbitrary` function takes a function argument of type `t` and a " +"random generator for a function result of type `r`. It uses the function " "argument to _perturb_ the random generator. That is, it uses the function " "argument to modify the random output of the random generator for the result." msgstr "" @@ -9359,7 +9363,7 @@ msgstr "" #: text/chapter13.md:277 #, markdown-text msgid "" -"In addition, there is a type class instance which gives us `Arbitrary` " +"In addition, there is a type class instance that gives us `Arbitrary` " "functions if the function domain is `Coarbitrary` and the function codomain " "is `Arbitrary`:" msgstr "" @@ -9374,21 +9378,20 @@ msgstr "" #: text/chapter13.md:283 #, markdown-text msgid "" -"In practice, this means that we can write properties which take functions as " -"arguments. In the case of the `mergeWith` function, we can generate the " -"first argument randomly, modifying our tests to take account of the new " -"argument." +"In practice, we can write properties that take functions as arguments. In " +"the case of the `mergeWith` function, we can generate the first argument " +"randomly, modifying our tests to take account of the new argument." msgstr "" #. type: Plain text #: text/chapter13.md:285 #, markdown-text msgid "" -"We cannot guarantee that the result will be sorted - we do not even " -"necessarily have an `Ord` instance - but we can expect that the result be " +"We cannot guarantee that the result will be sorted – we do not even " +"necessarily have an `Ord` instance – but we can expect that the result be " "sorted with respect to the function `f` that we pass in as an argument. In " -"addition, we need the two input arrays to be sorted with respect to `f`, so " -"we use the `sortBy` function to sort `xs` and `ys` based on comparison after " +"addition, we need the two input arrays to be sorted concerning `f`, so we " +"use the `sortBy` function to sort `xs` and `ys` based on comparison after " "the function `f` has been applied:" msgstr "" @@ -9442,7 +9445,7 @@ msgstr "" #: text/chapter13.md:315 #, markdown-text msgid "" -"This means that we are not limited to just values and functions - we can " +"This means that we are not limited to just values and functions – we can " "also randomly generate _higher-order functions_, or functions whose " "arguments are higher-order functions, and so on." msgstr "" @@ -9481,9 +9484,9 @@ msgstr "" #: text/chapter13.md:327 #, markdown-text msgid "" -"We have to write a function which perturbs a random generator given a value " -"of type `Tree a`. If the input value is a `Leaf`, then we will just return " -"the generator unchanged:" +"We have to write a function that perturbs a random generator given a value " +"of type `Tree a`. If the input value is a `Leaf`, then we will return the " +"generator unchanged:" msgstr "" #. type: Fenced code block (haskell) @@ -9515,9 +9518,9 @@ msgstr "" #: text/chapter13.md:342 #, markdown-text msgid "" -"Now we are free to write properties whose arguments include functions taking " -"trees as arguments. For example, the `Tree` module defines a function " -"`anywhere`, which tests if a predicate holds on any subtree of its argument:" +"Now we can write properties whose arguments include functions taking trees " +"as arguments. For example, the `Tree` module defines a function `anywhere`, " +"which tests if a predicate holds on any subtree of its argument:" msgstr "" #. type: Fenced code block (haskell) @@ -9530,8 +9533,8 @@ msgstr "" #: text/chapter13.md:348 #, markdown-text msgid "" -"Now we are able to generate the predicate function randomly. For example, we " -"expect the `anywhere` function to _respect disjunction_:" +"Now we can generate the predicate function randomly. For example, we expect " +"the `anywhere` function to _respect disjunction_:" msgstr "" #. type: Fenced code block (haskell) @@ -9572,8 +9575,8 @@ msgid "" "For the purposes of testing, we usually include calls to the `quickCheck` " "function in the `main` action of our test suite. However, there is a variant " "of the `quickCheck` function, called `quickCheckPure` which does not use " -"side-effects. Instead, it is a pure function which takes a random seed as an " -"input, and returns an array of test results." +"side-effects. Instead, it is a pure function that takes a random seed as an " +"input and returns an array of test results." msgstr "" #. type: Plain text @@ -9616,8 +9619,8 @@ msgstr "" #, markdown-text msgid "" "`quickCheckPure` might be useful in other situations, such as generating " -"random input data for performance benchmarks, or generating sample form data " -"for web applications." +"random input data for performance benchmarks or sample form data for web " +"applications." msgstr "" #. type: Bullet: ' 1. ' @@ -9661,8 +9664,8 @@ msgid "" " _Hint_: Use the `oneOf` function defined in `Test.QuickCheck.Gen` to " "define your `Arbitrary` instance.\n" " 1. (Medium) Use `all` to simplify the result of the `quickCheckPure` " -"function - your new function should have type `List Result -> Boolean` and " -"should return `true` if every test passes and `false` otherwise.\n" +"function – your new function should have the type `List Result -> Boolean` " +"and should return `true` if every test passes and `false` otherwise.\n" " 1. (Medium) As another approach to simplifying the result of " "`quickCheckPure`, try writing a function `squashResults :: List Result -> " "Result`. Consider using the `First` monoid from `Data.Maybe.First` with the " @@ -9688,7 +9691,7 @@ msgstr "" #: text/chapter13.md:408 #, markdown-text msgid "" -"We saw how to write properties as functions, and how to use the `` " +"We saw how to write properties as functions and how to use the `` " "operator to improve error messages." msgstr "" @@ -9697,7 +9700,7 @@ msgstr "" #, markdown-text msgid "" "We saw how the `Arbitrary` and `Coarbitrary` type classes enable generation " -"of boilerplate testing code, and how they allow us to test higher-order " +"of boilerplate testing code and how they allow us to test higher-order " "properties." msgstr "" @@ -9727,10 +9730,11 @@ msgstr "" #: text/chapter14.md:8 #, markdown-text msgid "" -"A domain-specific language is a language which is well-suited to development " +"A domain-specific language is a language that is well-suited to development " "in a particular problem domain. Its syntax and functions are chosen to " -"maximize readability of code used to express ideas in that domain. We have " -"already seen a number of examples of domain-specific languages in this book:" +"maximize the readability of code used to express ideas in that domain. We " +"have already seen several examples of domain-specific languages in this " +"book:" msgstr "" #. type: Bullet: '- ' @@ -9746,7 +9750,7 @@ msgstr "" #: text/chapter14.md:11 #, markdown-text msgid "" -"The `quickcheck` package, covered in chapter 13, is a domain-specific " +"The `quickcheck` package, covered in Chapter 13, is a domain-specific " "language for the domain of _generative testing_. Its combinators enable a " "particularly expressive notation for test properties." msgstr "" @@ -9755,10 +9759,10 @@ msgstr "" #: text/chapter14.md:13 #, markdown-text msgid "" -"This chapter will take a more structured approach to some of standard " -"techniques in the implementation of domain-specific languages. It is by no " -"means a complete exposition of the subject, but should provide you with " -"enough knowledge to build some practical DSLs for your own tasks." +"This chapter will take a more structured approach to some standard " +"techniques in implementing domain-specific languages. It is by no means a " +"complete exposition of the subject, but should provide you with enough " +"knowledge to build some practical DSLs for your own tasks." msgstr "" #. type: Plain text @@ -9766,7 +9770,7 @@ msgstr "" #, markdown-text msgid "" "Our running example will be a domain-specific language for creating HTML " -"documents. Our aim will be to develop a type-safe language for describing " +"documents. We will aim to develop a type-safe language for describing " "correct HTML documents, and we will work by improving a naive implementation " "in small steps." msgstr "" @@ -9775,9 +9779,8 @@ msgstr "" #: text/chapter14.md:19 #, markdown-text msgid "" -"The project accompanying this chapter adds one new dependency - the `free` " -"library, which defines the _free monad_, one of the tools which we will be " -"using." +"The project accompanying this chapter adds one new dependency – the `free` " +"library, which defines the _free monad_, one of the tools we will use." msgstr "" #. type: Plain text @@ -9789,7 +9792,7 @@ msgstr "" #. type: Title ## #: text/chapter14.md:22 #, markdown-text, no-wrap -msgid "A HTML Data Type" +msgid "An HTML Data Type" msgstr "" #. type: Plain text @@ -9826,7 +9829,7 @@ msgstr "" #, markdown-text msgid "" "The `Element` type represents HTML elements. Each element consists of an " -"element name, an array of attribute pairs and some content. The content " +"element name, an array of attribute pairs, and some content. The content " "property uses the `Maybe` type to indicate that an element might be open " "(containing other elements and text) or closed." msgstr "" @@ -9892,7 +9895,7 @@ msgstr "" #: text/chapter14.md:87 #, markdown-text msgid "" -"Creating HTML documents is difficult - every new element requires at least " +"Creating HTML documents is difficult – every new element requires at least " "one record and one data constructor." msgstr "" @@ -9942,8 +9945,8 @@ msgid "" "The first technique we will apply is simple but can be very " "effective. Instead of exposing the representation of the data to the " "module's users, we can use the module exports list to hide the `Element`, " -"`Content` and `Attribute` data constructors, and only export so-called " -"_smart constructors_, which construct data which is known to be correct." +"`Content`, and `Attribute` data constructors, and only export so-called " +"_smart constructors_, which construct data known to be correct." msgstr "" #. type: Plain text @@ -9971,7 +9974,7 @@ msgstr "" #, markdown-text msgid "" "Next, we create smart constructors for those HTML elements we want our users " -"to be able to create, by applying the `element` function:" +"to be able to create by applying the `element` function:" msgstr "" #. type: Fenced code block (haskell) @@ -10037,7 +10040,7 @@ msgstr "" #: text/chapter14.md:139 #, markdown-text msgid "" -"A type constructor and any associated data constructors, indicated by the " +"A type constructor and any associated data constructors indicated by the " "name of the type followed by a parenthesized list of exported data " "constructors." msgstr "" @@ -10047,8 +10050,7 @@ msgstr "" #, markdown-text msgid "" "Here, we export the `Element` _type_, but we do not export its data " -"constructors. If we did, the user would be able to construct invalid HTML " -"elements." +"constructors. If we did, the user could construct invalid HTML elements." msgstr "" #. type: Plain text @@ -10085,7 +10087,7 @@ msgstr "" #, markdown-text msgid "" "We can apply this technique to the `Content` type very easily. We simply " -"remove the data constructors for the `Content` type from the exports list, " +"remove the data constructors for the `Content` type from the exports list " "and provide the following smart constructors:" msgstr "" @@ -10126,9 +10128,9 @@ msgstr "" #, markdown-text msgid "" "This representation suffers from the same problem as the original `Element` " -"type - it is possible to represent attributes which do not exist or whose " +"type – it is possible to represent attributes that do not exist or whose " "names were entered incorrectly. To solve this problem, we can create a " -"newtype which represents attribute names:" +"newtype that represents attribute names:" msgstr "" #. type: Fenced code block (haskell) @@ -10248,9 +10250,9 @@ msgstr "" msgid "" "Note, however, that no changes had to be made to the `render` function, " "because the underlying data representation never changed. This is one of the " -"benefits of the smart constructors approach - it allows us to separate the " -"internal data representation for a module from the representation which is " -"perceived by users of its external API." +"benefits of the smart constructors approach – it allows us to separate the " +"internal data representation for a module from the representation perceived " +"by users of its external API." msgstr "" #. type: Bullet: ' 1. ' @@ -10265,8 +10267,8 @@ msgstr "" #: text/chapter14.md:253 #, markdown-text msgid "" -"(Medium) Some HTML attributes such as `checked` and `disabled` do not " -"require values, and may be rendered as _empty attributes_:" +"(Medium) Some HTML attributes, such as `checked` and `disabled`, do not " +"require values and may be rendered as _empty attributes_:" msgstr "" #. type: Plain text @@ -10472,7 +10474,7 @@ msgstr "" #: text/chapter14.md:356 #, markdown-text msgid "" -"(Easy) Create a data type which represents either pixel or percentage " +"(Easy) Create a data type representing either pixel or percentage " "lengths. Write an instance of `IsValue` for your type. Modify the `width` " "and `height` attributes to use your new type." msgstr "" @@ -10483,7 +10485,7 @@ msgstr "" msgid "" "(Difficult) By defining type-level representatives for the Boolean values " "`true` and `false`, we can use a phantom type to encode whether an " -"`AttributeKey` represents an _empty attribute_ such as `disabled` or " +"`AttributeKey` represents an _empty attribute_, such as `disabled` or " "`checked`." msgstr "" @@ -10519,7 +10521,7 @@ msgid "" "In our final set of modifications to our API, we will use a construction " "called the _free monad_ to turn our `Content` type into a monad, enabling do " "notation. This will allow us to structure our HTML documents in a form in " -"which the nesting of elements becomes clearer - instead of this:" +"which the nesting of elements becomes clearer – instead of this:" msgstr "" #. type: Fenced code block (haskell) @@ -10561,7 +10563,7 @@ msgstr "" msgid "" "However, do notation is not the only benefit of a free monad. The free monad " "allows us to separate the _representation_ of our monadic actions from their " -"_interpretation_, and even support _multiple interpretations_ of the same " +"_interpretation_ and even support _multiple interpretations_ of the same " "actions." msgstr "" @@ -10569,7 +10571,7 @@ msgstr "" #: text/chapter14.md:394 #, markdown-text msgid "" -"The `Free` monad is defined in the `free` library, in the " +"The `Free` monad is defined in the `free` library in the " "`Control.Monad.Free` module. We can find out some basic information about it " "using PSCi, as follows:" msgstr "" @@ -10588,9 +10590,9 @@ msgstr "" #: text/chapter14.md:403 #, markdown-text msgid "" -"The kind of `Free` indicates that it takes a type constructor as an " -"argument, and returns another type constructor. In fact, the `Free` monad " -"can be used to turn any `Functor` into a `Monad`!" +"The kind of `Free` indicates that it takes a type constructor as an argument " +"and returns another type constructor. In fact, the `Free` monad can be used " +"to turn any `Functor` into a `Monad`!" msgstr "" #. type: Plain text @@ -10600,8 +10602,7 @@ msgid "" "We begin by defining the _representation_ of our monadic actions. To do " "this, we need to create a `Functor` with one data constructor for each " "monadic action we wish to support. In our case, our two monadic actions will " -"be `elem` and `text`. In fact, we can simply modify our `Content` type as " -"follows:" +"be `elem` and `text`. We can simply modify our `Content` type as follows:" msgstr "" #. type: Fenced code block (haskell) @@ -10622,7 +10623,7 @@ msgstr "" #, markdown-text msgid "" "Here, the `ContentF` type constructor looks just like our old `Content` data " -"type - however, it now takes a type argument `a`, and each data constructor " +"type – however, it now takes a type argument `a`, and each data constructor " "has been modified to take a value of type `a` as an additional argument. The " "`Functor` instance simply applies the function `f` to the value of type `a` " "in each data constructor." @@ -10648,7 +10649,7 @@ msgstr "" #, markdown-text msgid "" "Instead of a type synonym, we might use a `newtype` to avoid exposing the " -"internal representation of our library to our users - by hiding the " +"internal representation of our library to our users – by hiding the " "`Content` data constructor, we restrict our users to only using the monadic " "actions we provide." msgstr "" @@ -10687,7 +10688,7 @@ msgstr "" msgid "" "In addition, we have to modify our `elem` and `text` functions, which become " "our new monadic actions for the `Content` monad. To do this, we can use the " -"`liftF` function, provided by the `Control.Monad.Free` module. Here is its " +"`liftF` function provided by the `Control.Monad.Free` module. Here is its " "type:" msgstr "" @@ -10702,8 +10703,8 @@ msgstr "" #, markdown-text msgid "" "`liftF` allows us to construct an action in our free monad from a value of " -"type `f a` for some type `a`. In our case, we can simply use the data " -"constructors of our `ContentF` type constructor directly:" +"type `f a` for some type `a`. In our case, we can use the data constructors " +"of our `ContentF` type constructor directly:" msgstr "" #. type: Fenced code block (haskell) @@ -10772,10 +10773,9 @@ msgstr "" #: text/chapter14.md:479 #, markdown-text msgid "" -"_Note_: Technically, we are restricted to using monads `m` which satisfy the " -"stronger `MonadRec` constraint. In practice, this means that we don't need " -"to worry about stack overflow, since `m` supports safe _monadic tail " -"recursion_." +"_Note_: Technically, we are restricted to monads `m` that satisfy the " +"stronger `MonadRec` constraint. In practice, we don't need to worry about " +"stack overflow since `m` supports safe _monadic tail recursion_." msgstr "" #. type: Plain text @@ -10783,7 +10783,7 @@ msgstr "" #, markdown-text msgid "" "First, we have to choose a monad in which we can interpret our actions. We " -"will use the `Writer String` monad to accumulate a HTML string as our " +"will use the `Writer String` monad to accumulate an HTML string as our " "result." msgstr "" @@ -10904,7 +10904,7 @@ msgstr "" #: text/chapter14.md:540 #, markdown-text msgid "" -"We can implement this function by simply pattern matching on the two data " +"We can implement this function by pattern matching on the two data " "constructors of `ContentF`:" msgstr "" @@ -10924,7 +10924,7 @@ msgstr "" #: text/chapter14.md:551 #, markdown-text msgid "" -"In each case, the expression `rest` has the type `Content Unit`, and " +"In each case, the expression `rest` has the type `Content Unit` and " "represents the remainder of the interpreted computation. We can complete " "each case by returning the `rest` action." msgstr "" @@ -10983,18 +10983,18 @@ msgstr "" #, markdown-text msgid "" "Let's illustrate the power of the free monad construction by extending our " -"language with a new monadic action which returns a non-trivial result." +"language with a new monadic action that returns a non-trivial result." msgstr "" #. type: Plain text #: text/chapter14.md:580 #, markdown-text msgid "" -"Suppose we want to generate HTML documents which contain hyperlinks to " +"Suppose we want to generate HTML documents that contain hyperlinks to " "different sections of the document using _anchors_. We can accomplish this " -"already, by generating anchor names by hand and including them at least " -"twice in the document: once at the definition of the anchor itself, and once " -"in each hyperlink. However, this approach has some basic issues:" +"by generating anchor names by hand and including them at least twice in the " +"document: once at the anchor's definition and once in each " +"hyperlink. However, this approach has some basic issues:" msgstr "" #. type: Bullet: '- ' @@ -11013,9 +11013,9 @@ msgstr "" #: text/chapter14.md:585 #, markdown-text msgid "" -"In the interest of protecting the developer from their own mistakes, we can " -"introduce a new type which represents anchor names, and provide a monadic " -"action for generating new unique names." +"To protect the developer from their mistakes, we can introduce a new type " +"that represents anchor names and provide a monadic action for generating new " +"unique names." msgstr "" #. type: Plain text @@ -11046,8 +11046,8 @@ msgstr "" #: text/chapter14.md:598 #, markdown-text msgid "" -"Next, we define an instance for the `IsValue` type class for our new type, " -"so that we are able to use names in attribute values:" +"Next, we define an instance for the `IsValue` type class for our new type so " +"that we can use names in attribute values:" msgstr "" #. type: Fenced code block (haskell) @@ -11166,21 +11166,20 @@ msgstr "" #: text/chapter14.md:654 #, markdown-text msgid "" -"Notice that we provide the `id` function as our continuation, meaning that " -"we return the result of type `Name` unchanged." +"Notice that we provide the `id` function as our continuation, meaning we " +"return the result of type `Name` unchanged." msgstr "" #. type: Plain text #: text/chapter14.md:656 #, markdown-text msgid "" -"Finally, we need to update our interpretation function, to interpret the new " +"Finally, we need to update our interpretation function to interpret the new " "action. We previously used the `Writer String` monad to interpret our " -"computations, but that monad does not have the ability to generate new " -"names, so we must switch to something else. The `WriterT` monad transformer " -"can be used with the `State` monad to combine the effects we need. We can " -"define our interpretation monad as a type synonym to keep our type " -"signatures short:" +"computations, but that monad cannot generate new names, so we must switch to " +"something else. The `WriterT` monad transformer can be used with the `State` " +"monad to combine the effects we need. We can define our interpretation monad " +"as a type synonym to keep our type signatures short:" msgstr "" #. type: Fenced code block (haskell) @@ -11202,8 +11201,8 @@ msgstr "" #, markdown-text msgid "" "Because the `Writer` and `WriterT` monads use the same type class members to " -"abstract their actions, we do not need to change any actions - we only need " -"to replace every reference to `Writer String` with `Interp`. We do, however, " +"abstract their actions, we do not need to change any actions – we only need " +"to replace every reference to `Writer String` with `Interp`. However, we " "need to modify the handler used to run our computation. Instead of just " "`execWriter`, we now need to use `evalState` as well:" msgstr "" @@ -11251,7 +11250,7 @@ msgstr "" #, markdown-text msgid "" "With that, we can try out our new functionality in PSCi, by generating a " -"unique name inside the `Content` monad, and using it as both the name of an " +"unique name inside the `Content` monad and using it as both the name of an " "element and the target of a hyperlink:" msgstr "" @@ -11280,12 +11279,12 @@ msgstr "" #: text/chapter14.md:703 #, markdown-text msgid "" -"You can verify that multiple calls to `newName` do in fact result in unique " -"names." +"You can verify that multiple calls to `newName` do, in fact, result in " +"unique names." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter14.md:712 +#: text/chapter14.md:711 #, markdown-text msgid "" "(Medium) We can simplify the API further by hiding the `Element` type from " @@ -11293,7 +11292,7 @@ msgid "" msgstr "" #. type: Bullet: ' - ' -#: text/chapter14.md:712 +#: text/chapter14.md:711 #, markdown-text msgid "" "Combine functions like `p` and `img` (with return type `Element`) with the " @@ -11301,25 +11300,30 @@ msgid "" msgstr "" #. type: Bullet: ' - ' -#: text/chapter14.md:712 +#: text/chapter14.md:711 #, markdown-text msgid "" "Change the `render` function to accept an argument of type `Content Unit` " "instead of `Element`." msgstr "" -#. type: Plain text -#: text/chapter14.md:712 -#, markdown-text, no-wrap +#. type: Bullet: ' 1. ' +#: text/chapter14.md:711 +#, markdown-text msgid "" -" 1. (Medium) Hide the implementation of the `Content` monad by using a " -"`newtype` instead of a type synonym. You should not export the data\n" -" constructor for your `newtype`.\n" -" 1. (Difficult) Modify the `ContentF` type to support a new action\n" +"(Medium) Hide the implementation of the `Content` monad using a `newtype` " +"instead of a type synonym. You should not export the data constructor for " +"your `newtype`." +msgstr "" + +#. type: Bullet: ' 1. ' +#: text/chapter14.md:711 +#, markdown-text +msgid "(Difficult) Modify the `ContentF` type to support a new action" msgstr "" #. type: Plain text -#: text/chapter14.md:716 +#: text/chapter14.md:715 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -11328,7 +11332,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter14.md:718 +#: text/chapter14.md:717 #, markdown-text, no-wrap msgid "" " which returns a boolean value indicating whether or not the document is " @@ -11336,7 +11340,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter14.md:720 +#: text/chapter14.md:719 #, markdown-text, no-wrap msgid "" " _Hint_: use the `ask` action and the `ReaderT` monad transformer to " @@ -11345,33 +11349,33 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter14.md:724 +#: text/chapter14.md:723 #, markdown-text msgid "" "In this chapter, we developed a domain-specific language for creating HTML " -"documents, by incrementally improving a naive implementation using some " +"documents by incrementally improving a naive implementation using some " "standard techniques:" msgstr "" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 #, markdown-text msgid "" "We used _smart constructors_ to hide the details of our data representation, " -"only permitting the user to create documents which were " +"only permitting the user to create documents that were " "_correct-by-construction_." msgstr "" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 #, markdown-text msgid "" -"We used an _user-defined infix binary operator_ to improve the syntax of the " +"We used a _user-defined infix binary operator_ to improve the syntax of the " "language." msgstr "" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 #, markdown-text msgid "" "We used _phantom types_ to encode additional information in the types of our " @@ -11379,17 +11383,17 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 #, markdown-text msgid "" "We used the _free monad_ to turn our array representation of a collection of " "content into a monadic representation supporting do notation. We then " -"extended this representation to support a new monadic action, and " -"interpreted the monadic computations using standard monad transformers." +"extended this representation to support a new monadic action and interpreted " +"the monadic computations using standard monad transformers." msgstr "" #. type: Plain text -#: text/chapter14.md:731 +#: text/chapter14.md:730 #, markdown-text msgid "" "These techniques all leverage PureScript's module and type systems, either " @@ -11398,13 +11402,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter14.md:732 +#: text/chapter14.md:731 #, markdown-text msgid "" -"The implementation of domain-specific languages in functional programming " -"languages is an area of active research, but hopefully this provides a " -"useful introduction some simple techniques, and illustrates the power of " -"working in a language with expressive types." +"Implementing domain-specific languages in functional programming languages " +"is an area of active research. Still, hopefully, this provides a useful " +"introduction to some simple techniques and illustrates the power of working " +"in a language with expressive types." msgstr "" #. type: Title # @@ -11497,11 +11501,11 @@ msgid "" "The book repo contains PureScript example code and unit tests for the " "exercises that accompany each chapter. There's some initial setup required " "to reset the exercise solutions so they are ready to be solved by you. Use " -"the `resetSolutions.sh` script to simplify this process. While you're at it, " -"you should also strip out all the anchor comments with the " -"`removeAnchors.sh` script (these anchors are used for copying code snippets " -"into the book's rendered markdown, and you probably don't need this clutter " -"in your local repo):" +"the `resetSolutions.sh` script to simplify this process. While at it, you " +"should also strip out all the anchor comments with the `removeAnchors.sh` " +"script (these anchors are used for copying code snippets into the book's " +"rendered markdown, and you probably don't need this clutter in your local " +"repo):" msgstr "" #. type: Fenced code block (sh) @@ -11552,10 +11556,10 @@ msgstr "" msgid "" "Note that the `answer` function (found in `src/Euler.purs`) has been " "modified to find the multiples of 3 and 5 below any integer. The test suite " -"(found in `test/Main.purs`) for this `answer` function is more comprehensive " -"than the test in the earlier getting-started guide. Don't worry about " -"understanding how this test framework code works while reading these early " -"chapters." +"(located in `test/Main.purs`) for this `answer` function is more " +"comprehensive than the test in the earlier getting-started guide. Don't " +"worry about understanding how this test framework code works while reading " +"these early chapters." msgstr "" #. type: Plain text @@ -11571,7 +11575,7 @@ msgstr "" #: text/chapter2.md:59 #, markdown-text msgid "" -"Let's work through this next exercise together in test-driven-development " +"Let's work through this next exercise together in a test-driven-development " "style." msgstr "" @@ -11601,7 +11605,7 @@ msgstr "" #, markdown-text msgid "" "We'll start by enabling the tests for this exercise. Move the start of the " -"block-comment down a few lines as shown below. Block comments start with " +"block-comment down a few lines, as shown below. Block comments start with " "`{-` and end with `-}`:" msgstr "" @@ -11638,8 +11642,8 @@ msgstr "" #: text/chapter2.md:86 #, markdown-text msgid "" -"Let's first take a look at what happens with a faulty version of this " -"function. Add the following code to `test/MySolutions.purs`:" +"Let's first look at what happens with a faulty version of this function. Add " +"the following code to `test/MySolutions.purs`:" msgstr "" #. type: Fenced code block (hs) @@ -11744,10 +11748,10 @@ msgstr "" #, markdown-text msgid "" "There will be many more exercises in the chapters ahead, and working through " -"those really helps with learning the material. If you're stumped by any of " -"the exercises, please reach out to any of the community resources listed in " -"the [Getting Help](https://book.purescript.org/chapter1.html#getting-help) " -"section of this book, or even file an issue in this [book's " +"those helps with learning the material. If any of the exercises stumps you, " +"please reach out to any of the community resources listed in the [Getting " +"Help](https://book.purescript.org/chapter1.html#getting-help) section of " +"this book, or even file an issue in this [book's " "repo](https://github.com/purescript-contrib/purescript-book/issues). This " "reader feedback on which exercises could be made more approachable helps us " "improve the book." @@ -11758,11 +11762,11 @@ msgstr "" #, markdown-text msgid "" "Once you solve all the exercises in a chapter, you may compare your answers " -"against those in the `no-peeking/Solutions.purs`. No peeking please without " -"putting in an honest effort to solve these yourself though. And even if you " +"against those in the `no-peeking/Solutions.purs`. No peeking, please, " +"without putting in an honest effort to solve these yourself. And even if you " "are stuck, try asking a community member for help first, as we would prefer " "to give you a small hint rather than spoil the exercise. If you found a more " -"elegant solution (that still only requires knowledge of covered content), " +"elegant solution (that only requires knowledge of the covered content), " "please send us a PR." msgstr "" @@ -11830,22 +11834,31 @@ msgid "Here, we import several modules:" msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:24 +#: text/chapter3.md:25 +#, markdown-text +msgid "" +"The `Prelude` module, which contains a small set of standard definitions and " +"functions. It re-exports many foundational modules from " +"the `purescript-prelude` library." +msgstr "" + +#. type: Bullet: '- ' +#: text/chapter3.md:25 #, markdown-text msgid "The `Control.Plus` module, which defines the `empty` value." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:24 +#: text/chapter3.md:25 #, markdown-text msgid "" -"The `Data.List` module, which is provided by the `lists` package which can " -"be installed using Spago. It contains a few functions which we will need for " +"The `Data.List` module, provided by the `lists` package, which can be " +"installed using Spago. It contains a few functions that we will need for " "working with linked lists." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:24 +#: text/chapter3.md:25 #, markdown-text msgid "" "The `Data.Maybe` module, which defines data types and functions for working " @@ -11853,16 +11866,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:26 +#: text/chapter3.md:27 #, markdown-text msgid "" "Notice that the imports for these modules are listed explicitly in " -"parentheses. This is generally a good practice, as it helps to avoid " -"conflicting imports." +"parentheses (except for `Prelude`, which is typically imported as an open " +"import). This is generally a good practice, as it helps to avoid conflicting " +"imports." msgstr "" #. type: Plain text -#: text/chapter3.md:28 +#: text/chapter3.md:29 #, markdown-text msgid "" "Assuming you have cloned the book's source code repository, the project for " @@ -11870,7 +11884,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:29 +#: text/chapter3.md:30 #, no-wrap msgid "" "$ cd chapter3\n" @@ -11878,24 +11892,24 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter3.md:34 +#: text/chapter3.md:35 #, markdown-text, no-wrap msgid "Simple Types" msgstr "" #. type: Plain text -#: text/chapter3.md:37 +#: text/chapter3.md:38 #, markdown-text msgid "" -"PureScript defines three built-in types which correspond to JavaScript's " -"primitive types: numbers, strings and booleans. These are defined in the " +"PureScript defines three built-in types corresponding to JavaScript's " +"primitive types: numbers, strings, and booleans. These are defined in the " "`Prim` module, which is implicitly imported by every module. They are called " "`Number`, `String`, and `Boolean`, respectively, and you can see them in " "PSCi by using the `:type` command to print the types of some simple values:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:38 +#: text/chapter3.md:39 #, no-wrap msgid "" "$ spago repl\n" @@ -11911,15 +11925,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:52 +#: text/chapter3.md:53 #, markdown-text msgid "" -"PureScript defines some other built-in types: integers, characters, arrays, " +"PureScript defines other built-in types: integers, characters, arrays, " "records, and functions." msgstr "" #. type: Plain text -#: text/chapter3.md:54 +#: text/chapter3.md:55 #, markdown-text msgid "" "Integers are differentiated from floating point values of type `Number` by " @@ -11927,7 +11941,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:55 +#: text/chapter3.md:56 #, no-wrap msgid "" "> :type 1\n" @@ -11935,7 +11949,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:61 +#: text/chapter3.md:62 #, markdown-text msgid "" "Character literals are wrapped in single quotes, unlike string literals " @@ -11943,7 +11957,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:62 +#: text/chapter3.md:63 #, no-wrap msgid "" "> :type 'a'\n" @@ -11951,7 +11965,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:68 +#: text/chapter3.md:69 #, markdown-text msgid "" "Arrays correspond to JavaScript arrays, but unlike in JavaScript, all " @@ -11959,7 +11973,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:69 +#: text/chapter3.md:70 #, no-wrap msgid "" "> :type [1, 2, 3]\n" @@ -11973,16 +11987,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:81 +#: text/chapter3.md:82 #, markdown-text msgid "" -"The error in the last example is an error from the type checker, which " -"unsuccessfully attempted to _unify_ (i.e. make equal) the types of the two " -"elements." +"The last example shows an error from the type checker, which failed to " +"_unify_ (i.e., make equal) the types of the two elements." msgstr "" #. type: Plain text -#: text/chapter3.md:83 +#: text/chapter3.md:84 #, markdown-text msgid "" "Records correspond to JavaScript's objects, and record literals have the " @@ -11990,7 +12003,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:84 +#: text/chapter3.md:85 #, no-wrap msgid "" "> author = { name: \"Phil\", interests: [\"Functional Programming\", " @@ -12003,16 +12016,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:94 +#: text/chapter3.md:95 #, markdown-text msgid "" -"This type indicates that the specified object has two _fields_, a `name` " -"field which has type `String`, and an `interests` field, which has type " -"`Array String`, i.e. an array of `String`s." +"This type indicates that the specified object has two _fields_: a `name` " +"field with the type `String` and an `interests` field with the type `Array " +"String`, i.e., an array of `String`s." msgstr "" #. type: Plain text -#: text/chapter3.md:96 +#: text/chapter3.md:97 #, markdown-text msgid "" "Fields of records can be accessed using a dot, followed by the label of the " @@ -12020,7 +12033,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:97 +#: text/chapter3.md:98 #, no-wrap msgid "" "> author.name\n" @@ -12031,57 +12044,40 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:106 -#, markdown-text -msgid "" -"PureScript's functions correspond to JavaScript's functions. The PureScript " -"standard libraries provide plenty of examples of functions, and we will see " -"more in this chapter:" -msgstr "" - -#. type: Fenced code block (text) #: text/chapter3.md:107 -#, no-wrap -msgid "" -"> import Prelude\n" -"> :type flip\n" -"forall a b c. (a -> b -> c) -> b -> a -> c\n" -"\n" -"> :type const\n" -"forall a b. a -> b -> a\n" -msgstr "" - -#. type: Plain text -#: text/chapter3.md:117 #, markdown-text msgid "" -"Functions can be defined at the top-level of a file by specifying arguments " -"before the equals sign:" +"PureScript's functions correspond to JavaScript's functions. Functions can " +"be defined at the top-level of a file by specifying arguments before the " +"equals sign:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:118 +#: text/chapter3.md:108 #, no-wrap msgid "" +"import Prelude -- bring the (+) operator into scope\n" +"\n" "add :: Int -> Int -> Int\n" "add x y = x + y\n" msgstr "" #. type: Plain text -#: text/chapter3.md:124 +#: text/chapter3.md:116 #, markdown-text msgid "" -"Alternatively, functions can be defined inline, by using a backslash " -"character followed by a space-delimited list of argument names. To enter a " -"multi-line declaration in PSCi, we can enter \"paste mode\" by using the " -"`:paste` command. In this mode, declarations are terminated using the " -"_Control-D_ key sequence:" +"Alternatively, functions can be defined inline using a backslash character " +"followed by a space-delimited list of argument names. To enter a multi-line " +"declaration in PSCi, we can enter \"paste mode\" using the `:paste` " +"command. In this mode, declarations are terminated using the _Control-D_ key " +"sequence:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:125 +#: text/chapter3.md:117 #, no-wrap msgid "" +"> import Prelude\n" "> :paste\n" "… add :: Int -> Int -> Int\n" "… add = \\x y -> x + y\n" @@ -12089,7 +12085,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:133 +#: text/chapter3.md:126 #, markdown-text msgid "" "Having defined this function in PSCi, we can _apply_ it to its arguments by " @@ -12097,7 +12093,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:134 +#: text/chapter3.md:127 #, no-wrap msgid "" "> add 10 20\n" @@ -12105,97 +12101,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter3.md:139 -#, markdown-text, no-wrap -msgid "Quantified Types" -msgstr "" - -#. type: Plain text -#: text/chapter3.md:142 -#, markdown-text -msgid "" -"In the previous section, we saw the types of some functions defined in the " -"Prelude. For example, the `flip` function had the following type:" -msgstr "" - -#. type: Fenced code block (text) -#: text/chapter3.md:143 -#, no-wrap -msgid "" -"> :type flip\n" -"forall a b c. (a -> b -> c) -> b -> a -> c\n" -msgstr "" - -#. type: Plain text -#: text/chapter3.md:149 -#, markdown-text -msgid "" -"The keyword `forall` here indicates that `flip` has a _universally " -"quantified type_. It means that we can substitute any types for `a`, `b` and " -"`c`, and `flip` will work with those types." -msgstr "" - -#. type: Plain text -#: text/chapter3.md:151 -#, markdown-text -msgid "" -"For example, we might choose the type `a` to be `Int`, `b` to be `String` " -"and `c` to be `String`. In that case we could _specialize_ the type of " -"`flip` to" -msgstr "" - -#. type: Fenced code block (text) -#: text/chapter3.md:152 -#, no-wrap -msgid "(Int -> String -> String) -> String -> Int -> String\n" -msgstr "" - -#. type: Plain text -#: text/chapter3.md:157 -#, markdown-text -msgid "" -"We don't have to indicate in code that we want to specialize a quantified " -"type - it happens automatically. For example, we can just use `flip` as if " -"it had this type already:" -msgstr "" - -#. type: Fenced code block (text) -#: text/chapter3.md:158 -#, no-wrap -msgid "" -"> flip (\\n s -> show n <> s) \"Ten\" 10\n" -"\n" -"\"10Ten\"\n" -msgstr "" - -#. type: Plain text -#: text/chapter3.md:165 -#, markdown-text -msgid "" -"While we can choose any types for `a`, `b` and `c`, we have to be " -"consistent. The type of the function we passed to `flip` had to be " -"consistent with the types of the other arguments. That is why we passed the " -"string `\"Ten\"` as the second argument, and the number `10` as the " -"third. It would not work if the arguments were reversed:" -msgstr "" - -#. type: Fenced code block (text) -#: text/chapter3.md:166 -#, no-wrap -msgid "" -"> flip (\\n s -> show n <> s) 10 \"Ten\"\n" -"\n" -"Could not match type Int with type String\n" -msgstr "" - -#. type: Title ## -#: text/chapter3.md:172 +#: text/chapter3.md:132 #, markdown-text, no-wrap msgid "Notes On Indentation" msgstr "" #. type: Plain text -#: text/chapter3.md:175 +#: text/chapter3.md:135 #, markdown-text msgid "" "PureScript code is _indentation-sensitive_, just like Haskell, but unlike " @@ -12205,21 +12117,21 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:177 +#: text/chapter3.md:137 #, markdown-text msgid "" -"If a declaration spans multiple lines, then any lines except the first must " -"be indented past the indentation level of the first line." +"If a declaration spans multiple lines, any lines except the first must be " +"indented past the indentation level of the first line." msgstr "" #. type: Plain text -#: text/chapter3.md:179 +#: text/chapter3.md:139 #, markdown-text -msgid "Therefore, the following is valid PureScript code:" +msgid "Therefore, the following is a valid PureScript code:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:180 +#: text/chapter3.md:140 #, no-wrap msgid "" "add x y z = x +\n" @@ -12227,13 +12139,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:186 +#: text/chapter3.md:146 #, markdown-text -msgid "But this is not valid code:" +msgid "But this is not a valid code:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:187 +#: text/chapter3.md:147 #, no-wrap msgid "" "add x y z = x +\n" @@ -12241,7 +12153,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:193 +#: text/chapter3.md:153 #, markdown-text msgid "" "In the second case, the PureScript compiler will try to parse _two_ " @@ -12249,7 +12161,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:195 +#: text/chapter3.md:155 #, markdown-text msgid "" "Generally, any declarations defined in the same block should be indented at " @@ -12258,7 +12170,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:196 +#: text/chapter3.md:156 #, no-wrap msgid "" "> :paste\n" @@ -12268,13 +12180,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:204 +#: text/chapter3.md:164 #, markdown-text -msgid "but this is not:" +msgid "But this is not:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:205 +#: text/chapter3.md:165 #, no-wrap msgid "" "> :paste\n" @@ -12284,47 +12196,60 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:213 +#: text/chapter3.md:173 #, markdown-text msgid "" -"Certain PureScript keywords (such as `where`, `of` and `let`) introduce a " -"new block of code, in which declarations must be further-indented:" +"Certain PureScript keywords introduce a new block of code, in which " +"declarations must be further-indented:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:214 +#: text/chapter3.md:174 #, no-wrap msgid "" -"example x y z = foo + bar\n" -" where\n" +"example x y z =\n" +" let\n" " foo = x * y\n" " bar = y * z\n" +" in\n" +" foo + bar\n" msgstr "" #. type: Plain text -#: text/chapter3.md:222 +#: text/chapter3.md:184 #, markdown-text +msgid "This doesn't compile:" +msgstr "" + +#. type: Fenced code block (haskell) +#: text/chapter3.md:185 +#, no-wrap msgid "" -"Note how the declarations for `foo` and `bar` are indented past the " -"declaration of `example`." +"example x y z =\n" +" let\n" +" foo = x * y\n" +" bar = y * z\n" +" in\n" +" foo + bar\n" msgstr "" #. type: Plain text -#: text/chapter3.md:224 +#: text/chapter3.md:195 #, markdown-text msgid "" -"The only exception to this rule is the `where` keyword in the initial " -"`module` declaration at the top of a source file." +"If you want to learn more (or encounter any problems), see the " +"[Syntax](https://github.com/purescript/documentation/blob/master/language/Syntax.md#syntax) " +"documentation." msgstr "" #. type: Title ## -#: text/chapter3.md:225 +#: text/chapter3.md:196 #, markdown-text, no-wrap msgid "Defining Our Types" msgstr "" #. type: Plain text -#: text/chapter3.md:228 +#: text/chapter3.md:199 #, markdown-text msgid "" "A good first step when tackling a new problem in PureScript is to write out " @@ -12333,64 +12258,64 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:229 +#: text/chapter3.md:200 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}}\n" msgstr "" #. type: Plain text -#: text/chapter3.md:234 +#: text/chapter3.md:205 #, markdown-text msgid "" -"This defines a _type synonym_ called `Entry` - the type `Entry` is " +"This defines a _type synonym_ called `Entry` – the type `Entry` is " "equivalent to the type on the right of the equals symbol: a record type with " -"three fields - `firstName`, `lastName` and `address`. The two name fields " -"will have type `String`, and the `address` field will have type `Address`, " -"defined as follows:" +"three fields – `firstName`, `lastName`, and `address`. The two name fields " +"will have the type `String`, and the `address` field will have the type " +"`Address`, defined as follows:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:235 +#: text/chapter3.md:206 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Address}}\n" msgstr "" #. type: Plain text -#: text/chapter3.md:240 +#: text/chapter3.md:211 #, markdown-text msgid "Note that records can contain other records." msgstr "" #. type: Plain text -#: text/chapter3.md:242 +#: text/chapter3.md:213 #, markdown-text msgid "" -"Now let's define a third type synonym, for our address book data structure, " +"Now let's define a third type synonym for our address book data structure, " "which will be represented simply as a linked list of entries:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:243 +#: text/chapter3.md:214 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}}\n" msgstr "" #. type: Plain text -#: text/chapter3.md:248 +#: text/chapter3.md:219 #, markdown-text msgid "" -"Note that `List Entry` is not the same as `Array Entry`, which represents an " +"Note that `List Entry` differs from `Array Entry`, which represents an " "_array_ of entries." msgstr "" #. type: Title ## -#: text/chapter3.md:249 +#: text/chapter3.md:220 #, markdown-text, no-wrap msgid "Type Constructors and Kinds" msgstr "" #. type: Plain text -#: text/chapter3.md:252 +#: text/chapter3.md:223 #, markdown-text msgid "" "`List` is an example of a _type constructor_. Values do not have the type " @@ -12399,17 +12324,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:254 +#: text/chapter3.md:225 #, markdown-text msgid "" "Note that just like function application, type constructors are applied to " -"other types simply by juxtaposition: the type `List Entry` is in fact the " -"type constructor `List` _applied_ to the type `Entry` - it represents a list " +"other types simply by juxtaposition: the type `List Entry` is, in fact, the " +"type constructor `List` _applied_ to the type `Entry` – it represents a list " "of entries." msgstr "" #. type: Plain text -#: text/chapter3.md:256 +#: text/chapter3.md:227 #, markdown-text msgid "" "If we try to incorrectly define a value of type `List` (by using the type " @@ -12417,7 +12342,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:257 +#: text/chapter3.md:228 #, no-wrap msgid "" "> import Data.List\n" @@ -12426,7 +12351,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:264 +#: text/chapter3.md:235 #, markdown-text msgid "" "This is a _kind error_. Just like values are distinguished by their _types_, " @@ -12435,7 +12360,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:266 +#: text/chapter3.md:237 #, markdown-text msgid "" "There is a special kind called `Type` which represents the kind of all types " @@ -12443,7 +12368,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:268 +#: text/chapter3.md:239 #, markdown-text, no-wrap msgid "" "There are also kinds for type constructors. For example, the kind `Type -> " @@ -12453,7 +12378,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:270 +#: text/chapter3.md:241 #, markdown-text msgid "" "To find out the kind of a type, use the `:kind` command in PSCi. For " @@ -12461,7 +12386,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:271 +#: text/chapter3.md:242 #, no-wrap msgid "" "> :kind Number\n" @@ -12476,7 +12401,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:284 +#: text/chapter3.md:255 #, markdown-text msgid "" "PureScript's _kind system_ supports other interesting kinds, which we will " @@ -12484,13 +12409,114 @@ msgid "" msgstr "" #. type: Title ## +#: text/chapter3.md:256 +#, markdown-text, no-wrap +msgid "Quantified Types" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:259 +#, markdown-text +msgid "" +"For illustration purposes, let's define a primitive function that takes any " +"two arguments and returns the first one:" +msgstr "" + +#. type: Fenced code block (text) +#: text/chapter3.md:260 +#, no-wrap +msgid "" +"> :paste\n" +"… constantlyFirst :: forall a b. a -> b -> a\n" +"… constantlyFirst = \\a b -> a\n" +"… ^D\n" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:275 +#, markdown-text, no-wrap +msgid "" +"> Note that if you use `:type` to ask about the type of `constantlyFirst`, " +"it will be more verbose:\n" +">\n" +"> ```text\n" +"> : type constantlyFirst\n" +"> forall (a :: Type) (b :: Type). a -> b -> a\n" +"> ```\n" +">\n" +"> The type signature contains additional kind information, which explicitly " +"notes that `a` and `b` should be concrete types.\n" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:277 +#, markdown-text +msgid "" +"The keyword `forall` indicates that `constantlyFirst` has a _universally " +"quantified type_. It means we can substitute any types for `a` and `b` – " +"`constantlyFirst` will work with these types." +msgstr "" + +#. type: Plain text +#: text/chapter3.md:279 +#, markdown-text +msgid "" +"For example, we might choose the type `a` to be `Int` and `b` – `String`. In " +"that case, we can _specialize_ the type of `constantlyFirst` to" +msgstr "" + +#. type: Fenced code block (text) +#: text/chapter3.md:280 +#, no-wrap +msgid "Int -> String -> Int\n" +msgstr "" + +#. type: Plain text #: text/chapter3.md:285 +#, markdown-text +msgid "" +"We don't have to indicate in code that we want to specialize a quantified " +"type – it happens automatically. For example, we can use `constantlyFirst` " +"as if it had this type already:" +msgstr "" + +#. type: Fenced code block (text) +#: text/chapter3.md:286 +#, no-wrap +msgid "" +"> constantlyFirst 3 \"ignored\"\n" +"\n" +"3\n" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:293 +#, markdown-text +msgid "" +"While we can choose any types for `a` and `b`, the return type of " +"`constantlyFirst` has to be the same as the type of the first argument " +"(because both of them are \"tied\" to the same `a`):" +msgstr "" + +#. type: Fenced code block (text) +#: text/chapter3.md:294 +#, no-wrap +msgid "" +":type constantlyFirst true \"ignored\"\n" +"Boolean\n" +"\n" +":type constantlyFirst \"keep\" 3\n" +"String\n" +msgstr "" + +#. type: Title ## +#: text/chapter3.md:302 #, markdown-text, no-wrap msgid "Displaying Address Book Entries" msgstr "" #. type: Plain text -#: text/chapter3.md:288 +#: text/chapter3.md:305 #, markdown-text msgid "" "Let's write our first function, which will render an address book entry as a " @@ -12502,7 +12528,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:289 +#: text/chapter3.md:306 #, no-wrap msgid "" "{{#include " @@ -12510,16 +12536,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:294 +#: text/chapter3.md:311 #, markdown-text msgid "" -"This type signature says that `showEntry` is a function, which takes an " +"This type signature says that `showEntry` is a function that takes an " "`Entry` as an argument and returns a `String`. Here is the code for " "`showEntry`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:295 +#: text/chapter3.md:312 #, no-wrap msgid "" "{{#include " @@ -12527,7 +12553,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:300 +#: text/chapter3.md:317 #, markdown-text msgid "" "This function concatenates the three fields of the `Entry` record into a " @@ -12536,13 +12562,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:301 +#: text/chapter3.md:318 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showAddress}}\n" msgstr "" #. type: Plain text -#: text/chapter3.md:306 +#: text/chapter3.md:323 #, markdown-text, no-wrap msgid "" "A function definition begins with the name of the function, followed by a " @@ -12553,13 +12579,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter3.md:307 +#: text/chapter3.md:324 #, markdown-text, no-wrap msgid "Test Early, Test Often" msgstr "" #. type: Plain text -#: text/chapter3.md:310 +#: text/chapter3.md:327 #, markdown-text msgid "" "The PSCi interactive mode allows for rapid prototyping with immediate " @@ -12568,19 +12594,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:312 +#: text/chapter3.md:329 #, markdown-text msgid "First, build the code you've written:" msgstr "" #. type: Plain text -#: text/chapter3.md:318 +#: text/chapter3.md:335 #, markdown-text msgid "Next, load PSCi, and use the `import` command to import your new module:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:319 +#: text/chapter3.md:336 #, no-wrap msgid "" "$ spago repl\n" @@ -12589,7 +12615,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:326 +#: text/chapter3.md:343 #, markdown-text msgid "" "We can create an entry by using a record literal, which looks just like an " @@ -12597,7 +12623,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:327 +#: text/chapter3.md:344 #, no-wrap msgid "" "> address = { street: \"123 Fake St.\", city: \"Faketown\", state: \"CA\" " @@ -12605,13 +12631,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:332 +#: text/chapter3.md:349 #, markdown-text msgid "Now, try applying our function to the example:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:333 +#: text/chapter3.md:350 #, no-wrap msgid "" "> showAddress address\n" @@ -12620,7 +12646,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:340 +#: text/chapter3.md:357 #, markdown-text msgid "" "Let's also test `showEntry` by creating an address book entry record " @@ -12628,7 +12654,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:341 +#: text/chapter3.md:358 #, no-wrap msgid "" "> entry = { firstName: \"John\", lastName: \"Smith\", address: address }\n" @@ -12638,27 +12664,27 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter3.md:348 +#: text/chapter3.md:365 #, markdown-text, no-wrap msgid "Creating Address Books" msgstr "" #. type: Plain text -#: text/chapter3.md:351 +#: text/chapter3.md:368 #, markdown-text msgid "" "Now let's write some utility functions for working with address books. We " -"will need a value which represents an empty address book: an empty list." +"will need a value representing an empty address book: an empty list." msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:352 +#: text/chapter3.md:369 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:emptyBook}}\n" msgstr "" #. type: Plain text -#: text/chapter3.md:357 +#: text/chapter3.md:374 #, markdown-text msgid "" "We will also need a function for inserting a value into an existing address " @@ -12666,7 +12692,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:358 +#: text/chapter3.md:375 text/chapter3.md:459 #, no-wrap msgid "" "{{#include " @@ -12674,28 +12700,28 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:363 +#: text/chapter3.md:380 #, markdown-text msgid "" "This type signature says that `insertEntry` takes an `Entry` as its first " -"argument, and an `AddressBook` as a second argument, and returns a new " +"argument, an `AddressBook` as a second argument, and returns a new " "`AddressBook`." msgstr "" #. type: Plain text -#: text/chapter3.md:365 +#: text/chapter3.md:382 #, markdown-text msgid "" "We don't modify the existing `AddressBook` directly. Instead, we return a " -"new `AddressBook` which contains the same data. As such, `AddressBook` is an " -"example of an _immutable data structure_. This is an important idea in " -"PureScript - mutation is a side-effect of code, and inhibits our ability to " +"new `AddressBook`, which contains the same data. As such, `AddressBook` is " +"an example of an _immutable data structure_. This is an important idea in " +"PureScript – mutation is a side-effect of code and inhibits our ability to " "reason effectively about its behavior, so we prefer pure functions and " "immutable data where possible." msgstr "" #. type: Plain text -#: text/chapter3.md:367 +#: text/chapter3.md:384 #, markdown-text msgid "" "To implement `insertEntry`, we can use the `Cons` function from " @@ -12703,7 +12729,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:368 +#: text/chapter3.md:385 #, no-wrap msgid "" "$ spago repl\n" @@ -12711,38 +12737,38 @@ msgid "" "> import Data.List\n" "> :type Cons\n" "\n" -"forall a. a -> List a -> List a\n" +"forall (a :: Type). a -> List a -> List a\n" msgstr "" #. type: Plain text -#: text/chapter3.md:378 +#: text/chapter3.md:395 #, markdown-text msgid "" -"This type signature says that `Cons` takes a value of some type `a`, and a " +"This type signature says that `Cons` takes a value of some type `a`, takes a " "list of elements of type `a`, and returns a new list with entries of the " "same type. Let's specialize this with `a` as our `Entry` type:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:379 +#: text/chapter3.md:396 #, no-wrap msgid "Entry -> List Entry -> List Entry\n" msgstr "" #. type: Plain text -#: text/chapter3.md:384 +#: text/chapter3.md:401 #, markdown-text msgid "But `List Entry` is the same as `AddressBook`, so this is equivalent to" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:385 +#: text/chapter3.md:402 #, no-wrap msgid "Entry -> AddressBook -> AddressBook\n" msgstr "" #. type: Plain text -#: text/chapter3.md:390 +#: text/chapter3.md:407 #, markdown-text msgid "" "In our case, we already have the appropriate inputs: an `Entry`, and an " @@ -12751,74 +12777,152 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:392 +#: text/chapter3.md:409 #, markdown-text msgid "Here is our implementation of `insertEntry`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:393 +#: text/chapter3.md:410 #, no-wrap msgid "insertEntry entry book = Cons entry book\n" msgstr "" #. type: Plain text -#: text/chapter3.md:398 +#: text/chapter3.md:415 #, markdown-text msgid "" -"This brings the two arguments `entry` and `book` into scope, on the left " -"hand side of the equals symbol, and then applies the `Cons` function to " -"create the result." +"This brings the two arguments `entry` and `book` into scope – on the " +"left-hand side of the equals symbol – and then applies the `Cons` function " +"to create the result." msgstr "" #. type: Title ## -#: text/chapter3.md:399 +#: text/chapter3.md:416 #, markdown-text, no-wrap msgid "Curried Functions" msgstr "" #. type: Plain text -#: text/chapter3.md:402 +#: text/chapter3.md:419 #, markdown-text msgid "" "Functions in PureScript take exactly one argument. While it looks like the " -"`insertEntry` function takes two arguments, it is in fact an example of a " -"_curried function_." +"`insertEntry` function takes two arguments, it is an example of a _curried " +"function_. In PureScript, all functions are considered curried." +msgstr "" + +#. type: Plain text +#: text/chapter3.md:421 +#, markdown-text +msgid "" +"Currying means converting a function that takes multiple arguments into a " +"function that takes them one at a time. When we call a function, we pass it " +"one argument, and it returns another function that also takes one argument " +"until all arguments are passed." +msgstr "" + +#. type: Plain text +#: text/chapter3.md:423 +#, markdown-text +msgid "" +"For example, when we pass `5` to `add`, we get another function, which takes " +"an int, adds 5 to it, and returns the sum as a result:" +msgstr "" + +#. type: Fenced code block (haskell) +#: text/chapter3.md:424 +#, no-wrap +msgid "" +"add :: Int -> Int -> Int\n" +"add x y = x + y\n" +"\n" +"addFive :: Int -> Int\n" +"addFive = add 5\n" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:433 +#, markdown-text +msgid "" +"`addFive` is the result of _partial application_, which means we pass less " +"than the total number of arguments to a function that takes multiple " +"arguments. Let's give it a try:" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:443 +#, markdown-text, no-wrap +msgid "" +"> Note that you must define the `add` function if you haven't already:\n" +">\n" +"> ```text\n" +"> > import Prelude\n" +"> > :paste\n" +">… add :: Int -> Int -> Int\n" +">… add x y = x + y\n" +">… ^D\n" +"> ```\n" +msgstr "" + +#. type: Fenced code block (text) +#: text/chapter3.md:444 +#, no-wrap +msgid "" +"> :paste\n" +"… addFive :: Int -> Int\n" +"… addFive = add 5\n" +"… ^D\n" +"\n" +"> addFive 1\n" +"6\n" +"\n" +"> add 5 1\n" +"6\n" +msgstr "" + +#. type: Plain text +#: text/chapter3.md:458 +#, markdown-text +msgid "" +"To better understand currying and partial application, try making a few " +"other functions, for example, out of `add`. And when you're done, let's " +"return to the `insertEntry`." msgstr "" #. type: Plain text -#: text/chapter3.md:404 +#: text/chapter3.md:464 #, markdown-text, no-wrap msgid "" -"The `->` operator in the type of `insertEntry` associates to the right, " -"which means that the compiler parses the type as\n" +"The `->` operator (in the type signature) associates to the right, which " +"means that the compiler parses the type as\n" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:405 +#: text/chapter3.md:465 #, no-wrap msgid "Entry -> (AddressBook -> AddressBook)\n" msgstr "" #. type: Plain text -#: text/chapter3.md:410 +#: text/chapter3.md:470 #, markdown-text msgid "" -"That is, `insertEntry` is a function which returns a function! It takes a " -"single argument, an `Entry`, and returns a new function, which in turn takes " -"a single `AddressBook` argument and returns a new `AddressBook`." +"`insertEntry` takes a single argument, an `Entry`, and returns a new " +"function, which in turn takes a single `AddressBook` argument and returns a " +"new `AddressBook`." msgstr "" #. type: Plain text -#: text/chapter3.md:412 +#: text/chapter3.md:472 #, markdown-text msgid "" -"This means that we can _partially apply_ `insertEntry` by specifying only " -"its first argument, for example. In PSCi, we can see the result type:" +"This means we can _partially apply_ `insertEntry` by specifying only its " +"first argument, for example. In PSCi, we can see the result type:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:413 +#: text/chapter3.md:473 #, no-wrap msgid "" "> :type insertEntry entry\n" @@ -12827,7 +12931,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:420 +#: text/chapter3.md:480 #, markdown-text msgid "" "As expected, the return type was a function. We can apply the resulting " @@ -12835,7 +12939,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:421 +#: text/chapter3.md:481 #, no-wrap msgid "" "> :type (insertEntry entry) emptyBook\n" @@ -12843,15 +12947,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:427 +#: text/chapter3.md:487 #, markdown-text msgid "" -"Note though that the parentheses here are unnecessary - the following is " +"Note though, that the parentheses here are unnecessary – the following is " "equivalent:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:428 +#: text/chapter3.md:488 #, no-wrap msgid "" "> :type insertEntry entry emptyBook\n" @@ -12859,25 +12963,25 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:434 +#: text/chapter3.md:494 #, markdown-text msgid "" -"This is because function application associates to the left, and this " -"explains why we can just specify function arguments one after the other, " -"separated by whitespace." +"This is because function application associates to the left, which explains " +"why we can specify function arguments one after the other, separated by " +"whitespace." msgstr "" #. type: Plain text -#: text/chapter3.md:436 +#: text/chapter3.md:496 #, markdown-text, no-wrap msgid "" "The `->` operator in function types is a _type constructor_ for " -"functions. It takes two type arguments, the function's argument type and the " -"return type. The left and right operands respectively.\n" +"functions. It takes two type arguments: the function's argument type and the " +"return type – the left and right operands, respectively.\n" msgstr "" #. type: Plain text -#: text/chapter3.md:438 +#: text/chapter3.md:498 #, markdown-text msgid "" "Note that in the rest of the book, I will talk about things like \"functions " @@ -12887,13 +12991,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:440 +#: text/chapter3.md:500 #, markdown-text msgid "Now consider the definition of `insertEntry`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:441 +#: text/chapter3.md:501 #, no-wrap msgid "" "insertEntry :: Entry -> AddressBook -> AddressBook\n" @@ -12901,18 +13005,18 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:447 +#: text/chapter3.md:507 #, markdown-text msgid "" "If we explicitly parenthesize the right-hand side, we get `(Cons entry) " "book`. That is, `insertEntry entry` is a function whose argument is just " "passed along to the `(Cons entry)` function. But if two functions have the " -"same result for every input, then they are the same function! So we can " -"remove the argument `book` from both sides:" +"same result for every input, then they are the same! So we can remove the " +"argument `book` from both sides:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:448 +#: text/chapter3.md:508 #, no-wrap msgid "" "insertEntry :: Entry -> AddressBook -> AddressBook\n" @@ -12920,44 +13024,44 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:454 +#: text/chapter3.md:514 #, markdown-text msgid "But now, by the same argument, we can remove `entry` from both sides:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:455 +#: text/chapter3.md:515 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}}\n" msgstr "" #. type: Plain text -#: text/chapter3.md:460 +#: text/chapter3.md:520 #, markdown-text msgid "" -"This process is called _eta conversion_, and can be used (along with some " -"other techniques) to rewrite functions in _point-free form_, which means " -"functions defined without reference to their arguments." +"This process, called _eta conversion_, can be used (along with other " +"techniques) to rewrite functions in _point-free form_, which means functions " +"defined without reference to their arguments." msgstr "" #. type: Plain text -#: text/chapter3.md:462 +#: text/chapter3.md:522 #, markdown-text msgid "" "In the case of `insertEntry`, _eta conversion_ has resulted in a very clear " -"definition of our function - \"`insertEntry` is just cons on " -"lists\". However, it is arguable whether point-free form is better in " +"definition of our function – \"`insertEntry` is just cons on " +"lists\". However, it is arguable whether the point-free form is better in " "general." msgstr "" #. type: Title ## -#: text/chapter3.md:463 +#: text/chapter3.md:523 #, markdown-text, no-wrap msgid "Property Accessors" msgstr "" #. type: Plain text -#: text/chapter3.md:466 +#: text/chapter3.md:526 #, markdown-text msgid "" "One common pattern is to use a function to access individual fields (or " @@ -12966,13 +13070,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:467 +#: text/chapter3.md:527 #, no-wrap msgid "\\entry -> entry.address\n" msgstr "" #. type: Plain text -#: text/chapter3.md:472 +#: text/chapter3.md:532 #, markdown-text msgid "" "PureScript also allows [_property " @@ -12982,13 +13086,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:473 +#: text/chapter3.md:533 #, no-wrap msgid "_.address\n" msgstr "" #. type: Plain text -#: text/chapter3.md:478 +#: text/chapter3.md:538 #, markdown-text msgid "" "This works with any number of levels or properties, so a function to extract " @@ -12996,19 +13100,19 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:479 +#: text/chapter3.md:539 #, no-wrap msgid "_.address.city\n" msgstr "" #. type: Plain text -#: text/chapter3.md:484 text/chapter5.md:247 +#: text/chapter3.md:544 text/chapter5.md:247 #, markdown-text msgid "For example:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:485 +#: text/chapter3.md:545 #, no-wrap msgid "" "> address = { street: \"123 Fake St.\", city: \"Faketown\", state: \"CA\" " @@ -13022,41 +13126,41 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter3.md:495 +#: text/chapter3.md:555 #, markdown-text, no-wrap msgid "Querying the Address Book" msgstr "" #. type: Plain text -#: text/chapter3.md:498 +#: text/chapter3.md:558 #, markdown-text msgid "" "The last function we need to implement for our minimal address book " "application will look up a person by name and return the correct " "`Entry`. This will be a nice application of building programs by composing " -"small functions - a key idea from functional programming." +"small functions – a key idea from functional programming." msgstr "" #. type: Plain text -#: text/chapter3.md:500 +#: text/chapter3.md:560 #, markdown-text msgid "" -"We can first filter the address book, keeping only those entries with the " -"correct first and last names. Then we can simply return the head " -"(i.e. first) element of the resulting list." +"We can filter the address book, keeping only those entries with the correct " +"first and last names. Then we can return the head (i.e., first) element of " +"the resulting list." msgstr "" #. type: Plain text -#: text/chapter3.md:502 +#: text/chapter3.md:562 #, markdown-text msgid "" "With this high-level specification of our approach, we can calculate the " -"type of our function. First open PSCi, and find the types of the `filter` " +"type of our function. First, open PSCi, and find the types of the `filter` " "and `head` functions:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:503 +#: text/chapter3.md:563 #, no-wrap msgid "" "$ spago repl\n" @@ -13064,34 +13168,34 @@ msgid "" "> import Data.List\n" "> :type filter\n" "\n" -"forall a. (a -> Boolean) -> List a -> List a\n" +"forall (a :: Type). (a -> Boolean) -> List a -> List a\n" "\n" "> :type head\n" "\n" -"forall a. List a -> Maybe a\n" +"forall (a :: Type). List a -> Maybe a\n" msgstr "" #. type: Plain text -#: text/chapter3.md:517 +#: text/chapter3.md:577 #, markdown-text msgid "Let's pick apart these two types to understand their meaning." msgstr "" #. type: Plain text -#: text/chapter3.md:519 +#: text/chapter3.md:579 #, markdown-text msgid "" "`filter` is a curried function of two arguments. Its first argument is a " -"function, which takes an element of the list and returns a `Boolean` value " -"as a result. Its second argument is a list of elements, and the return value " -"is another list." +"function, which takes an element of the list and returns a `Boolean` " +"value. Its second argument is a list of elements, and the return value is " +"another list." msgstr "" #. type: Plain text -#: text/chapter3.md:521 +#: text/chapter3.md:581 #, markdown-text msgid "" -"`head` takes a list as its argument, and returns a type we haven't seen " +"`head` takes a list as its argument and returns a type we haven't seen " "before: `Maybe a`. `Maybe a` represents an optional value of type `a`, and " "provides a type-safe alternative to using `null` to indicate a missing value " "in languages like JavaScript. We will see it again in more detail in later " @@ -13099,7 +13203,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:523 +#: text/chapter3.md:583 #, markdown-text msgid "" "The universally quantified types of `filter` and `head` can be _specialized_ " @@ -13107,7 +13211,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:524 +#: text/chapter3.md:584 #, no-wrap msgid "" "filter :: (Entry -> Boolean) -> AddressBook -> AddressBook\n" @@ -13116,15 +13220,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:531 +#: text/chapter3.md:591 #, markdown-text msgid "" "We know that we will need to pass the first and last names that we want to " -"search for, as arguments to our function." +"search for as arguments to our function." msgstr "" #. type: Plain text -#: text/chapter3.md:533 +#: text/chapter3.md:593 #, markdown-text, no-wrap msgid "" "We also know that we will need a function to pass to `filter`. Let's call " @@ -13135,7 +13239,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:535 +#: text/chapter3.md:595 #, markdown-text msgid "" "Putting these facts together, a reasonable type signature for our function, " @@ -13143,7 +13247,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:536 +#: text/chapter3.md:596 #, no-wrap msgid "" "{{#include " @@ -13151,23 +13255,23 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:541 +#: text/chapter3.md:601 #, markdown-text msgid "" -"This type signature says that `findEntry` takes two strings, the first and " -"last names, and a `AddressBook`, and returns an optional `Entry`. The " +"This type signature says that `findEntry` takes two strings: the first and " +"last names, takes an `AddressBook`, and returns an optional `Entry`. The " "optional result will contain a value only if the name is found in the " "address book." msgstr "" #. type: Plain text -#: text/chapter3.md:543 +#: text/chapter3.md:603 #, markdown-text msgid "And here is the definition of `findEntry`:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:544 +#: text/chapter3.md:604 #, no-wrap msgid "" "findEntry firstName lastName book = head (filter filterEntry book)\n" @@ -13178,13 +13282,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:552 +#: text/chapter3.md:612 #, markdown-text msgid "Let's go over this code step by step." msgstr "" #. type: Plain text -#: text/chapter3.md:554 +#: text/chapter3.md:614 #, markdown-text msgid "" "`findEntry` brings three names into scope: `firstName` and `lastName`, both " @@ -13192,16 +13296,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:556 +#: text/chapter3.md:616 #, markdown-text msgid "" -"The right hand side of the definition combines the `filter` and `head` " +"The right-hand side of the definition combines the `filter` and `head` " "functions: first, the list of entries is filtered, and the `head` function " "is applied to the result." msgstr "" #. type: Plain text -#: text/chapter3.md:558 +#: text/chapter3.md:618 #, markdown-text msgid "" "The predicate function `filterEntry` is defined as an auxiliary declaration " @@ -13213,74 +13317,74 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:560 +#: text/chapter3.md:620 #, markdown-text msgid "" -"Note that, just like for top-level declarations, it was not necessary to " +"Note that, just like for top-level declarations, it was unnecessary to " "specify a type signature for `filterEntry`. However, doing so is recommended " "as a form of documentation." msgstr "" #. type: Title ## -#: text/chapter3.md:561 +#: text/chapter3.md:621 #, markdown-text, no-wrap msgid "Infix Function Application" msgstr "" #. type: Plain text -#: text/chapter3.md:564 +#: text/chapter3.md:624 #, markdown-text msgid "" -"Most of the functions discussed so far used _prefix_ function application, " -"where the function name was put _before_ the arguments. For example, when " -"using the `insertEntry` function to add an `Entry` (`john`) to an empty " +"Most functions discussed so far used _prefix_ function application, where " +"the function name was put _before_ the arguments. For example, when using " +"the `insertEntry` function to add an `Entry` (`john`) to an empty " "`AddressBook`, we might write:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:565 +#: text/chapter3.md:625 #, no-wrap msgid "> book1 = insertEntry john emptyBook\n" msgstr "" #. type: Plain text -#: text/chapter3.md:570 +#: text/chapter3.md:630 #, markdown-text msgid "" "However, this chapter has also included examples of _infix_ [binary " "operators](https://github.com/purescript/documentation/blob/master/language/Syntax.md#binary-operators), " "such as the `==` operator in the definition of `filterEntry`, where the " "operator is put _between_ the two arguments. These infix operators are " -"actually defined in the PureScript source as infix aliases for their " -"underlying _prefix_ implementations. For example, `==` is defined as an " -"infix alias for the prefix `eq` function with the line:" +"defined in the PureScript source as infix aliases for their underlying " +"_prefix_ implementations. For example, `==` is defined as an infix alias for " +"the prefix `eq` function with the line:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:571 +#: text/chapter3.md:631 #, no-wrap msgid "infix 4 eq as ==\n" msgstr "" #. type: Plain text -#: text/chapter3.md:576 +#: text/chapter3.md:636 #, markdown-text msgid "" -"and therefore `entry.firstName == firstName` in `filterEntry` could be " -"replaced with the `eq entry.firstName firstName`. We'll cover a few more " -"examples of defining infix operators later in this section." +"Therefore `entry.firstName == firstName` in `filterEntry` could be replaced " +"with the `eq entry.firstName firstName`. We'll cover a few more examples of " +"defining infix operators later in this section." msgstr "" #. type: Plain text -#: text/chapter3.md:578 +#: text/chapter3.md:638 #, markdown-text msgid "" -"There are situations where putting a prefix function in an infix position as " -"an operator leads to more readable code. One example is the `mod` function:" +"In some situations, putting a prefix function in an infix position as an " +"operator leads to more readable code. One example is the `mod` function:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:579 +#: text/chapter3.md:639 #, no-wrap msgid "" "> mod 8 3\n" @@ -13288,16 +13392,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:585 +#: text/chapter3.md:645 #, markdown-text msgid "" -"The above usage works fine, but is awkward to read. A more familiar phrasing " +"The above usage works fine but is awkward to read. A more familiar phrasing " "is \"eight mod three\", which you can achieve by wrapping a prefix function " "in backticks (\\`):" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:586 +#: text/chapter3.md:646 #, no-wrap msgid "" "> 8 `mod` 3\n" @@ -13305,7 +13409,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:592 +#: text/chapter3.md:652 #, markdown-text msgid "" "In the same way, wrapping `insertEntry` in backticks turns it into an infix " @@ -13313,7 +13417,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:593 +#: text/chapter3.md:653 #, no-wrap msgid "" "book1 = insertEntry john emptyBook\n" @@ -13321,7 +13425,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:599 +#: text/chapter3.md:659 #, markdown-text msgid "" "We can make an `AddressBook` with multiple entries by using multiple " @@ -13330,7 +13434,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:600 +#: text/chapter3.md:660 #, no-wrap msgid "" "book3 = insertEntry john (insertEntry peggy (insertEntry ned emptyBook))\n" @@ -13339,7 +13443,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:606 +#: text/chapter3.md:666 #, markdown-text msgid "" "We can also define an infix operator alias (or synonym) for `insertEntry.` " @@ -13351,39 +13455,39 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:607 +#: text/chapter3.md:667 #, no-wrap msgid "infixr 5 insertEntry as ++\n" msgstr "" #. type: Plain text -#: text/chapter3.md:612 +#: text/chapter3.md:672 #, markdown-text msgid "This new operator lets us rewrite the above `book4` example as:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:613 +#: text/chapter3.md:673 #, no-wrap msgid "book5 = john ++ (peggy ++ (ned ++ emptyBook))\n" msgstr "" #. type: Plain text -#: text/chapter3.md:618 +#: text/chapter3.md:678 #, markdown-text msgid "" -"and the right associativity of our new `++` operator lets us get rid of the " +"The right associativity of our new `++` operator lets us get rid of the " "parentheses without changing the meaning:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:619 +#: text/chapter3.md:679 #, no-wrap msgid "book6 = john ++ peggy ++ ned ++ emptyBook\n" msgstr "" #. type: Plain text -#: text/chapter3.md:624 +#: text/chapter3.md:684 #, markdown-text msgid "" "Another common technique for eliminating parens is to use `apply`'s infix " @@ -13391,19 +13495,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:626 +#: text/chapter3.md:686 #, markdown-text msgid "For example, the earlier `book3` example could be rewritten as:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:627 +#: text/chapter3.md:687 #, no-wrap msgid "book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook\n" msgstr "" #. type: Plain text -#: text/chapter3.md:632 +#: text/chapter3.md:692 #, markdown-text msgid "" "Substituting `$` for parens is usually easier to type and (arguably) easier " @@ -13413,16 +13517,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:634 +#: text/chapter3.md:694 #, markdown-text msgid "" -"Note that `$` isn't special syntax that's hardcoded into the language. It's " +"Note that `$` isn't a special syntax hardcoded into the language. It's " "simply the infix operator for a regular function called `apply`, which is " "defined in `Data.Function` as follows:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:635 +#: text/chapter3.md:695 #, no-wrap msgid "" "apply :: forall a b. (a -> b) -> a -> b\n" @@ -13432,7 +13536,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:643 +#: text/chapter3.md:703 #, markdown-text, no-wrap msgid "" "The `apply` function takes another function (of type `(a -> b)`) as its " @@ -13448,7 +13552,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:645 +#: text/chapter3.md:705 #, markdown-text msgid "" "Another parens-busting opportunity for the `$` operator is in our earlier " @@ -13456,13 +13560,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:646 +#: text/chapter3.md:706 #, no-wrap msgid "findEntry firstName lastName book = head $ filter filterEntry book\n" msgstr "" #. type: Plain text -#: text/chapter3.md:651 +#: text/chapter3.md:711 #, markdown-text msgid "" "We'll see an even more elegant way to rewrite this line with \"function " @@ -13470,7 +13574,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:653 +#: text/chapter3.md:713 #, markdown-text msgid "" "If you'd like to use a concise infix operator alias as a prefix function, " @@ -13478,7 +13582,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:654 +#: text/chapter3.md:714 #, no-wrap msgid "" "> 8 + 3\n" @@ -13489,7 +13593,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:663 +#: text/chapter3.md:723 #, markdown-text msgid "" "Alternatively, operators can be partially applied by surrounding the " @@ -13501,7 +13605,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:664 +#: text/chapter3.md:724 #, no-wrap msgid "" "> add3 = (3 + _)\n" @@ -13510,7 +13614,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:671 +#: text/chapter3.md:731 #, markdown-text msgid "" "To summarize, the following are equivalent definitions of a function that " @@ -13518,7 +13622,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:672 +#: text/chapter3.md:732 #, no-wrap msgid "" "add5 x = 5 + x\n" @@ -13533,13 +13637,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter3.md:683 +#: text/chapter3.md:743 #, markdown-text, no-wrap msgid "Function Composition" msgstr "" #. type: Plain text -#: text/chapter3.md:686 +#: text/chapter3.md:746 #, markdown-text msgid "" "Just like we were able to simplify the `insertEntry` function by using eta " @@ -13548,7 +13652,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:688 +#: text/chapter3.md:748 #, markdown-text msgid "" "Note that the `book` argument is passed to the `filter filterEntry` " @@ -13558,7 +13662,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:690 +#: text/chapter3.md:750 #, markdown-text, no-wrap msgid "" "In PureScript, the function composition operators are `<<<` and `>>>`. The " @@ -13567,7 +13671,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:692 +#: text/chapter3.md:752 #, markdown-text msgid "" "We can rewrite the right-hand side of `findEntry` using either " @@ -13575,13 +13679,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:693 +#: text/chapter3.md:753 #, no-wrap msgid "(head <<< filter filterEntry) book\n" msgstr "" #. type: Plain text -#: text/chapter3.md:698 +#: text/chapter3.md:758 #, markdown-text msgid "" "In this form, we can apply the eta conversion trick from earlier, to arrive " @@ -13589,7 +13693,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:699 +#: text/chapter3.md:759 #, no-wrap msgid "" "{{#include " @@ -13598,19 +13702,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:705 +#: text/chapter3.md:765 #, markdown-text msgid "An equally valid right-hand side would be:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:706 +#: text/chapter3.md:766 #, no-wrap msgid "filter filterEntry >>> head\n" msgstr "" #. type: Plain text -#: text/chapter3.md:711 +#: text/chapter3.md:771 #, markdown-text msgid "" "Either way, this gives a clear definition of the `findEntry` function: " @@ -13619,17 +13723,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:713 +#: text/chapter3.md:773 #, markdown-text msgid "" -"I will let you make your own decision which definition is easier to " -"understand, but it is often useful to think of functions as building blocks " -"in this way - each function executing a single task, and solutions assembled " -"using function composition." +"I will let you decide which definition is easier to understand, but it is " +"often useful to think of functions as building blocks in this way: each " +"function executes a single task, and solutions are assembled using function " +"composition." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" "(Easy) Test your understanding of the `findEntry` function by writing down " @@ -13639,7 +13743,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" "(Medium) Write a function `findEntryByStreet :: String -> AddressBook -> " @@ -13649,7 +13753,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" "(Medium) Rewrite `findEntryByStreet` to replace `filterEntry` with the " @@ -13659,17 +13763,17 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" -"(Medium) Write a function `isInBook` which tests whether a name appears in a " +"(Medium) Write a function `isInBook` that tests whether a name appears in a " "`AddressBook`, returning a Boolean value. _Hint_: Use PSCi to find the type " "of the `Data.List.null` function, which tests whether a list is empty or " "not." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" "(Difficult) Write a function `removeDuplicates` which removes \"duplicate\" " @@ -13677,64 +13781,64 @@ msgid "" "same first and last names, while ignoring `address` fields. _Hint_: Use PSCi " "to find the type of the `Data.List.nubByEq` function, which removes " "duplicate elements from a list based on an equality predicate. Note that the " -"first element in each set of duplicates (closest to list head) is the one " -"that is kept." +"first element in each set of duplicates (closest to the list head) is the " +"one that is kept." msgstr "" #. type: Plain text -#: text/chapter3.md:725 +#: text/chapter3.md:785 #, markdown-text -msgid "In this chapter, we covered several new functional programming concepts:" +msgid "" +"In this chapter, we covered several new functional programming concepts and " +"learned how to:" msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text -msgid "" -"How to use the interactive mode PSCi to experiment with functions and test " -"ideas." +msgid "Use the interactive mode PSCi to experiment with functions and test ideas." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text -msgid "The role of types as both a correctness tool, and an implementation tool." +msgid "Use types as both a correctness tool and an implementation tool." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text -msgid "The use of curried functions to represent functions of multiple arguments." +msgid "Use curried functions to represent functions of multiple arguments." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text -msgid "Creating programs from smaller components by composition." +msgid "Create programs from smaller components by composition." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text -msgid "Structuring code neatly using `where` expressions." +msgid "Structure code neatly using `where` expressions." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text -msgid "How to avoid null values by using the `Maybe` type." +msgid "Avoid null values by using the `Maybe` type." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text msgid "" -"Using techniques like eta conversion and function composition to refactor " -"code into a clear specification." +"Use techniques like eta conversion and function composition to refactor code " +"into a clear specification." msgstr "" #. type: Plain text -#: text/chapter3.md:734 +#: text/chapter3.md:794 #, markdown-text msgid "In the following chapters, we'll build on these ideas." msgstr "" @@ -13742,7 +13846,7 @@ msgstr "" #. type: Title # #: text/chapter4.md:1 #, markdown-text, no-wrap -msgid "Recursion, Maps And Folds" +msgid "Recursion, Maps, And Folds" msgstr "" #. type: Plain text @@ -13759,8 +13863,8 @@ msgstr "" #, markdown-text msgid "" "We will also cover some standard functions from PureScript's standard " -"libraries. We will see the `map` and `fold` functions, as well as some " -"useful special cases, like `filter` and `concatMap`." +"libraries. We will `map`, `fold`, and some useful special cases, like " +"`filter` and `concatMap`." msgstr "" #. type: Plain text @@ -13769,7 +13873,7 @@ msgstr "" msgid "" "The motivating example for this chapter is a library of functions for " "working with a virtual filesystem. We will apply the techniques learned in " -"this chapter to write functions which compute properties of the files " +"this chapter to write functions that compute properties of the files " "represented by a model of a filesystem." msgstr "" @@ -13866,14 +13970,14 @@ msgstr "" #, markdown-text msgid "" "Here, we can see how the factorial function is computed by reducing the " -"problem to a subproblem - that of computing the factorial of a smaller " -"integer. When we reach zero, the answer is immediate." +"problem to a subproblem – computing the factorial of a smaller integer. When " +"we reach zero, the answer is immediate." msgstr "" #. type: Plain text #: text/chapter4.md:40 #, markdown-text -msgid "Here is another common example, which computes the _Fibonacci function_:" +msgid "Here is another common example that computes the _Fibonacci function_:" msgstr "" #. type: Fenced code block (haskell) @@ -13894,12 +13998,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:48 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"Note that, while the above examples of `factorial` and `fib` work as " +"> Note that, while the above examples of `factorial` and `fib` work as " "intended, a more idiomatic implementation would use pattern matching instead " -"of `if`/`then`/`else`. Pattern matching techniques are discussed in a later " -"chapter." +"of `if`/`then`/`else`. Pattern-matching techniques are discussed in a later " +"chapter.\n" msgstr "" #. type: Title ## @@ -13945,7 +14049,7 @@ msgstr "" msgid "" "In this function, we use an `if .. then .. else` expression to branch based " "on the emptiness of the array. The `null` function returns `true` on an " -"empty array. Empty arrays have length zero, and a non-empty array has a " +"empty array. Empty arrays have a length of zero, and a non-empty array has a " "length that is one more than the length of its tail." msgstr "" @@ -13954,26 +14058,26 @@ msgstr "" #, markdown-text msgid "" "The `tail` function returns a `Maybe` wrapping the given array without its " -"first element. If the array is empty (i.e. it doesn't have a tail) `Nothing` " -"is returned. The `fromMaybe` function takes a default value and a `Maybe` " -"value. If the latter is `Nothing` it returns the default, in the other case " -"it returns the value wrapped by `Just`." +"first element. If the array is empty (i.e., it doesn't have a tail), " +"`Nothing` is returned. The `fromMaybe` function takes a default value and a " +"`Maybe` value. If the latter is `Nothing` it returns the default; in the " +"other case, it returns the value wrapped by `Just`." msgstr "" #. type: Plain text #: text/chapter4.md:69 #, markdown-text msgid "" -"This example is obviously a very impractical way to find the length of an " -"array in JavaScript, but should provide enough help to allow you to complete " -"the following exercises:" +"This example is a very impractical way to find the length of an array in " +"JavaScript, but it should provide enough help to allow you to complete the " +"following exercises:" msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:74 #, markdown-text msgid "" -"(Easy) Write a recursive function `isEven` which returns `true` if and only " +"(Easy) Write a recursive function `isEven` that returns `true` if and only " "if its input is an even integer." msgstr "" @@ -13981,7 +14085,7 @@ msgstr "" #: text/chapter4.md:74 #, markdown-text msgid "" -"(Medium) Write a recursive function `countEven` which counts the number of " +"(Medium) Write a recursive function `countEven` that counts the number of " "even integers in an array. _Hint_: the function `head` (also available in " "`Data.Array`) can be used to find the first element in a non-empty array." msgstr "" @@ -13998,15 +14102,15 @@ msgstr "" msgid "" "The `map` function is an example of a recursive function on arrays. It is " "used to transform the elements of an array by applying a function to each " -"element in turn. Therefore, it changes the _contents_ of the array, but " -"preserves its _shape_ (i.e. its length)." +"element in turn. Therefore, it changes the _contents_ of the array but " +"preserves its _shape_ (i.e., its length)." msgstr "" #. type: Plain text #: text/chapter4.md:80 #, markdown-text msgid "" -"When we cover _type classes_ later in the book we will see that the `map` " +"When we cover _type classes_ later in the book, we will see that the `map` " "function is an example of a more general pattern of shape-preserving " "functions which transform a class of type constructors called _functors_." msgstr "" @@ -14032,7 +14136,7 @@ msgstr "" #: text/chapter4.md:92 #, markdown-text msgid "" -"Notice how `map` is used - we provide a function which should be \"mapped " +"Notice how `map` is used – we provide a function that should be \"mapped " "over\" the array in the first argument, and the array itself in its second." msgstr "" @@ -14072,8 +14176,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" "There is an operator which is equivalent to the `map` function when used " -"with arrays, called `<$>`. This operator can be used infix like any other " -"binary operator:\n" +"with arrays, called `<$>`.\n" msgstr "" #. type: Fenced code block (text) @@ -14095,7 +14198,8 @@ msgstr "" #, no-wrap msgid "" "> :type map\n" -"forall a b f. Functor f => (a -> b) -> f a -> f b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Functor f => (a -> b) -> " +"f a -> f b\n" msgstr "" #. type: Plain text @@ -14110,7 +14214,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:120 #, no-wrap -msgid "forall a b. (a -> b) -> Array a -> Array b\n" +msgid "forall (a :: Type) (b :: Type). (a -> b) -> Array a -> Array b\n" msgstr "" #. type: Plain text @@ -14141,7 +14245,7 @@ msgid "" "fact just an alias for a regular PureScript function. The function is simply " "_applied_ using infix syntax. In fact, the function can be used like a " "regular function by enclosing its name in parentheses. This means that we " -"can used the parenthesized name `(<$>)` in place of `map` on arrays:\n" +"can use the parenthesized name `(<$>)` in place of `map` on arrays:\n" msgstr "" #. type: Fenced code block (text) @@ -14330,7 +14434,7 @@ msgid "" "> import Data.Array\n" "\n" "> :type concat\n" -"forall a. Array (Array a) -> Array a\n" +"forall (a :: Type). Array (Array a) -> Array a\n" "\n" "> concat [[1, 2, 3], [4, 5], [6]]\n" "[1, 2, 3, 4, 5, 6]\n" @@ -14340,10 +14444,10 @@ msgstr "" #: text/chapter4.md:205 #, markdown-text msgid "" -"There is a related function called `concatMap` which is like a combination " -"of the `concat` and `map` functions. Where `map` takes a function from " -"values to values (possibly of a different type), `concatMap` takes a " -"function from values to arrays of values." +"There is a related function called `concatMap` which is a combination of the " +"`concat` and `map` functions. Where `map` takes a function from values to " +"values (possibly of a different type), `concatMap` takes a function from " +"values to arrays of values." msgstr "" #. type: Plain text @@ -14359,7 +14463,7 @@ msgid "" "> import Data.Array\n" "\n" "> :type concatMap\n" -"forall a b. (a -> Array b) -> Array a -> Array b\n" +"forall (a :: Type) (b :: Type). (a -> Array b) -> Array a -> Array b\n" "\n" "> concatMap (\\n -> [n, n * n]) (1 .. 5)\n" "[1,1,2,4,3,9,4,16,5,25]\n" @@ -14413,8 +14517,8 @@ msgstr "" #: text/chapter4.md:229 #, markdown-text msgid "" -"We can perform this computation using an array comprehension. We will do so " -"in steps, using PSCi as our interactive development environment." +"We can perform this computation using array comprehension. We will do so in " +"steps, using PSCi as our interactive development environment." msgstr "" #. type: Plain text @@ -14551,13 +14655,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:292 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"_Note_: Just like `map` and `concatMap` allowed us to write _array " +"> _Note_: Just like `map` and `concatMap` allowed us to write _array " "comprehensions_, the more general operators `map` and `bind` allow us to " "write so-called _monad comprehensions_. We'll see plenty more examples of " "_monads_ later in the book, but in this chapter, we will only consider " -"arrays." +"arrays.\n" msgstr "" #. type: Plain text @@ -14576,15 +14680,15 @@ msgstr "" #: text/chapter4.md:300 #, markdown-text msgid "" -"The keyword `do` introduces a block of code which uses do notation. The " -"block consists of expressions of a few types:" +"The keyword `do` introduces a block of code that uses do notation. The block " +"consists of expressions of a few types:" msgstr "" #. type: Bullet: '- ' #: text/chapter4.md:304 #, markdown-text msgid "" -"Expressions which bind elements of an array to a name. These are indicated " +"Expressions that bind elements of an array to a name. These are indicated " "with the backwards-facing arrow `<-`, with a name on the left, and an " "expression on the right whose type is an array." msgstr "" @@ -14593,7 +14697,7 @@ msgstr "" #: text/chapter4.md:304 #, markdown-text msgid "" -"Expressions which do not bind elements of the array to names. The `do` " +"Expressions that do not bind elements of the array to names. The `do` " "_result_ is an example of this kind of expression and is illustrated in the " "last line, `pure [i, j]`." msgstr "" @@ -14601,7 +14705,7 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter4.md:304 #, markdown-text -msgid "Expressions which give names to expressions, using the `let` keyword." +msgid "Expressions that give names to expressions, using the `let` keyword." msgstr "" #. type: Plain text @@ -14634,9 +14738,8 @@ msgstr "" #: text/chapter4.md:315 #, markdown-text msgid "" -"In the case of arrays, `pure` simply constructs a singleton array. In fact, " -"we could modify our `factors` function to use this form, instead of using " -"`pure`:" +"In the case of arrays, `pure` simply constructs a singleton array. We can " +"modify our `factors` function to use this form, instead of using `pure`:" msgstr "" #. type: Fenced code block (haskell) @@ -14691,7 +14794,7 @@ msgid "" "> import Control.Alternative\n" "\n" "> :type guard\n" -"forall m. Alternative m => Boolean -> m Unit\n" +"forall (m :: Type -> Type). Alternative m => Boolean -> m Unit\n" msgstr "" #. type: Plain text @@ -14731,8 +14834,8 @@ msgstr "" #: text/chapter4.md:360 #, markdown-text msgid "" -"That is, if `guard` is passed an expression which evaluates to `true`, then " -"it returns an array with a single element. If the expression evaluates to " +"If we pass an expression to `guard` that evaluates to `true`, then it " +"returns an array with a single element. If the expression evaluates to " "`false`, then its result is empty." msgstr "" @@ -14752,8 +14855,8 @@ msgstr "" #: text/chapter4.md:369 #, markdown-text msgid "" -"(Easy) Write a function `isPrime` which tests if its integer argument is " -"prime or not. _Hint_: Use the `factors` function." +"(Easy) Write a function `isPrime`, which tests whether its integer argument " +"is prime. _Hint_: Use the `factors` function." msgstr "" #. type: Bullet: ' 1. ' @@ -14761,18 +14864,18 @@ msgstr "" #, markdown-text msgid "" "(Medium) Write a function `cartesianProduct` which uses do notation to find " -"the _cartesian product_ of two arrays, i.e. the set of all pairs of elements " -"`a`, `b`, where `a` is an element of the first array, and `b` is an element " -"of the second." +"the _cartesian product_ of two arrays, i.e., the set of all pairs of " +"elements `a`, `b`, where `a` is an element of the first array, and `b` is an " +"element of the second." msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 #, markdown-text msgid "" -"(Medium) Write a function `triples :: Int -> Array (Array Int)` which takes " +"(Medium) Write a function `triples :: Int -> Array (Array Int)`, which takes " "a number `n` and returns all Pythagorean triples whose components (the `a`, " -"`b` and `c` values) are each less than or equal to `n`. A _Pythagorean " +"`b`, and `c` values) are each less than or equal to `n`. A _Pythagorean " "triple_ is an array of numbers `[a, b, c]` such that `a² + b² = c²`. _Hint_: " "Use the `guard` function in an array comprehension." msgstr "" @@ -14783,9 +14886,9 @@ msgstr "" msgid "" "(Difficult) Write a function `primeFactors` which produces the [prime " "factorization](https://www.mathsisfun.com/prime-factorization.html) of `n`, " -"i.e. the array of prime integers whose product is `n`. _Hint_: for an " -"integer greater than 1, break the problem down into two subproblems: finding " -"the first factor, and finding the remaining factors." +"i.e., the array of prime integers whose product is `n`. _Hint_: for an " +"integer greater than 1, break the problem into two subproblems: finding the " +"first factor and the remaining factors." msgstr "" #. type: Title ## @@ -14799,14 +14902,14 @@ msgstr "" #, markdown-text msgid "" "Left and right folds over arrays provide another class of interesting " -"functions which can be implemented using recursion." +"functions that can be implemented using recursion." msgstr "" #. type: Plain text #: text/chapter4.md:375 #, markdown-text msgid "" -"Start by importing the `Data.Foldable` module, and inspecting the types of " +"Start by importing the `Data.Foldable` module and inspecting the types of " "the `foldl` and `foldr` functions using PSCi:" msgstr "" @@ -14817,29 +14920,31 @@ msgid "" "> import Data.Foldable\n" "\n" "> :type foldl\n" -"forall a b f. Foldable f => (b -> a -> b) -> b -> f a -> b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (b -> a -> " +"b) -> b -> f a -> b\n" "\n" "> :type foldr\n" -"forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (a -> b -> " +"b) -> b -> f a -> b\n" msgstr "" #. type: Plain text #: text/chapter4.md:387 #, markdown-text msgid "" -"These types are actually more general than we are interested in right " -"now. For the purposes of this chapter, we can assume that PSCi had given the " -"following (more specific) answer:" +"These types are more general than we are interested in right now. For this " +"chapter, we can simplify and assume the following (more specific) type " +"signatures:" msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:388 #, no-wrap msgid "" -"> :type foldl\n" +"-- foldl\n" "forall a b. (b -> a -> b) -> b -> Array a -> b\n" "\n" -"> :type foldr\n" +"-- foldr\n" "forall a b. (a -> b -> b) -> b -> Array a -> b\n" msgstr "" @@ -14847,8 +14952,8 @@ msgstr "" #: text/chapter4.md:397 #, markdown-text msgid "" -"In both of these cases, the type `a` corresponds to the type of elements of " -"our array. The type `b` can be thought of as the type of an \"accumulator\", " +"In both cases, the type `a` corresponds to the type of elements of our " +"array. The type `b` can be thought of as the type of an \"accumulator\", " "which will accumulate a result as we traverse the array." msgstr "" @@ -14870,8 +14975,8 @@ msgid "" "`b` to be `Int`. We need to provide three arguments: a function `Int -> Int " "-> Int`, which will add the next element to the accumulator, an initial " "value for the accumulator of type `Int`, and an array of `Int`s to add. For " -"the first argument, we can just use the addition operator, and the initial " -"value of the accumulator will be zero:\n" +"the first argument, we can use the addition operator, and the initial value " +"of the accumulator will be zero:\n" msgstr "" #. type: Fenced code block (text) @@ -14902,9 +15007,9 @@ msgstr "" #: text/chapter4.md:415 #, markdown-text msgid "" -"Let's write an example where the choice of folding function does matter, in " -"order to illustrate the difference. Instead of the addition function, let's " -"use string concatenation to build a string:" +"Let's write an example where the choice of folding function matters to " +"illustrate the difference. Instead of the addition function, let's use " +"string concatenation to build a string:" msgstr "" #. type: Fenced code block (text) @@ -14935,7 +15040,7 @@ msgstr "" #. type: Plain text #: text/chapter4.md:431 #, markdown-text -msgid "whereas the right fold is equivalent to this:" +msgid "Whereas the right fold is equivalent to this:" msgstr "" #. type: Fenced code block (text) @@ -14954,15 +15059,15 @@ msgstr "" #: text/chapter4.md:439 #, markdown-text msgid "" -"Recursion is a powerful technique for specifying algorithms, but comes with " -"a problem: evaluating recursive functions in JavaScript can lead to stack " +"Recursion is a powerful technique for specifying algorithms but comes with a " +"problem: evaluating recursive functions in JavaScript can lead to stack " "overflow errors if our inputs are too large." msgstr "" #. type: Plain text #: text/chapter4.md:441 #, markdown-text -msgid "It is easy to verify this problem, with the following code in PSCi:" +msgid "It is easy to verify this problem with the following code in PSCi:" msgstr "" #. type: Fenced code block (text) @@ -14987,41 +15092,41 @@ msgstr "" #: text/chapter4.md:458 #, markdown-text msgid "" -"This is a problem. If we are going to adopt recursion as a standard " -"technique from functional programming, then we need a way to deal with " -"possibly unbounded recursion." +"This is a problem. If we adopt recursion as a standard technique from " +"functional programming, we need a way to deal with possibly unbounded " +"recursion." msgstr "" #. type: Plain text #: text/chapter4.md:460 #, markdown-text msgid "" -"PureScript provides a partial solution to this problem in the form of _tail " +"PureScript provides a partial solution to this problem through _tail " "recursion optimization_." msgstr "" #. type: Plain text #: text/chapter4.md:462 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"_Note_: more complete solutions to the problem can be implemented in " +"> _Note_: more complete solutions to the problem can be implemented in " "libraries using so-called _trampolining_, but that is beyond the scope of " "this chapter. The interested reader can consult the documentation for the " "[`free`](https://pursuit.purescript.org/packages/purescript-free) and " "[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec) " -"packages." +"packages.\n" msgstr "" #. type: Plain text #: text/chapter4.md:464 #, markdown-text msgid "" -"The key observation which enables tail recursion optimization is the " -"following: a recursive call in _tail position_ to a function can be replaced " -"with a _jump_, which does not allocate a stack frame. A call is in _tail " -"position_ when it is the last call made before a function returns. This is " -"the reason why we observed a stack overflow in the example - the recursive " -"call to `f` was _not_ in tail position." +"The key observation that enables tail recursion optimization: a recursive " +"call in _tail position_ to a function can be replaced with a _jump_, which " +"does not allocate a stack frame. A call is in _tail position_ when it is the " +"last call made before a function returns. This is why we observed a stack " +"overflow in the example – the recursive call to `f` was _not_ in tail " +"position." msgstr "" #. type: Plain text @@ -15051,8 +15156,8 @@ msgstr "" #: text/chapter4.md:474 #, markdown-text msgid "" -"Notice that the recursive call to `factorialTailRec` is the last thing that " -"happens in this function - it is in tail position." +"Notice that the recursive call to `factorialTailRec` is the last thing in " +"this function – it is in tail position." msgstr "" #. type: Title ## @@ -15065,18 +15170,17 @@ msgstr "" #: text/chapter4.md:478 #, markdown-text msgid "" -"One common way to turn a function which is not tail recursive into a tail " -"recursive function is to use an _accumulator parameter_. An accumulator " -"parameter is an additional parameter which is added to a function which " -"_accumulates_ a return value, as opposed to using the return value to " -"accumulate the result." +"One common way to turn a not tail recursive function into a tail recursive " +"is to use an _accumulator parameter_. An accumulator parameter is an " +"additional parameter added to a function that _accumulates_ a return value, " +"as opposed to using the return value to accumulate the result." msgstr "" #. type: Plain text #: text/chapter4.md:480 #, markdown-text msgid "" -"For example, consider again the `length` function presented in the beginning " +"For example, consider again the `length` function presented at the beginning " "of the chapter:" msgstr "" @@ -15112,9 +15216,9 @@ msgstr "" #, markdown-text msgid "" "In this case, we delegate to the helper function `length'`, which is tail " -"recursive - its only recursive call is in the last case, and is in tail " -"position. This means that the generated code will be a _while loop_, and " -"will not blow the stack for large inputs." +"recursive – its only recursive call is in the last case, in tail " +"position. This means that the generated code will be a _while loop_ and not " +"blow the stack for large inputs." msgstr "" #. type: Plain text @@ -15123,16 +15227,16 @@ msgstr "" msgid "" "To understand the implementation of `lengthTailRec`, note that the helper " "function `length'` essentially uses the accumulator parameter to maintain an " -"additional piece of state - the partial result. It starts out at 0, and " -"grows by adding 1 for every element in the input array." +"additional piece of state – the partial result. It starts at 0 and grows by " +"adding 1 for every element in the input array." msgstr "" #. type: Plain text #: text/chapter4.md:500 #, markdown-text msgid "" -"Note also that while we might think of the accumulator as \"state\", there " -"is no direct mutation going on." +"Note also that while we might think of the accumulator as a \"state\", there " +"is no direct mutation." msgstr "" #. type: Title ## @@ -15145,14 +15249,14 @@ msgstr "" #: text/chapter4.md:504 #, markdown-text msgid "" -"If we can write our recursive functions using tail recursion, then we can " -"benefit from tail recursion optimization, so it becomes tempting to try to " -"write all of our functions in this form. However, it is often easy to forget " -"that many functions can be written directly as a fold over an array or " -"similar data structure. Writing algorithms directly in terms of combinators " -"such as `map` and `fold` has the added advantage of code simplicity - these " -"combinators are well-understood, and as such, communicate the _intent_ of " -"the algorithm much better than explicit recursion." +"If we can write our recursive functions using tail recursion, we can benefit " +"from tail recursion optimization, so it becomes tempting to try to write all " +"of our functions in this form. However, it is often easy to forget that many " +"functions can be written directly as a fold over an array or similar data " +"structure. Writing algorithms directly in terms of combinators such as `map` " +"and `fold` has the added advantage of code simplicity – these combinators " +"are well-understood, and as such, communicate the _intent_ of the algorithm " +"much better than explicit recursion." msgstr "" #. type: Plain text @@ -15225,15 +15329,15 @@ msgstr "" #: text/chapter4.md:531 #, markdown-text msgid "" -"In this section, we're going to apply what we've learned, writing functions " -"which will work with a model of a filesystem. We will use maps, folds and " -"filters to work with a predefined API." +"In this section, we'll apply what we've learned, writing functions that will " +"work with a model of a filesystem. We will use maps, folds, and filters to " +"work with a predefined API." msgstr "" #. type: Plain text #: text/chapter4.md:533 #, markdown-text -msgid "The `Data.Path` module defines an API for a virtual filesystem, as follows:" +msgid "The `Data.Path` module defines an API for a virtual filesystem as follows:" msgstr "" #. type: Bullet: '- ' @@ -15263,9 +15367,7 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter4.md:540 #, markdown-text -msgid "" -"The `size` function returns the file size for a `Path` which represents a " -"file." +msgid "The `size` function returns the file size for a `Path` representing a file." msgstr "" #. type: Bullet: '- ' @@ -15323,7 +15425,7 @@ msgstr "" #: text/chapter4.md:573 #, markdown-text msgid "" -"The `Test.Examples` module defines functions which use the `Data.Path` " +"The `Test.Examples` module defines functions that use the `Data.Path` " "API. You do not need to modify the `Data.Path` module, or understand its " "implementation. We will work entirely in the `Test.Examples` module." msgstr "" @@ -15338,7 +15440,7 @@ msgstr "" #: text/chapter4.md:577 #, markdown-text msgid "" -"Let's write a function which performs a deep enumeration of all files inside " +"Let's write a function that performs a deep enumeration of all files inside " "a directory. This function will have the following type:" msgstr "" @@ -15356,7 +15458,7 @@ msgid "" "enumerate the immediate children of the directory. For each child, we can " "recursively apply `allFiles`, which will return an array of " "paths. `concatMap` will allow us to apply `allFiles` and flatten the results " -"at the same time." +"simultaneously." msgstr "" #. type: Plain text @@ -15375,11 +15477,11 @@ msgstr "" #. type: Plain text #: text/chapter4.md:591 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"_Note_: the cons operator `:` actually has poor performance on immutable " -"arrays, so it is not recommended in general. Performance can be improved by " -"using other data structures, such as linked lists and sequences." +"> _Note_: the cons operator `:` has poor performance on immutable arrays, so " +"it is not generally recommended. Performance can be improved by using other " +"data structures, such as linked lists and sequences.\n" msgstr "" #. type: Plain text @@ -15414,9 +15516,9 @@ msgstr "" msgid "" "Recall that a backwards arrow corresponds to choosing an element from an " "array. The first step is to choose an element from the immediate children of " -"the argument. Then we simply call the function recursively for that " -"file. Since we are using do notation, there is an implicit call to " -"`concatMap` which concatenates all of the recursive results." +"the argument. Then we call the function recursively for that file. Since we " +"use do notation, there is an implicit call to `concatMap`, which " +"concatenates all of the recursive results." msgstr "" #. type: Plain text @@ -15435,7 +15537,7 @@ msgstr "" #: text/chapter4.md:614 #, markdown-text msgid "" -"Try out the new version in PSCi - you should get the same result. I'll let " +"Try out the new version in PSCi – you should get the same result. I'll let " "you decide which version you find clearer." msgstr "" @@ -15483,21 +15585,19 @@ msgid "" " 3. (Difficult) Write a function `largestSmallest` which takes a `Path` and " "returns an array containing the single largest and single smallest files in " "the `Path`. _Note_: consider the cases where there are zero or one files in " -"the `Path` by returning an empty array or a one-element array " -"respectively.\n" +"the `Path` by returning an empty or one-element array, respectively.\n" msgstr "" #. type: Plain text #: text/chapter4.md:633 #, markdown-text msgid "" -"In this chapter, we covered the basics of recursion in PureScript, as a " -"means of expressing algorithms concisely. We also introduced user-defined " -"infix operators, standard functions on arrays such as maps, filters and " -"folds, and array comprehensions which combine these ideas. Finally, we " -"showed the importance of using tail recursion in order to avoid stack " -"overflow errors, and how to use accumulator parameters to convert functions " -"to tail recursive form." +"In this chapter, we covered the basics of recursion in PureScript to express " +"algorithms concisely. We also introduced user-defined infix operators, " +"standard functions on arrays such as maps, filters, and folds, and array " +"comprehensions that combine these ideas. Finally, we showed the importance " +"of using tail recursion to avoid stack overflow errors and how to use " +"accumulator parameters to convert functions to tail recursive form." msgstr "" #. type: Title # @@ -15510,7 +15610,7 @@ msgstr "" #: text/chapter5.md:6 #, markdown-text msgid "" -"This chapter will introduce two new concepts: algebraic data types, and " +"This chapter will introduce two new concepts: algebraic data types and " "pattern matching. We will also briefly cover an interesting feature of the " "PureScript type system: row polymorphism." msgstr "" @@ -15520,26 +15620,25 @@ msgstr "" #, markdown-text msgid "" "Pattern matching is a common technique in functional programming and allows " -"the developer to write compact functions which express potentially complex " -"ideas, by breaking their implementation down into multiple cases." +"the developer to write compact functions, which express potentially complex " +"ideas by breaking their implementation down into multiple cases." msgstr "" #. type: Plain text #: text/chapter5.md:10 #, markdown-text msgid "" -"Algebraic data types are a feature of the PureScript type system which " -"enable a similar level of expressiveness in the language of types - they are " -"closely related to pattern matching." +"Algebraic data types are a feature of the PureScript type system, which " +"enables a similar level of expressiveness in the language of types – they " +"are closely related to pattern matching." msgstr "" #. type: Plain text #: text/chapter5.md:12 #, markdown-text msgid "" -"The goal of the chapter will be to write a library to describe and " -"manipulate simple vector graphics using algebraic types and pattern " -"matching." +"The chapter's goal will be to write a library to describe and manipulate " +"simple vector graphics using algebraic types and pattern matching." msgstr "" #. type: Plain text @@ -15554,7 +15653,7 @@ msgstr "" #: text/chapter5.md:18 #, markdown-text msgid "" -"The `Data.Picture` module defines a data type `Shape` for simple shapes, and " +"The `Data.Picture` module defines a data type `Shape` for simple shapes and " "a type `Picture` for collections of shapes, along with functions for working " "with those types." msgstr "" @@ -15593,17 +15692,17 @@ msgstr "" msgid "" "This makes the types and functions in that module available for use, but " "only by using the _qualified name_, like `Number.max`. This can be useful to " -"avoid overlapping imports, or just to make it clearer which modules certain " -"things are imported from." +"avoid overlapping imports or clarify which modules certain things are " +"imported from." msgstr "" #. type: Plain text #: text/chapter5.md:34 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"_Note_: it is not necessary to use the same module name as the original " -"module for a qualified import. Shorter qualified names like `import " -"Data.Number as N` are possible, and quite common." +"> _Note_: Using the same module name as the original module for a qualified " +"import is unnecessary – shorter qualified names like `import Data.Number as " +"N` are possible and quite common.\n" msgstr "" #. type: Title ## @@ -15616,7 +15715,7 @@ msgstr "" #: text/chapter5.md:38 #, markdown-text msgid "" -"Let's begin by looking at an example. Here is a function which computes the " +"Let's begin by looking at an example. Here is a function that computes the " "greatest common divisor of two integers using pattern matching:" msgstr "" @@ -15631,10 +15730,10 @@ msgstr "" #, markdown-text msgid "" "This algorithm is called the Euclidean Algorithm. If you search for its " -"definition online, you will likely find a set of mathematical equations " -"which look a lot like the code above. This is one benefit of pattern " -"matching: it allows you to define code by cases, writing simple, declarative " -"code which looks like a specification of a mathematical function." +"definition online, you will likely find a set of mathematical equations that " +"look like the code above. One benefit of pattern matching is that it allows " +"you to define code by cases, writing simple, declarative code that looks " +"like a mathematical function specification." msgstr "" #. type: Plain text @@ -15644,7 +15743,7 @@ msgid "" "A function written using pattern matching works by pairing sets of " "conditions with their results. Each line is called an _alternative_ or a " "_case_. The expressions on the left of the equals sign are called " -"_patterns_, and each case consists of one or more patterns, separated by " +"_patterns_, and each case consists of one or more patterns separated by " "spaces. Cases describe which conditions the arguments must satisfy before " "the expression on the right of the equals sign should be evaluated and " "returned. Each case is tried in order, and the first case whose patterns " @@ -15685,10 +15784,10 @@ msgstr "" #: text/chapter5.md:54 #, markdown-text msgid "" -"Note that patterns can bind values to names - each line in the example binds " +"Note that patterns can bind values to names – each line in the example binds " "one or both of the names `n` and `m` to the input values. As we learn about " -"different kinds of patterns, we will see that different types of patterns " -"correspond to different ways to choose names from the input arguments." +"different patterns, we will see that different patterns correspond to " +"different ways to choose names from the input arguments." msgstr "" #. type: Title ## @@ -15726,21 +15825,21 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter5.md:66 #, markdown-text -msgid "`Number`, `String`, `Char` and `Boolean` literals" +msgid "`Number`, `String`, `Char`, and `Boolean` literals" msgstr "" #. type: Bullet: '- ' #: text/chapter5.md:66 #, markdown-text msgid "" -"Wildcard patterns, indicated with an underscore (`_`), which match any " -"argument, and which do not bind any names." +"Wildcard patterns, indicated with an underscore (`_`), match any argument " +"and do not bind any names." msgstr "" #. type: Plain text #: text/chapter5.md:68 #, markdown-text -msgid "Here are two more examples which demonstrate using these simple patterns:" +msgid "Here are two more examples that demonstrate using these simple patterns:" msgstr "" #. type: Fenced code block (haskell) @@ -15764,15 +15863,15 @@ msgstr "" msgid "" "In the Euclidean algorithm example, we used an `if .. then .. else` " "expression to switch between the two alternatives when `m > n` and `m <= " -"n`. Another option in this case would be to use a _guard_.\n" +"n`. Another option, in this case, would be to use a _guard_.\n" msgstr "" #. type: Plain text #: text/chapter5.md:82 #, markdown-text msgid "" -"A guard is a boolean-valued expression which must be satisfied in addition " -"to the constraints imposed by the patterns. Here is the Euclidean algorithm " +"A guard is a boolean-valued expression that must be satisfied in addition to " +"the constraints imposed by the patterns. Here is the Euclidean algorithm " "rewritten to use a guard:" msgstr "" @@ -15788,8 +15887,8 @@ msgstr "" msgid "" "In this case, the third line uses a guard to impose the extra condition that " "the first argument is strictly larger than the second. The guard in the " -"final line uses the expression `otherwise`, which might seem like a keyword, " -"but is in fact just a regular binding in `Prelude`:" +"final line uses the expression `otherwise`, which might seem like a keyword " +"but is, in fact, just a regular binding in `Prelude`:" msgstr "" #. type: Fenced code block (text) @@ -15807,7 +15906,7 @@ msgstr "" #: text/chapter5.md:98 #, markdown-text msgid "" -"As this example demonstrates, guards appear on the left of the equals " +"This example demonstrates that guards appear on the left of the equals " "symbol, separated from the list of patterns by a pipe character (`|`)." msgstr "" @@ -15869,8 +15968,8 @@ msgstr "" #: text/chapter5.md:114 #, markdown-text msgid "" -"Here is another function which matches arrays of length five, binding each " -"of its five elements in a different way:" +"Here is another function that matches arrays of length five, binding each of " +"its five elements differently:" msgstr "" #. type: Fenced code block (haskell) @@ -15884,9 +15983,9 @@ msgstr "" #, markdown-text msgid "" "The first pattern only matches arrays with five elements, whose first and " -"second elements are 0 and 1 respectively. In that case, the function returns " -"the product of the third and fourth elements. In every other case, the " -"function returns zero. For example, in PSCi:" +"second elements are 0 and 1, respectively. In that case, the function " +"returns the product of the third and fourth elements. In every other case, " +"the function returns zero. For example, in PSCi:" msgstr "" #. type: Fenced code block (text) @@ -15912,11 +16011,11 @@ msgstr "" #: text/chapter5.md:138 #, markdown-text msgid "" -"Array literal patterns allow us to match arrays of a fixed length, but " +"Array literal patterns allow us to match arrays of a fixed length. Still, " "PureScript does _not_ provide any means of matching arrays of an unspecified " -"length, since destructuring immutable arrays in these sorts of ways can lead " -"to poor performance. If you need a data structure which supports this sort " -"of matching, the recommended approach is to use `Data.List`. Other data " +"length since destructuring immutable arrays in these sorts of ways can lead " +"to poor performance. If you need a data structure that supports this sort of " +"matching, the recommended approach is to use `Data.List`. Other data " "structures exist which provide improved asymptotic performance for different " "operations." msgstr "" @@ -15930,7 +16029,7 @@ msgstr "" #. type: Plain text #: text/chapter5.md:142 #, markdown-text -msgid "_Record patterns_ are used to match - you guessed it - records." +msgid "_Record patterns_ are used to match – you guessed it – records." msgstr "" #. type: Plain text @@ -15945,8 +16044,8 @@ msgstr "" #: text/chapter5.md:146 #, markdown-text msgid "" -"For example: this pattern matches any record which contains fields called " -"`first` and `last`, and binds their values to the names `x` and `y` " +"For example, this pattern matches any record which contains fields called " +"`first` and `last`, and binds their values to the names `x` and `y`, " "respectively:" msgstr "" @@ -15973,7 +16072,7 @@ msgid "" "> showPerson { first: x, last: y } = y <> \", \" <> x\n" "\n" "> :type showPerson\n" -"forall r. { first :: String, last :: String | r } -> String\n" +"forall (r :: Row Type). { first :: String, last :: String | r } -> String\n" msgstr "" #. type: Plain text @@ -16000,11 +16099,10 @@ msgstr "" #: text/chapter5.md:171 #, markdown-text msgid "" -"We are able to append additional fields to the record, and the `showPerson` " -"function will still work. As long as the record contains the `first` and " -"`last` fields of type `String`, the function application is " -"well-typed. However, it is _not_ valid to call `showPerson` with too _few_ " -"fields:" +"We can append additional fields to the record, and the `showPerson` function " +"will still work. As long as the record contains the `first` and `last` " +"fields of type `String`, the function application is well-typed. However, it " +"is _not_ valid to call `showPerson` with too _few_ fields:" msgstr "" #. type: Fenced code block (text) @@ -16044,7 +16142,7 @@ msgstr "" #. type: Plain text #: text/chapter5.md:187 #, markdown-text -msgid "and PSCi would have inferred the same type." +msgid "And PSCi would have inferred the same type." msgstr "" #. type: Title ## @@ -16059,8 +16157,8 @@ msgstr "" msgid "" "Recall that the `showPerson` function matches a record inside its argument, " "binding the `first` and `last` fields to values named `x` and `y`. We could " -"alternatively just reuse the field names themselves, and simplify this sort " -"of pattern match as follows:" +"alternatively reuse the field names themselves and simplify this sort of " +"pattern match as follows:" msgstr "" #. type: Fenced code block (haskell) @@ -16095,7 +16193,7 @@ msgstr "" #. type: Plain text #: text/chapter5.md:205 #, markdown-text -msgid "This may improve readability of code in some circumstances." +msgid "This may improve the readability of code in some circumstances." msgstr "" #. type: Title ## @@ -16110,9 +16208,9 @@ msgstr "" msgid "" "Array patterns and record patterns both combine smaller patterns to build " "larger patterns. For the most part, the examples above have only used simple " -"patterns inside array patterns and record patterns, but it is important to " -"note that patterns can be arbitrarily _nested_, which allows functions to be " -"defined using conditions on potentially complex data types." +"patterns inside array patterns and record patterns. Still, it is important " +"to note that patterns can be arbitrarily _nested_, which allows functions to " +"be defined using conditions on potentially complex data types." msgstr "" #. type: Plain text @@ -16161,8 +16259,7 @@ msgstr "" msgid "" "This way, we save ourselves from allocating a new array if the pair is " "already sorted. Note that if the input array does not contain _exactly_ two " -"elements, then this function simply returns it unchanged, even if it's " -"unsorted." +"elements, then this function returns it unchanged, even if it's unsorted." msgstr "" #. type: Bullet: '1. ' @@ -16177,8 +16274,8 @@ msgstr "" #: text/chapter5.md:233 #, markdown-text msgid "" -"(Medium) What is the most general type of the `sameCity` function, taking " -"into account row polymorphism? What about the `livesInLA` function defined " +"(Medium) What is the most general type of the `sameCity` function, " +"considering row polymorphism? What about the `livesInLA` function defined " "above? _Note_: There is no test for this exercise." msgstr "" @@ -16186,9 +16283,9 @@ msgstr "" #: text/chapter5.md:233 #, markdown-text msgid "" -"(Medium) Write a function `fromSingleton` which uses an array literal " -"pattern to extract the sole member of a singleton array. If the array is not " -"a singleton, your function should return a provided default value. Your " +"(Medium) Write a function `fromSingleton` that uses an array literal pattern " +"to extract the sole member of a singleton array. If the array is not a " +"singleton, your function should return a provided default value. Your " "function should have type `forall a. a -> Array a -> a`" msgstr "" @@ -16203,7 +16300,7 @@ msgstr "" #, markdown-text msgid "" "Patterns do not only appear in top-level function declarations. It is " -"possible to use patterns to match on an intermediate value in a computation, " +"possible to use patterns to match on an intermediate value in a computation " "using a `case` expression. Case expressions provide a similar type of " "utility to anonymous functions: it is not always desirable to give a name to " "a function, and a `case` expression allows us to avoid naming a function " @@ -16214,7 +16311,7 @@ msgstr "" #: text/chapter5.md:239 #, markdown-text msgid "" -"Here is an example. This function computes \"longest zero suffix\" of an " +"Here is an example. This function computes the \"longest zero suffix\" of an " "array (the longest suffix which sums to zero):" msgstr "" @@ -16244,8 +16341,9 @@ msgstr "" msgid "" "This function works by case analysis. If the array is empty, our only option " "is to return an empty array. If the array is non-empty, we first use a " -"`case` expression to split into two cases. If the sum of the array is zero, " -"we return the whole array. If not, we recurse on the tail of the array." +"`case` expression to split it into two cases. If the sum of the array is " +"zero, we return the whole array. If not, we recurse on the tail of the " +"array." msgstr "" #. type: Title ## @@ -16258,10 +16356,9 @@ msgstr "" #: text/chapter5.md:261 #, markdown-text msgid "" -"If patterns in a case expression are tried in order, then what happens in " -"the case when none of the patterns in a case alternatives match their " -"inputs? In this case, the case expression will fail at runtime with a " -"_pattern match failure_." +"If patterns in a case expression are tried in order, what happens when none " +"of the patterns in a case alternatives match their inputs? In this case, the " +"case expression will fail at runtime with a _pattern match failure_." msgstr "" #. type: Plain text @@ -16286,7 +16383,7 @@ msgstr "" #, markdown-text msgid "" "This function contains only a single case, which only matches a single " -"input, `true`. If we compile this file, and test in PSCi with any other " +"input, `true`. If we compile this file and test in PSCi with any other " "argument, we will see an error at runtime:" msgstr "" @@ -16303,8 +16400,8 @@ msgstr "" #: text/chapter5.md:279 #, markdown-text msgid "" -"Functions which return a value for any combination of inputs are called " -"_total_ functions, and functions which do not are called _partial_." +"Functions that return a value for any combination of inputs are called " +"_total_ functions, and functions that do not are called _partial_." msgstr "" #. type: Plain text @@ -16326,7 +16423,7 @@ msgid "" "The PureScript compiler will generate an error if it can detect that your " "function is not total due to an incomplete pattern match. The " "`unsafePartial` function can be used to silence these errors (if you are " -"sure that your partial function is safe!) If we removed the call to the " +"sure your partial function is safe!) If we removed the call to the " "`unsafePartial` function above, then the compiler would generate the " "following error:" msgstr "" @@ -16380,9 +16477,9 @@ msgstr "" #: text/chapter5.md:308 #, markdown-text, no-wrap msgid "" -"We will see more types which involve the `=>` symbol later on in the book " +"We will see more types that involve the `=>` symbol later on in the book " "(they are related to _type classes_), but for now, it suffices to observe " -"that PureScript keeps track of partial functions using the type system, and " +"that PureScript keeps track of partial functions using the type system and " "that we must explicitly tell the type checker when they are safe.\n" msgstr "" @@ -16392,7 +16489,7 @@ msgstr "" msgid "" "The compiler will also generate a warning in certain cases when it can " "detect that cases are _redundant_ (that is, a case only matches values which " -"would have been matched by a prior case):" +"a prior case would have matched):" msgstr "" #. type: Fenced code block (haskell) @@ -16422,10 +16519,11 @@ msgstr "" #. type: Plain text #: text/chapter5.md:327 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"_Note_: PSCi does not show warnings, so to reproduce this example, you will " -"need to save this function as a file and compile it using `spago build`." +"> _Note_: PSCi does not show warnings, so to reproduce this example, you " +"will need to save this function as a file and compile it using `spago " +"build`.\n" msgstr "" #. type: Title ## @@ -16468,17 +16566,17 @@ msgstr "" msgid "" "However, this approach has one major drawback: to work with `Shape`s " "abstractly, it is necessary to identify all of the operations one might wish " -"to perform, and to define them on the `Shape` interface. It becomes " -"difficult to add new operations without breaking modularity." +"to perform and to define them on the `Shape` interface. It becomes difficult " +"to add new operations without breaking modularity." msgstr "" #. type: Plain text #: text/chapter5.md:339 #, markdown-text msgid "" -"Algebraic data types provide a type-safe way to solve this sort of problem, " -"if the set of shapes is known in advance. It is possible to define new " -"operations on `Shape` in a modular way, and still maintain type-safety." +"Algebraic data types provide a type-safe way to solve this problem if the " +"set of shapes is known in advance. It is possible to define new operations " +"on `Shape` in a modular way and still maintain type-safety." msgstr "" #. type: Plain text @@ -16501,8 +16599,8 @@ msgstr "" #, markdown-text msgid "" "This declaration defines `Shape` as a sum of different constructors, and for " -"each constructor identifies the data that is included. A `Shape` is either a " -"`Circle` which contains a center `Point` and a radius (a number), or a " +"each constructor identifies the included data. A `Shape` is either a " +"`Circle` that contains a center `Point` and a radius (a number), or a " "`Rectangle`, or a `Line`, or `Text`. There are no other ways to construct a " "value of type `Shape`." msgstr "" @@ -16513,7 +16611,7 @@ msgstr "" msgid "" "An algebraic data type is introduced using the `data` keyword, followed by " "the name of the new type and any type arguments. The type's constructors " -"(i.e. its _data constructors_) are defined after the equals symbol, and are " +"(i.e., its _data constructors_) are defined after the equals symbol and " "separated by pipe characters (`|`). The data carried by an ADT's " "constructors doesn't have to be restricted to primitive types: constructors " "can include records, arrays, or even other ADTs." @@ -16549,7 +16647,7 @@ msgstr "" #, markdown-text msgid "" "Note that we don't use the syntax `forall a.` anywhere in our data " -"definition. `forall` syntax is necessary for functions, but is not used when " +"definition. `forall` syntax is necessary for functions but is not used when " "defining ADTs with `data` or type aliases with `type`." msgstr "" @@ -16653,14 +16751,14 @@ msgstr "" #, markdown-text msgid "" "(Easy) Write a function `circleAtOrigin` which constructs a `Circle` (of " -"type `Shape`) centered at the origin with radius `10.0`." +"type `Shape`) centered at the origin with a radius `10.0`." msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:397 #, markdown-text msgid "" -"(Medium) Write a function `doubleScaleAndCenter` which scales the size of a " +"(Medium) Write a function `doubleScaleAndCenter` that scales the size of a " "`Shape` by a factor of `2.0` and centers it at the origin." msgstr "" @@ -16801,7 +16899,7 @@ msgstr "" #: text/chapter5.md:456 #, markdown-text msgid "" -"Also note that the constructor of a newtype often has the same name as the " +"Also, note that the constructor of a newtype often has the same name as the " "newtype itself, but this is not a requirement. For example, unique names are " "also valid:" msgstr "" @@ -16816,13 +16914,13 @@ msgstr "" #: text/chapter5.md:462 #, markdown-text msgid "" -"In this case, `Coulomb` is the _type constructor_ (of zero arguments) and " +"In this case, `Coulomb` is the _type constructor_ (of zero arguments), and " "`MakeCoulomb` is the _data constructor_. These constructors live in " "different namespaces, even when the names are identical, such as with the " "`Volt` example. This is true for all ADTs. Note that although the type " -"constructor and data constructor can have different names, in practice it is " -"idiomatic for them to share the same name. This is the case with `Amp` and " -"`Volt` types above." +"constructor and data constructor can have different names, in practice, it " +"is idiomatic for them to share the same name. This is the case with `Amp` " +"and `Volt` types above." msgstr "" #. type: Plain text @@ -16874,7 +16972,7 @@ msgstr "" #. type: Plain text #: text/chapter5.md:480 #, markdown-text -msgid "Define a type synonym for a `Picture` - just an array of `Shape`s:" +msgid "Define a type synonym for a `Picture` – just an array of `Shape`s:" msgstr "" #. type: Fenced code block (haskell) @@ -17015,7 +17113,7 @@ msgstr "" msgid "" "This chapter also introduced algebraic data types, which are closely related " "to pattern matching. We saw how algebraic data types allow concise " -"descriptions of data structures, and provide a modular way to extend data " +"descriptions of data structures and provide a modular way to extend data " "types with new operations." msgstr "" @@ -17023,7 +17121,7 @@ msgstr "" #: text/chapter5.md:536 #, markdown-text msgid "" -"Finally, we covered _row polymorphism_, a powerful type of abstraction which " +"Finally, we covered _row polymorphism_, a powerful type of abstraction that " "allows many idiomatic JavaScript functions to be given a type." msgstr "" @@ -17047,8 +17145,8 @@ msgstr "" #: text/chapter6.md:6 #, markdown-text msgid "" -"This chapter will introduce a powerful form of abstraction which is enabled " -"by PureScript's type system - type classes." +"This chapter will introduce a powerful form of abstraction enabled by " +"PureScript's type system – type classes." msgstr "" #. type: Plain text @@ -17056,7 +17154,7 @@ msgstr "" #, markdown-text msgid "" "This motivating example for this chapter will be a library for hashing data " -"structures. We will see how the machinery of type classes allow us to hash " +"structures. We will see how the machinery of type classes allows us to hash " "complex data structures without having to think directly about the structure " "of the data itself." msgstr "" @@ -17115,7 +17213,7 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter6.md:24 #, markdown-text -msgid "`strings`, which defines functions which operate on strings." +msgid "`strings`, which defines functions that operate on strings." msgstr "" #. type: Bullet: '- ' @@ -17202,7 +17300,7 @@ msgstr "" #: text/chapter6.md:51 #, markdown-text msgid "" -"This code declares a type class instance called `showBoolean` - in " +"This code declares a type class instance called `showBoolean` – in " "PureScript, type class instances can be named to aid the readability of the " "generated JavaScript. We say that the `Boolean` type _belongs to the `Show` " "type class_." @@ -17261,9 +17359,9 @@ msgstr "" msgid "" "The output of `show` should be a string that you can paste back into the " "repl (or `.purs` file) to recreate the item being shown. Here we'll use " -"`logShow`, which just calls `show` then `log`, to render the string without " -"quotes. Ignore the `unit` print - that will covered in Chapter 8 when we " -"examine `Effect`s, like `log`." +"`logShow`, which just calls `show` and then `log`, to render the string " +"without quotes. Ignore the `unit` print – that will be covered in Chapter 8 " +"when we examine `Effect`s, like `log`." msgstr "" #. type: Fenced code block (text) @@ -17309,15 +17407,15 @@ msgstr "" #, markdown-text msgid "" "The problem here is not that there is no `Show` instance for the type we " -"intended to `show`, but rather that PSCi was unable to infer the type. This " -"is indicated by the _unknown type_ `a` in the inferred type." +"intended to `show`, but rather that PSCi could not infer the type. This is " +"indicated by the _unknown type_ `a` in the inferred type." msgstr "" #. type: Plain text #: text/chapter6.md:111 #, markdown-text msgid "" -"We can annotate the expression with a type, using the `::` operator, so that " +"We can annotate the expression with a type using the `::` operator, so that " "PSCi can choose the correct type class instance:" msgstr "" @@ -17413,7 +17511,7 @@ msgstr "" #, markdown-text msgid "" "The `Eq` type class defines the `eq` function, which tests two values for " -"equality. The `==` operator is actually just an alias for `eq`." +"equality. The `==` operator is actually an alias for `eq`." msgstr "" #. type: Fenced code block (haskell) @@ -17428,8 +17526,8 @@ msgstr "" #: text/chapter6.md:152 #, markdown-text msgid "" -"Note that in either case, the two arguments must have the same type: it does " -"not make sense to compare two values of different types for equality." +"In either case, the two arguments must have the same type: it does not make " +"sense to compare two values of different types for equality." msgstr "" #. type: Plain text @@ -17460,7 +17558,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" "The `Ord` type class defines the `compare` function, which can be used to " -"compare two values, for types which support ordering. The comparison " +"compare two values, for types that support ordering. The comparison " "operators `<` and `>` along with their non-strict companions `<=` and `>=`, " "can be defined in terms of `compare`.\n" msgstr "" @@ -17489,26 +17587,26 @@ msgstr "" #: text/chapter6.md:177 #, markdown-text msgid "" -"The `compare` function compares two values, and returns an `Ordering`, which " +"The `compare` function compares two values and returns an `Ordering`, which " "has three alternatives:" msgstr "" #. type: Bullet: '- ' #: text/chapter6.md:181 #, markdown-text -msgid "`LT` - if the first argument is less than the second." +msgid "`LT` – if the first argument is less than the second." msgstr "" #. type: Bullet: '- ' #: text/chapter6.md:181 #, markdown-text -msgid "`EQ` - if the first argument is equal to the second." +msgid "`EQ` – if the first argument is equal to the second." msgstr "" #. type: Bullet: '- ' #: text/chapter6.md:181 #, markdown-text -msgid "`GT` - if the first argument is greater than the second." +msgid "`GT` – if the first argument is greater than the second." msgstr "" #. type: Plain text @@ -17539,19 +17637,19 @@ msgstr "" #, markdown-text msgid "" "The `Field` type class identifies those types which support numeric " -"operators such as addition, subtraction, multiplication and division. It is " +"operators such as addition, subtraction, multiplication, and division. It is " "provided to abstract over those operators, so that they can be reused where " "appropriate." msgstr "" #. type: Plain text #: text/chapter6.md:197 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"_Note_: Just like the `Eq` and `Ord` type classes, the `Field` type class " +"> _Note_: Just like the `Eq` and `Ord` type classes, the `Field` type class " "has special support in the PureScript compiler, so that simple expressions " "such as `1 + 2 * 3` get translated into simple JavaScript, as opposed to " -"function calls which dispatch based on a type class implementation." +"function calls which dispatch based on a type class implementation.\n" msgstr "" #. type: Fenced code block (haskell) @@ -17565,7 +17663,7 @@ msgstr "" #, markdown-text msgid "" "The `Field` type class is composed from several more general " -"_superclasses_. This allows us to talk abstractly about types which support " +"_superclasses_. This allows us to talk abstractly about types that support " "some but not all of the `Field` operations. For example, a type of natural " "numbers would be closed under addition and multiplication, but not " "necessarily under subtraction, so that type might have an instance of the " @@ -17612,8 +17710,7 @@ msgstr "" #, markdown-text msgid "" "Strings form a semigroup under regular string concatenation, and so do " -"arrays. Several other standard instances are provided by the `prelude` " -"package." +"arrays. The `prelude` package provides several other standard instances." msgstr "" #. type: Plain text @@ -17651,9 +17748,9 @@ msgstr "" #, markdown-text msgid "" "A `Monoid` type class instance for a type describes how to _accumulate_ a " -"result with that type, by starting with an \"empty\" value, and combining " -"new results. For example, we can write a function which concatenates an " -"array of values in some monoid by using a fold. In PSCi:" +"result with that type by starting with an \"empty\" value and combining new " +"results. For example, we can write a function that concatenates an array of " +"values in some monoid using a fold. In PSCi:" msgstr "" #. type: Fenced code block (haskell) @@ -17727,8 +17824,8 @@ msgstr "" msgid "" "It is instructive to specialize to the case where `f` is the array type " "constructor. In this case, we can replace `f a` with `Array a` for any a, " -"and we notice that the types of `foldl` and `foldr` become the types that we " -"saw when we first encountered folds over arrays." +"and we notice that the types of `foldl` and `foldr` become the types we saw " +"when we first encountered folds over arrays." msgstr "" #. type: Plain text @@ -17738,9 +17835,9 @@ msgid "" "What about `foldMap`? Well, that becomes `forall a m. Monoid m => (a -> m) " "-> Array a -> m`. This type signature says that we can choose any type `m` " "for our result type, as long as that type is an instance of the `Monoid` " -"type class. If we can provide a function which turns our array elements into " +"type class. If we can provide a function that turns our array elements into " "values in that monoid, then we can accumulate over our array using the " -"structure of the monoid, and return a single value.\n" +"structure of the monoid and return a single value.\n" msgstr "" #. type: Plain text @@ -17764,7 +17861,7 @@ msgstr "" #, markdown-text msgid "" "Here, we choose the monoid for strings, which concatenates strings together, " -"and the `show` function which renders an `Int` as a `String`. Then, passing " +"and the `show` function, which renders an `Int` as a `String`. Then, passing " "in an array of integers, we see that the results of `show`ing each integer " "have been concatenated into a single `String`." msgstr "" @@ -17773,7 +17870,7 @@ msgstr "" #: text/chapter6.md:275 #, markdown-text msgid "" -"But arrays are not the only types which are foldable. `foldable-traversable` " +"But arrays are not the only types that are foldable. `foldable-traversable` " "also defines `Foldable` instances for types like `Maybe` and `Tuple`, and " "other libraries like `lists` define `Foldable` instances for their own data " "types. `Foldable` captures the notion of an _ordered container_." @@ -17782,16 +17879,16 @@ msgstr "" #. type: Title ### #: text/chapter6.md:276 #, markdown-text, no-wrap -msgid "Functor, and Type Class Laws" +msgid "Functor and Type Class Laws" msgstr "" #. type: Plain text #: text/chapter6.md:279 #, markdown-text msgid "" -"The Prelude also defines a collection of type classes which enable a " +"The Prelude also defines a collection of type classes that enable a " "functional style of programming with side-effects in PureScript: `Functor`, " -"`Applicative` and `Monad`. We will cover these abstractions later in the " +"`Applicative`, and `Monad`. We will cover these abstractions later in the " "book, but for now, let's look at the definition of the `Functor` type class, " "which we have seen already in the form of the `map` function:" msgstr "" @@ -17883,8 +17980,8 @@ msgstr "" #, markdown-text msgid "" "The second law is the _composition law_. It states that mapping one function " -"over a structure, and then mapping a second, is the same thing as mapping " -"the composition of the two functions over the structure." +"over a structure and then mapping a second is the same as mapping the " +"composition of the two functions over the structure." msgstr "" #. type: Plain text @@ -18011,7 +18108,7 @@ msgstr "" #, markdown-text msgid "" "Types of functions can be constrained by using type classes. Here is an " -"example: suppose we want to write a function which tests if three values are " +"example: suppose we want to write a function that tests if three values are " "equal, by using equality defined using an `Eq` type class instance." msgstr "" @@ -18110,17 +18207,16 @@ msgid "" "> import Prelude\n" "\n" "> :type \\x -> x + x\n" -"forall a. Semiring a => a -> a\n" +"forall (a :: Type). Semiring a => a -> a\n" msgstr "" #. type: Plain text #: text/chapter6.md:388 #, markdown-text, no-wrap msgid "" -"Here, we might have annotated this function as `Int -> Int`, or `Number -> " +"Here, we might have annotated this function as `Int -> Int` or `Number -> " "Number`, but PSCi shows us that the most general type works for any " -"`Semiring`, allowing us to use our function with both `Int`s and " -"`Number`s.\n" +"`Semiring`, allowing us to use our function with both `Int`s and `Number.\n" msgstr "" #. type: Title ## @@ -18158,16 +18254,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:402 +#: text/chapter6.md:401 #, markdown-text, no-wrap msgid "" "If a type class instance depends on multiple other instances, those " -"instances should be grouped in parentheses and separated by\n" -"commas on the left hand side of the `=>` symbol:\n" +"instances should be grouped in parentheses and separated by commas on the " +"left-hand side of the `=>` symbol:\n" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:403 +#: text/chapter6.md:402 #, no-wrap msgid "" "instance (Show a, Show b) => Show (Either a b) where\n" @@ -18175,13 +18271,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:409 +#: text/chapter6.md:408 #, markdown-text msgid "These two type class instances are provided in the `prelude` library." msgstr "" #. type: Plain text -#: text/chapter6.md:411 +#: text/chapter6.md:410 #, markdown-text msgid "" "When the program is compiled, the correct type class instance for `Show` is " @@ -18191,7 +18287,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:415 +#: text/chapter6.md:414 #, markdown-text msgid "" "(Easy) The following declaration defines a type of non-empty arrays of " @@ -18199,7 +18295,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:419 +#: text/chapter6.md:418 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18209,16 +18305,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:421 +#: text/chapter6.md:420 #, markdown-text, no-wrap msgid "" -" Write an `Eq` instance for the type `NonEmpty a` which reuses the " +" Write an `Eq` instance for the type `NonEmpty a` that reuses the " "instances for `Eq a` and `Eq (Array a)`. _Note:_ you may instead derive the " "`Eq` instance.\n" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:423 +#: text/chapter6.md:422 #, markdown-text msgid "" "(Medium) Write a `Semigroup` instance for `NonEmpty a` by reusing the " @@ -18226,21 +18322,21 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:425 +#: text/chapter6.md:424 #, markdown-text msgid "(Medium) Write a `Functor` instance for `NonEmpty`." msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:427 +#: text/chapter6.md:426 #, markdown-text msgid "" "(Medium) Given any type `a` with an instance of `Ord`, we can add a new " -"\"infinite\" value which is greater than any other value:" +"\"infinite\" value that is greater than any other value:" msgstr "" #. type: Plain text -#: text/chapter6.md:431 +#: text/chapter6.md:430 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18250,15 +18346,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:433 +#: text/chapter6.md:432 #, markdown-text, no-wrap msgid "" -" Write an `Ord` instance for `Extended a` which reuses the `Ord` instance " +" Write an `Ord` instance for `Extended a` that reuses the `Ord` instance " "for `a`.\n" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:435 +#: text/chapter6.md:434 #, markdown-text msgid "" "(Difficult) Write a `Foldable` instance for `NonEmpty`. _Hint_: reuse the " @@ -18266,16 +18362,16 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:437 +#: text/chapter6.md:436 #, markdown-text msgid "" "(Difficult) Given a type constructor `f` which defines an ordered container " -"(and so has a `Foldable` instance), we can create a new container type which " +"(and so has a `Foldable` instance), we can create a new container type that " "includes an extra element at the front:" msgstr "" #. type: Plain text -#: text/chapter6.md:441 +#: text/chapter6.md:440 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18285,7 +18381,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:443 +#: text/chapter6.md:442 #, markdown-text, no-wrap msgid "" " The container `OneMore f` also has an ordering, where the new element " @@ -18294,7 +18390,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:448 +#: text/chapter6.md:447 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18305,15 +18401,15 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:450 +#: text/chapter6.md:449 #, markdown-text msgid "" -"(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function which " +"(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function that " "removes duplicate `Shape`s from an array using the `nubEq` function." msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:452 +#: text/chapter6.md:451 #, markdown-text msgid "" "(Medium) Write a `dedupShapesFast` function which is the same as " @@ -18321,28 +18417,28 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter6.md:453 +#: text/chapter6.md:452 #, markdown-text, no-wrap -msgid "Multi Parameter Type Classes" +msgid "Multi-Parameter Type Classes" msgstr "" #. type: Plain text -#: text/chapter6.md:456 +#: text/chapter6.md:455 #, markdown-text msgid "" "It's not the case that a type class can only take a single type as an " -"argument. This is the most common case, but in fact, a type class can be " +"argument. This is the most common case, but a type class can be " "parameterized by _zero or more_ type arguments." msgstr "" #. type: Plain text -#: text/chapter6.md:458 +#: text/chapter6.md:457 #, markdown-text msgid "Let's see an example of a type class with two type arguments." msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:459 +#: text/chapter6.md:458 #, no-wrap msgid "" "module Stream where\n" @@ -18362,16 +18458,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:477 +#: text/chapter6.md:476 #, markdown-text msgid "" -"The `Stream` module defines a class `Stream` which identifies types which " +"The `Stream` module defines a class `Stream` which identifies types that " "look like streams of elements, where elements can be pulled from the front " "of the stream using the `uncons` function." msgstr "" #. type: Plain text -#: text/chapter6.md:479 +#: text/chapter6.md:478 #, markdown-text msgid "" "Note that the `Stream` type class is parameterized not only by the type of " @@ -18380,7 +18476,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:481 +#: text/chapter6.md:480 #, markdown-text msgid "" "The module defines two type class instances: an instance for arrays, where " @@ -18389,16 +18485,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:483 +#: text/chapter6.md:482 #, markdown-text msgid "" -"We can write functions which work over arbitrary streams. For example, here " -"is a function which accumulates a result in some `Monoid` based on the " +"We can write functions that work over arbitrary streams. For example, here " +"is a function that accumulates a result in some `Monoid` based on the " "elements of a stream:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:484 +#: text/chapter6.md:483 #, no-wrap msgid "" "import Prelude\n" @@ -18412,7 +18508,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:496 +#: text/chapter6.md:495 #, markdown-text msgid "" "Try using `foldStream` in PSCi for different types of `Stream` and different " @@ -18420,35 +18516,35 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter6.md:497 +#: text/chapter6.md:496 #, markdown-text, no-wrap msgid "Functional Dependencies" msgstr "" #. type: Plain text -#: text/chapter6.md:500 +#: text/chapter6.md:499 #, markdown-text msgid "" -"Multi-parameter type classes can be very useful, but can easily lead to " +"Multi-parameter type classes can be very useful but can easily lead to " "confusing types and even issues with type inference. As a simple example, " "consider writing a generic `tail` function on streams using the `Stream` " "class given above:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:501 +#: text/chapter6.md:500 #, no-wrap msgid "genericTail xs = map _.tail (uncons xs)\n" msgstr "" #. type: Plain text -#: text/chapter6.md:506 +#: text/chapter6.md:505 #, markdown-text msgid "This gives a somewhat confusing error message:" msgstr "" #. type: Fenced code block (text) -#: text/chapter6.md:507 +#: text/chapter6.md:506 #, no-wrap msgid "" "The inferred type\n" @@ -18460,7 +18556,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:516 +#: text/chapter6.md:515 #, markdown-text msgid "" "The problem is that the `genericTail` function does not use the `element` " @@ -18469,7 +18565,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:518 +#: text/chapter6.md:517 #, markdown-text msgid "" "Worse still, we cannot even use `genericTail` by applying it to a specific " @@ -18477,7 +18573,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter6.md:519 +#: text/chapter6.md:518 #, no-wrap msgid "" "> map _.tail (uncons \"testing\")\n" @@ -18491,7 +18587,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:530 +#: text/chapter6.md:529 #, markdown-text msgid "" "Here, we might expect the compiler to choose the `streamString` " @@ -18500,16 +18596,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:532 +#: text/chapter6.md:531 #, markdown-text msgid "" -"The compiler is unable to make that deduction automatically, and cannot " -"commit to the `streamString` instance. However, we can help the compiler by " -"adding a hint to the type class definition:" +"The compiler cannot make that deduction automatically or commit to the " +"`streamString` instance. However, we can help the compiler by adding a hint " +"to the type class definition:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:533 +#: text/chapter6.md:532 #, no-wrap msgid "" "class Stream stream element | stream -> element where\n" @@ -18517,7 +18613,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:539 +#: text/chapter6.md:538 #, markdown-text, no-wrap msgid "" "Here, `stream -> element` is called a _functional dependency_. A functional " @@ -18529,7 +18625,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:541 +#: text/chapter6.md:540 #, markdown-text msgid "" "This hint is enough for the compiler to infer the correct type for our " @@ -18537,52 +18633,53 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter6.md:542 +#: text/chapter6.md:541 #, no-wrap msgid "" "> :type genericTail\n" -"forall stream element. Stream stream element => stream -> Maybe stream\n" +"forall (stream :: Type) (element :: Type). Stream stream element => stream " +"-> Maybe stream\n" "\n" "> genericTail \"testing\"\n" "(Just \"esting\")\n" msgstr "" #. type: Plain text -#: text/chapter6.md:551 +#: text/chapter6.md:550 #, markdown-text msgid "" -"Functional dependencies can be quite useful when using multi-parameter type " -"classes to design certain APIs." +"Functional dependencies can be useful when designing certain APIs using " +"multi-parameter type classes." msgstr "" #. type: Title ## -#: text/chapter6.md:552 +#: text/chapter6.md:551 #, markdown-text, no-wrap msgid "Nullary Type Classes" msgstr "" #. type: Plain text -#: text/chapter6.md:555 +#: text/chapter6.md:554 #, markdown-text msgid "" -"We can even define type classes with zero type arguments! These correspond " -"to compile-time assertions about our functions, allowing us to track global " -"properties of our code in the type system." +"We can even define type classes with zero-type arguments! These correspond " +"to compile-time assertions about our functions, allowing us to track the " +"global properties of our code in the type system." msgstr "" #. type: Plain text -#: text/chapter6.md:557 +#: text/chapter6.md:556 #, markdown-text msgid "" -"An important example is the `Partial` class which we saw earlier when " -"discussing partial functions. Take for example the functions `head` and " -"`tail` defined in `Data.Array.Partial` that allow us to get the head or tail " -"of an array without wrapping them in a `Maybe`, so they can fail if the " -"array is empty:" +"An important example is the `Partial` class we saw earlier when discussing " +"partial functions. Take, for example, the functions `head` and `tail` " +"defined in `Data.Array.Partial` that allow us to get the head or tail of an " +"array without wrapping them in a `Maybe`, so they can fail if the array is " +"empty:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:558 +#: text/chapter6.md:557 #, no-wrap msgid "" "head :: forall a. Partial => Array a -> a\n" @@ -18591,7 +18688,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:565 +#: text/chapter6.md:564 #, markdown-text msgid "" "Note that there is no instance defined for the `Partial` type class! Doing " @@ -18600,7 +18697,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter6.md:566 +#: text/chapter6.md:565 #, no-wrap msgid "" "> head [1, 2, 3]\n" @@ -18611,7 +18708,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:575 +#: text/chapter6.md:574 #, markdown-text msgid "" "Instead, we can republish the `Partial` constraint for any functions making " @@ -18619,7 +18716,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:576 +#: text/chapter6.md:575 #, no-wrap msgid "" "secondElement :: forall a. Partial => Array a -> a\n" @@ -18627,7 +18724,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:582 +#: text/chapter6.md:581 #, markdown-text msgid "" "We've already seen the `unsafePartial` function, which allows us to treat a " @@ -18636,13 +18733,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:583 +#: text/chapter6.md:582 #, no-wrap msgid "unsafePartial :: forall a. (Partial => a) -> a\n" msgstr "" #. type: Plain text -#: text/chapter6.md:588 +#: text/chapter6.md:587 #, markdown-text msgid "" "Note that the `Partial` constraint appears _inside the parentheses_ on the " @@ -18651,7 +18748,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter6.md:589 +#: text/chapter6.md:588 #, no-wrap msgid "" "> unsafePartial head [1, 2, 3]\n" @@ -18662,13 +18759,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter6.md:597 +#: text/chapter6.md:596 #, markdown-text, no-wrap msgid "Superclasses" msgstr "" #. type: Plain text -#: text/chapter6.md:600 +#: text/chapter6.md:599 #, markdown-text msgid "" "Just as we can express relationships between type class instances by making " @@ -18677,7 +18774,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:602 +#: text/chapter6.md:601 #, markdown-text, no-wrap msgid "" "We say that one type class is a superclass of another if every instance of " @@ -18687,60 +18784,60 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:604 +#: text/chapter6.md:603 #, markdown-text msgid "" "We've [already seen an example of superclass relationships](#ord): the `Eq` " "class is a superclass of `Ord`, and the `Semigroup` class is a superclass of " "`Monoid`. For every type class instance of the `Ord` class, there must be a " -"corresponding `Eq` instance for the same type. This makes sense, since in " +"corresponding `Eq` instance for the same type. This makes sense since, in " "many cases, when the `compare` function reports that two values are " "incomparable, we often want to use the `Eq` class to determine if they are " -"in fact equal." +"equal." msgstr "" #. type: Plain text -#: text/chapter6.md:606 +#: text/chapter6.md:605 #, markdown-text msgid "" "In general, it makes sense to define a superclass relationship when the laws " -"for the subclass mention the members of the superclass. For example, it is " -"reasonable to assume, for any pair of `Ord` and `Eq` instances, that if two " -"values are equal under the `Eq` instance, then the `compare` function should " -"return `EQ`. In other words, `a == b` should be true exactly when `compare a " -"b` evaluates to `EQ`. This relationship on the level of laws justifies the " +"for the subclass mention the superclass members. For example, for any pair " +"of Ord and Eq instances, it is reasonable to assume that if two values are " +"equal under the `Eq` instance, then the `compare` function should return " +"`EQ`. In other words, `a == b` should be true exactly when `compare a b` " +"evaluates to `EQ`. This relationship on the level of laws justifies the " "superclass relationship between `Eq` and `Ord`." msgstr "" #. type: Plain text -#: text/chapter6.md:608 +#: text/chapter6.md:607 #, markdown-text msgid "" -"Another reason to define a superclass relationship is in the case where " -"there is a clear \"is-a\" relationship between the two classes. That is, " -"every member of the subclass _is a_ member of the superclass as well." +"Another reason to define a superclass relationship is when there is a clear " +"\"is-a\" relationship between the two classes. That is, every member of the " +"subclass _is a_ member of the superclass as well." msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:612 +#: text/chapter6.md:611 #, markdown-text msgid "" "(Medium) Define a partial function `unsafeMaximum :: Partial => Array Int -> " -"Int` which finds the maximum of a non-empty array of integers. Test out your " +"Int` that finds the maximum of a non-empty array of integers. Test out your " "function in PSCi using `unsafePartial`. _Hint_: Use the `maximum` function " "from `Data.Foldable`." msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:614 +#: text/chapter6.md:613 #, markdown-text msgid "" -"(Medium) The `Action` class is a multi-parameter type class which defines an " +"(Medium) The `Action` class is a multi-parameter type class that defines an " "action of one type on another:" msgstr "" #. type: Plain text -#: text/chapter6.md:618 +#: text/chapter6.md:617 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18750,28 +18847,28 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:620 +#: text/chapter6.md:619 #, markdown-text, no-wrap msgid "" -" An _action_ is a function which describes how monoidal values are used " -"to determine how to modify a value of another type. There are two laws for " -"the `Action` type class:\n" +" An _action_ is a function that describes how monoidal values are used to " +"determine how to modify a value of another type. There are two laws for the " +"`Action` type class:\n" msgstr "" #. type: Bullet: ' - ' -#: text/chapter6.md:623 +#: text/chapter6.md:622 #, markdown-text msgid "`act mempty a = a`" msgstr "" #. type: Bullet: ' - ' -#: text/chapter6.md:623 +#: text/chapter6.md:622 #, markdown-text msgid "`act (m1 <> m2) a = act m1 (act m2 a)`" msgstr "" #. type: Plain text -#: text/chapter6.md:625 +#: text/chapter6.md:624 #, markdown-text, no-wrap msgid "" " Applying an empty action is a no-op. And applying two actions in " @@ -18780,13 +18877,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:627 +#: text/chapter6.md:626 #, markdown-text, no-wrap msgid " For example, the natural numbers form a monoid under multiplication:\n" msgstr "" #. type: Plain text -#: text/chapter6.md:630 +#: text/chapter6.md:629 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18795,7 +18892,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:632 +#: text/chapter6.md:631 #, markdown-text, no-wrap msgid "" " {{#include " @@ -18803,7 +18900,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:635 +#: text/chapter6.md:634 #, markdown-text, no-wrap msgid "" " {{#include " @@ -18812,13 +18909,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:637 +#: text/chapter6.md:636 #, markdown-text, no-wrap -msgid " Write an instance which implements this action:\n" +msgid " Write an instance that implements this action:\n" msgstr "" #. type: Plain text -#: text/chapter6.md:642 +#: text/chapter6.md:641 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18829,31 +18926,31 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:644 +#: text/chapter6.md:643 #, markdown-text, no-wrap msgid " Remember, your instance must satisfy the laws listed above.\n" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:646 +#: text/chapter6.md:645 #, markdown-text msgid "" -"(Difficult) There are actually multiple ways to implement an instance of " -"`Action Multiply Int`. How many can you think of? Purescript does not allow " -"multiple implementations of a same instance, so you will have to replace " -"your original implementation. _Note_: the tests cover 4 implementations." +"(Difficult) There are multiple ways to implement an instance of `Action " +"Multiply Int`. How many can you think of? Purescript does not allow multiple " +"implementations of the same instance, so you will have to replace your " +"original implementation. _Note_: the tests cover 4 implementations." msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:648 +#: text/chapter6.md:647 #, markdown-text msgid "" -"(Medium) Write an `Action` instance which repeats an input string some " -"number of times:" +"(Medium) Write an `Action` instance that repeats an input string some number " +"of times:" msgstr "" #. type: Plain text -#: text/chapter6.md:653 +#: text/chapter6.md:652 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18864,7 +18961,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:655 +#: text/chapter6.md:654 #, markdown-text, no-wrap msgid "" " _Hint_: Search Pursuit for a helper-function with the signature [`String " @@ -18874,13 +18971,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:657 +#: text/chapter6.md:656 #, markdown-text, no-wrap msgid " Does this instance satisfy the laws listed above?\n" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:659 +#: text/chapter6.md:658 #, markdown-text msgid "" "(Medium) Write an instance `Action m a => Action m (Array a)`, where the " @@ -18888,7 +18985,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:661 +#: text/chapter6.md:660 #, markdown-text msgid "" "(Difficult) Given the following newtype, write an instance for `Action m " @@ -18896,7 +18993,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:665 +#: text/chapter6.md:664 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18905,7 +19002,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:667 +#: text/chapter6.md:666 #, markdown-text, no-wrap msgid "" " _Note_: The testing framework requires `Show` and `Eq` instances for the " @@ -18916,7 +19013,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter6.md:669 +#: text/chapter6.md:668 #, markdown-text msgid "" "(Difficult) Should the arguments of the multi-parameter type class `Action` " @@ -18925,13 +19022,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter6.md:670 +#: text/chapter6.md:669 #, markdown-text, no-wrap msgid "A Type Class for Hashes" msgstr "" #. type: Plain text -#: text/chapter6.md:673 +#: text/chapter6.md:672 #, markdown-text msgid "" "In the last section of this chapter, we will use the lessons from the rest " @@ -18939,29 +19036,29 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:675 -#, markdown-text +#: text/chapter6.md:674 +#, markdown-text, no-wrap msgid "" -"Note that this library is for demonstration purposes only, and is not " -"intended to provide a robust hashing mechanism." +"> Note that this library is for demonstration purposes only and is not " +"intended to provide a robust hashing mechanism.\n" msgstr "" #. type: Plain text -#: text/chapter6.md:677 +#: text/chapter6.md:676 #, markdown-text msgid "What properties might we expect of a hash function?" msgstr "" #. type: Bullet: '- ' -#: text/chapter6.md:680 +#: text/chapter6.md:679 #, markdown-text msgid "" -"A hash function should be deterministic, and map equal values to equal hash " +"A hash function should be deterministic and map equal values to equal hash " "codes." msgstr "" #. type: Bullet: '- ' -#: text/chapter6.md:680 +#: text/chapter6.md:679 #, markdown-text msgid "" "A hash function should distribute its results approximately uniformly over " @@ -18969,29 +19066,29 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:682 +#: text/chapter6.md:681 #, markdown-text msgid "" "The first property looks a lot like a law for a type class, whereas the " -"second property is more along the lines of an informal contract, and " +"second property is more along the lines of an informal contract and " "certainly would not be enforceable by PureScript's type system. However, " "this should provide the intuition for the following type class:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:683 +#: text/chapter6.md:682 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:Hashable}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:688 +#: text/chapter6.md:687 #, markdown-text msgid "with the associated law that `a == b` implies `hash a == hash b`." msgstr "" #. type: Plain text -#: text/chapter6.md:690 +#: text/chapter6.md:689 #, markdown-text msgid "" "We'll spend the rest of this section building a library of instances and " @@ -18999,19 +19096,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:692 +#: text/chapter6.md:691 #, markdown-text msgid "We will need a way to combine hash codes in a deterministic way:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:693 +#: text/chapter6.md:692 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:combineHashes}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:698 +#: text/chapter6.md:697 #, markdown-text msgid "" "The `combineHashes` function will mix two hash codes and redistribute the " @@ -19019,48 +19116,48 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:700 +#: text/chapter6.md:699 #, markdown-text msgid "" -"Let's write a function which uses the `Hashable` constraint to restrict the " +"Let's write a function that uses the `Hashable` constraint to restrict the " "types of its inputs. One common task which requires a hashing function is to " "determine if two values hash to the same hash code. The `hashEqual` relation " "provides such a capability:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:701 +#: text/chapter6.md:700 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashEqual}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:706 +#: text/chapter6.md:705 #, markdown-text msgid "" "This function uses the `on` function from `Data.Function` to define " "hash-equality in terms of equality of hash codes, and should read like a " "declarative definition of hash-equality: two values are \"hash-equal\" if " -"they are equal after each value has been passed through the `hash` function." +"they are equal after each value passed through the `hash` function." msgstr "" #. type: Plain text -#: text/chapter6.md:708 +#: text/chapter6.md:707 #, markdown-text msgid "" "Let's write some `Hashable` instances for some primitive types. Let's start " "with an instance for integers. Since a `HashCode` is really just a wrapped " -"integer, this is simple - we can use the `hashCode` helper function:" +"integer, this is simple – we can use the `hashCode` helper function:" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:709 +#: text/chapter6.md:708 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashInt}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:714 +#: text/chapter6.md:713 #, markdown-text msgid "" "We can also define a simple instance for `Boolean` values using pattern " @@ -19068,13 +19165,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:715 +#: text/chapter6.md:714 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashBoolean}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:720 +#: text/chapter6.md:719 #, markdown-text msgid "" "With an instance for hashing integers, we can create an instance for hashing " @@ -19082,13 +19179,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:721 +#: text/chapter6.md:720 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashChar}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:726 +#: text/chapter6.md:725 #, markdown-text msgid "" "To define an instance for arrays, we can `map` the `hash` function over the " @@ -19098,13 +19195,13 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:727 +#: text/chapter6.md:726 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashArray}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:732 +#: text/chapter6.md:731 #, markdown-text msgid "" "Notice how we build up instances using the simpler instances we have already " @@ -19113,29 +19210,29 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter6.md:733 +#: text/chapter6.md:732 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashString}}\n" msgstr "" #. type: Plain text -#: text/chapter6.md:738 +#: text/chapter6.md:737 #, markdown-text msgid "" "How can we prove that these `Hashable` instances satisfy the type class law " "that we stated above? We need to make sure that equal values have equal hash " -"codes. In cases like `Int`, `Char`, `String` and `Boolean`, this is simple " -"because there are no values of those types which are equal in the sense of " +"codes. In cases like `Int`, `Char`, `String`, and `Boolean`, this is simple " +"because there are no values of those types that are equal in the sense of " "`Eq` but not equal identically." msgstr "" #. type: Plain text -#: text/chapter6.md:740 +#: text/chapter6.md:739 #, markdown-text msgid "" "What about some more interesting types? To prove the type class law for the " "`Array` instance, we can use induction on the length of the array. The only " -"array with length zero is `[]`. Any two non-empty arrays are equal only if " +"array with a length zero is `[]`. Any two non-empty arrays are equal only if " "they have equal head elements and equal tails, by the definition of `Eq` on " "arrays. By the inductive hypothesis, the tails have equal hashes, and we " "know that the head elements have equal hashes if the `Hashable a` instance " @@ -19144,7 +19241,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:742 +#: text/chapter6.md:741 #, markdown-text msgid "" "The source code for this chapter includes several other examples of " @@ -19152,7 +19249,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 +#: text/chapter6.md:747 #, markdown-text msgid "" "(Easy) Use PSCi to test the hash functions for each of the defined " @@ -19160,18 +19257,18 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 +#: text/chapter6.md:747 #, markdown-text msgid "" -"(Medium) Write a function `arrayHasDuplicates` which tests if an array has " -"any duplicate elements based on both hash and value equality. First check " +"(Medium) Write a function `arrayHasDuplicates`, which tests if an array has " +"any duplicate elements based on both hash and value equality. First, check " "for hash equality with the `hashEqual` function, then check for value " "equality with `==` if a duplicate pair of hashes is found. _Hint_: the " "`nubByEq` function in `Data.Array` should make this task much simpler." msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 +#: text/chapter6.md:747 #, markdown-text msgid "" "(Medium) Write a `Hashable` instance for the following newtype which " @@ -19179,7 +19276,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:751 +#: text/chapter6.md:750 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -19187,7 +19284,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:754 +#: text/chapter6.md:753 #, markdown-text, no-wrap msgid "" " {{#include " @@ -19196,7 +19293,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:757 +#: text/chapter6.md:756 #, markdown-text, no-wrap msgid "" " The newtype `Hour` and its `Eq` instance represent the type of integers " @@ -19207,26 +19304,25 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:761 +#: text/chapter6.md:760 #, markdown-text msgid "" "In this chapter, we've been introduced to _type classes_, a type-oriented " -"form of abstraction which enables powerful forms of code reuse. We've seen a " -"collection of standard type classes from the PureScript standard libraries, " +"form of abstraction that enables powerful forms of code reuse. We've seen a " +"collection of standard type classes from the PureScript standard libraries " "and defined our own library based on a type class for computing hash codes." msgstr "" #. type: Plain text -#: text/chapter6.md:762 +#: text/chapter6.md:761 #, markdown-text msgid "" -"This chapter also gave an introduction to the notion of type class laws, a " -"technique for proving properties about code which uses type classes for " -"abstraction. Type class laws are part of a larger subject called _equational " -"reasoning_, in which the properties of a programming language and its type " -"system are used to enable logical reasoning about its programs. This is an " -"important idea, and will be a theme which we will return to throughout the " -"rest of the book." +"This chapter also introduced type class laws, a technique for proving " +"properties about code that uses type classes for abstraction. Type class " +"laws are part of a larger subject called _equational reasoning_, in which " +"the properties of a programming language and its type system are used to " +"enable logical reasoning about its programs. This is an important idea and a " +"theme that we will return to throughout the rest of the book." msgstr "" #. type: Title ## @@ -19239,10 +19335,10 @@ msgstr "" #: text/chapter7.md:6 #, markdown-text msgid "" -"In this chapter, we will meet an important new abstraction - the " +"In this chapter, we will meet an important new abstraction – the " "_applicative functor_, described by the `Applicative` type class. Don't " -"worry if the name sounds confusing - we will motivate the concept with a " -"practical example - validating form data. This technique allows us to " +"worry if the name sounds confusing – we will motivate the concept with a " +"practical example – validating form data. This technique allows us to " "convert code which usually involves a lot of boilerplate checking into a " "simple, declarative description of our form." msgstr "" @@ -19261,9 +19357,9 @@ msgstr "" #, markdown-text msgid "" "The example code for this chapter will be a continuation of the address book " -"example from chapter 3. This time, we will extend our address book data " -"types, and write functions to validate values for those types. The " -"understanding is that these functions could be used, for example in a web " +"example from Chapter 3. This time, we will extend our address book data " +"types and write functions to validate values for those types. The " +"understanding is that these functions could be used, for example, in a web " "user interface, to display errors to the user as part of a data entry form." msgstr "" @@ -19304,7 +19400,7 @@ msgstr "" #, markdown-text msgid "" "The `Data.AddressBook` module defines data types and `Show` instances for " -"the types in our project, and the `Data.AddressBook.Validation` module " +"the types in our project and the `Data.AddressBook.Validation` module " "contains validation rules for those types." msgstr "" @@ -19326,7 +19422,7 @@ msgstr "" #: text/chapter7.md:27 #, markdown-text msgid "" -"The source code for this module defines a function `address` which has the " +"The source code for this module defines a function `address` that has the " "following type:" msgstr "" @@ -19397,7 +19493,7 @@ msgstr "" #: text/chapter7.md:61 #, markdown-text msgid "" -"Of course, this is an expected type error - `address` takes strings as " +"Of course, this is an expected type error – `address` takes strings as " "arguments, not values of type `Maybe String`." msgstr "" @@ -19473,8 +19569,8 @@ msgstr "" #, no-wrap msgid "" "> :type lift3\n" -"forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f " -"d\n" +"forall (a :: Type) (b :: Type) (c :: Type) (d :: Type) (f :: Type -> " +"Type). Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d\n" msgstr "" #. type: Plain text @@ -19497,7 +19593,7 @@ msgstr "" #: text/chapter7.md:99 #, markdown-text msgid "" -"This type says that we can take any function with three arguments, and lift " +"This type says that we can take any function with three arguments and lift " "it to give a new function whose argument and result types are wrapped with " "`Maybe`." msgstr "" @@ -19583,13 +19679,13 @@ msgstr "" #, markdown-text msgid "" "Now we'll see how `map` and `apply` can be used together to lift functions " -"of arbitrary number of arguments." +"of an arbitrary number of arguments." msgstr "" #. type: Plain text #: text/chapter7.md:131 #, markdown-text -msgid "For functions of one argument, we can just use `map` directly." +msgid "For functions of one argument, we can use `map` directly." msgstr "" #. type: Plain text @@ -19641,10 +19737,10 @@ msgstr "" #. type: Plain text #: text/chapter7.md:150 -#, markdown-text +#, markdown-text, no-wrap msgid "" -"It is left as an exercise for the reader to verify the types involved in " -"this expression." +"> It is left as an exercise for the reader to verify the types involved in " +"this expression.\n" msgstr "" #. type: Plain text @@ -19678,7 +19774,7 @@ msgstr "" #: text/chapter7.md:164 #, markdown-text msgid "" -"Alternatively _applicative do notation_ can be used for the same purpose in " +"Alternatively, _applicative do notation_ can be used for the same purpose in " "a way that looks similar to the familiar _do notation_. Here is `lift3` " "using _applicative do notation_. Note `ado` is used instead of `do`, and " "`in` is used on the final line to denote the yielded value:" @@ -19749,7 +19845,7 @@ msgstr "" #: text/chapter7.md:199 #, markdown-text msgid "" -"If we think of applicative functors as functors which allow lifting of " +"If we think of applicative functors as functors that allow lifting of " "functions, then `pure` can be thought of as lifting functions of zero " "arguments." msgstr "" @@ -19777,7 +19873,7 @@ msgid "" "As an example, the functor `Maybe` represents the side effect of " "possibly-missing values. Some other examples include `Either err`, which " "represents the side effect of possible errors of type `err`, and the arrow " -"functor `r ->` which represents the side-effect of reading from a global " +"functor `r ->`, which represents the side-effect of reading from a global " "configuration. For now, we'll only consider the `Maybe` functor.\n" msgstr "" @@ -19795,8 +19891,8 @@ msgstr "" #: text/chapter7.md:209 #, markdown-text msgid "" -"`pure` lifts pure (side-effect free) values into the larger language, and " -"for functions, we can use `map` and `apply` as described above." +"`pure` lifts pure (side-effect free) values into the larger language; for " +"functions, we can use `map` and `apply` as described above." msgstr "" #. type: Plain text @@ -19859,12 +19955,12 @@ msgstr "" #: text/chapter7.md:230 #, markdown-text msgid "" -"Now suppose that this function forms the implementation of a (very simple!) " -"web service with the three arguments provided as query parameters. We want " -"to make sure that the user provided each of the three parameters, so we " -"might use the `Maybe` type to indicate the presence or otherwise absence of " -"a parameter. We can lift `fullName` over `Maybe` to create an implementation " -"of the web service which checks for missing parameters:" +"Suppose that this function forms the implementation of a (very simple!) web " +"service with the three arguments provided as query parameters. We want to " +"ensure that the user provided each of the three parameters, so we might use " +"the Maybe type to indicate the presence or absence of a parameter. We can " +"lift `fullName` over `Maybe` to create an implementation of the web service " +"which checks for missing parameters:" msgstr "" #. type: Fenced code block (text) @@ -19882,9 +19978,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:242 text/chapter7.md:292 text/chapter7.md:444 -#: text/chapter7.md:479 text/chapter7.md:525 text/chapter7.md:557 +#: text/chapter7.md:479 text/chapter7.md:525 #, markdown-text -msgid "or with _applicative do_" +msgid "Or with _applicative do_:" msgstr "" #. type: Fenced code block (text) @@ -19923,7 +20019,7 @@ msgstr "" #: text/chapter7.md:267 #, markdown-text msgid "" -"This is good, because now we can send an error response back from our web " +"This is good because now we can send an error response back from our web " "service if the parameters are invalid. However, it would be better if we " "could indicate which field was incorrect in the response." msgstr "" @@ -19997,8 +20093,8 @@ msgstr "" #: text/chapter7.md:307 #, markdown-text msgid "" -"Now our function takes three optional arguments using `Maybe`, and returns " -"either a `String` error message or a `String` result." +"Now our function takes three optional arguments using `Maybe, and returns " +"either a`String` error message or a `String` result." msgstr "" #. type: Plain text @@ -20026,8 +20122,8 @@ msgstr "" #, markdown-text msgid "" "In this case, we see the error message corresponding to the first missing " -"field, or a successful result if every field was provided. However, if we " -"are missing multiple inputs, we still only see the first error:" +"field or a successful result if every field was provided. However, if we are " +"missing multiple inputs, we still only see the first error:" msgstr "" #. type: Fenced code block (text) @@ -20058,8 +20154,8 @@ msgstr "" #, markdown-text msgid "" "As an example of working with applicative functors abstractly, this section " -"will show how to write a function which will generically combine " -"side-effects encoded by an applicative functor `f`." +"will show how to write a function that generically combines side-effects " +"encoded by an applicative functor `f`." msgstr "" #. type: Plain text @@ -20080,7 +20176,7 @@ msgstr "" #: text/chapter7.md:337 #, markdown-text, no-wrap msgid "" -"For any fixed list size `n`, there is a function of `n` arguments which " +"For any fixed list size `n`, there is a function of `n` arguments that " "builds a list of size `n` out of those arguments. For example, if `n` is " "`3`, the function is `\\x y z -> x : y : z : Nil`. This function has type `a " "-> a -> a -> List a`. We can use the `Applicative` instance for `List` to " @@ -20183,9 +20279,9 @@ msgstr "" #, markdown-text msgid "" "When specialized to `Maybe`, our function returns a `Just` only if every " -"list element was `Just`, otherwise it returns `Nothing`. This is consistent " +"list element is `Just`; otherwise, it returns `Nothing`. This is consistent " "with our intuition of working in a larger language supporting optional " -"values - a list of computations which return optional results only has a " +"values – a list of computations that produce optional results only has a " "result itself if every computation contained a result." msgstr "" @@ -20194,7 +20290,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" "But the `combineList` function works for any `Applicative`! We can use it to " -"combine computations which possibly signal an error using `Either err`, or " +"combine computations that possibly signal an error using `Either err`, or " "which read from a global configuration using `r ->`.\n" msgstr "" @@ -20202,7 +20298,7 @@ msgstr "" #: text/chapter7.md:380 #, markdown-text msgid "" -"We will see the `combineList` function again later, when we consider " +"We will see the `combineList` function again later when we consider " "`Traversable` functors." msgstr "" @@ -20210,10 +20306,10 @@ msgstr "" #: text/chapter7.md:386 #, markdown-text msgid "" -"(Medium) Write versions of the numeric operators `+`, `-`, `*` and `/` which " -"work with optional arguments (i.e. arguments wrapped in `Maybe`) and return " -"a value wrapped in `Maybe`. Name these functions `addMaybe`, `subMaybe`, " -"`mulMaybe`, and `divMaybe`. _Hint_: Use `lift2`." +"(Medium) Write versions of the numeric operators `+`, `-`, `*`, and `/` " +"which work with optional arguments (i.e., arguments wrapped in `Maybe`) and " +"return a value wrapped in `Maybe`. Name these functions `addMaybe`, " +"`subMaybe`, `mulMaybe`, and `divMaybe`. _Hint_: Use `lift2`." msgstr "" #. type: Bullet: ' 1. ' @@ -20231,8 +20327,8 @@ msgstr "" msgid "" "(Difficult) Write a function `combineMaybe` which has type `forall a " "f. Applicative f => Maybe (f a) -> f (Maybe a)`. This function takes an " -"optional computation with side-effects, and returns a side-effecting " -"computation which has an optional result." +"optional computation with side-effects and returns a side-effecting " +"computation with an optional result." msgstr "" #. type: Plain text @@ -20241,8 +20337,8 @@ msgstr "" msgid "" "The source code for this chapter defines several data types which might be " "used in an address book application. The details are omitted here, but the " -"key functions which are exported by the `Data.AddressBook` module have the " -"following types:" +"key functions exported by the `Data.AddressBook` module have the following " +"types:" msgstr "" #. type: Fenced code block (haskell) @@ -20260,7 +20356,7 @@ msgstr "" #. type: Plain text #: text/chapter7.md:400 #, markdown-text -msgid "where `PhoneType` is defined as an algebraic data type:" +msgid "Where `PhoneType` is defined as an algebraic data type:" msgstr "" #. type: Fenced code block (haskell) @@ -20273,9 +20369,8 @@ msgstr "" #: text/chapter7.md:406 #, markdown-text msgid "" -"These functions can be used to construct a `Person` representing an address " -"book entry. For example, the following value is defined in " -"`Data.AddressBook`:" +"These functions can construct a `Person` representing an address book " +"entry. For example, the following value is defined in `Data.AddressBook`:" msgstr "" #. type: Fenced code block (haskell) @@ -20350,7 +20445,7 @@ msgstr "" msgid "" "In the first two lines, we use the `nonEmpty1` function to validate a " "non-empty string. `nonEmpty1` returns an error indicated with the `Left` " -"constructor if its input is empty, otherwise it returns the value wrapped " +"constructor if its input is empty. Otherwise, it returns the value wrapped " "with the `Right` constructor." msgstr "" @@ -20367,7 +20462,7 @@ msgstr "" #: text/chapter7.md:454 #, markdown-text msgid "" -"This function can be seen to work in PSCi, but has a limitation which we " +"This function can be seen to work in PSCi, but it has a limitation that we " "have seen before:" msgstr "" @@ -20384,19 +20479,18 @@ msgstr "" #, markdown-text msgid "" "The `Either String` applicative functor only provides the first error " -"encountered. Given the input here, we would prefer to see two errors - one " -"for the missing first name, and a second for the missing last name." +"encountered. Given the input here, we would prefer to see two errors – one " +"for the missing first name and a second for the missing last name." msgstr "" #. type: Plain text #: text/chapter7.md:463 #, markdown-text msgid "" -"There is another applicative functor which is provided by the `validation` " -"library. This functor is called `V`, and it provides the ability to return " -"errors in any _semigroup_. For example, we can use `V (Array String)` to " -"return an array of `String`s as errors, concatenating new errors onto the " -"end of the array." +"There is another applicative functor that the `validation` library " +"provides. This functor is called `V`, and it can return errors in any " +"_semigroup_. For example, we can use `V (Array String)` to return an array " +"of `String`s as errors, concatenating new errors onto the end of the array." msgstr "" #. type: Plain text @@ -20446,8 +20540,8 @@ msgstr "" #, markdown-text msgid "" "`validateAddress` validates an `Address` structure. It checks that the " -"`street` and `city` fields are non-empty, and checks that the string in the " -"`state` field has length 2." +"`street` and `city` fields are non-empty and that the string in the `state` " +"field has length 2." msgstr "" #. type: Plain text @@ -20580,7 +20674,7 @@ msgstr "" msgid "" "(Medium) Write a regular expression `nonEmptyRegex :: Regex` to check that a " "string is not entirely whitespace. _Hint_: If you need help developing this " -"regex expression, check out [RegExr](https://regexr.com) which has a great " +"regex expression, check out [RegExr](https://regexr.com), which has a great " "cheatsheet and interactive test environment." msgstr "" @@ -20621,6 +20715,12 @@ msgid "" "../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson}}\n" msgstr "" +#. type: Plain text +#: text/chapter7.md:557 +#, markdown-text +msgid "or with _applicative do_" +msgstr "" + #. type: Fenced code block (haskell) #: text/chapter7.md:558 #, no-wrap @@ -20633,7 +20733,7 @@ msgstr "" #: text/chapter7.md:563 #, markdown-text msgid "" -"`validatePhoneNumbers` uses a new function we haven't seen before - " +"`validatePhoneNumbers` uses a new function we haven't seen before – " "`traverse`." msgstr "" @@ -20668,10 +20768,9 @@ msgstr "" #, markdown-text msgid "" "Every traversable functor is both a `Functor` and `Foldable` (recall that a " -"_foldable functor_ was a type constructor which supported a fold operation, " +"_foldable functor_ was a type constructor that supported a fold operation, " "reducing a structure to a single value). In addition, a traversable functor " -"provides the ability to combine a collection of side-effects which depend on " -"its structure." +"can combine a collection of side-effects that depend on its structure." msgstr "" #. type: Plain text @@ -20724,7 +20823,7 @@ msgid "" "type `a`, then `traverse m` is a validation function for arrays of type " "`Array a`. But that's exactly what we need to be able to validate the " "`phones` field of the `Person` data structure! We pass `validatePhoneNumber` " -"to `traverse` to create a validation function which validates each element " +"to `traverse` to create a validation function that validates each element " "successively." msgstr "" @@ -20767,7 +20866,7 @@ msgid "" "Traversable functors capture the idea of traversing a data structure, " "collecting a set of effectful computations, and combining their effects. In " "fact, `sequence` and `traverse` are equally important to the definition of " -"`Traversable` - each can be implemented in terms of each other. This is left " +"`Traversable` – each can be implemented in terms of the other. This is left " "as an exercise for the interested reader." msgstr "" @@ -20801,11 +20900,11 @@ msgstr "" #: text/chapter7.md:620 #, markdown-text msgid "" -"In the case of an empty list, we can simply return an empty list using " -"`pure`. If the list is non-empty, we can use the function `f` to create a " -"computation of type `f b` from the head element. We can also call `traverse` " -"recursively on the tail. Finally, we can lift the `Cons` constructor over " -"the applicative functor `m` to combine the two results." +"In the case of an empty list, we can return an empty list using `pure`. If " +"the list is non-empty, we can use the function `f` to create a computation " +"of type `f b` from the head element. We can also call `traverse` recursively " +"on the tail. Finally, we can lift the `Cons` constructor over the " +"applicative functor `m` to combine the two results." msgstr "" #. type: Plain text @@ -20842,7 +20941,7 @@ msgid "" "These examples show that traversing the `Nothing` value returns `Nothing` " "with no validation, and traversing `Just x` uses the validation function to " "validate `x`. That is, `traverse` takes a validation function for type `a` " -"and returns a validation function for `Maybe a`, i.e. a validation function " +"and returns a validation function for `Maybe a`, i.e., a validation function " "for optional values of type `a`." msgstr "" @@ -20850,7 +20949,7 @@ msgstr "" #: text/chapter7.md:641 #, markdown-text msgid "" -"Other traversable functors include `Array`, and `Tuple a` and `Either a` for " +"Other traversable functors include `Array`, `Tuple a`, and `Either a` for " "any type `a`. Generally, most \"container\" data type constructors have " "`Traversable` instances. As an example, the exercises will include writing a " "`Traversable` instance for a type of binary trees." @@ -20878,7 +20977,7 @@ msgstr "" #, markdown-text, no-wrap msgid "" " Recall from the previous chapter that you may either write these " -"instances manually or let the compiler derive them for you.\n" +"instances manually or let the compiler derive them.\n" msgstr "" #. type: Plain text @@ -20886,9 +20985,9 @@ msgstr "" #, markdown-text, no-wrap msgid "" " There are many \"correct\" formatting options for `Show` output. The " -"test for this exercise expects the following whitespace style. This happens " -"to match the default formatting of generic show, so you only need to make " -"note of this if you're planning on writing this instance manually.\n" +"test for this exercise expects the following whitespace style. This matches " +"the default formatting of the generic show, so you only need to note this if " +"you're planning on writing this instance manually.\n" msgstr "" #. type: Plain text @@ -20905,7 +21004,7 @@ msgstr "" #, markdown-text msgid "" "(Medium) Write a `Traversable` instance for `Tree a`, which combines " -"side-effects from left-to-right. _Hint_: There are some additional instance " +"side-effects left-to-right. _Hint_: There are some additional instance " "dependencies that need to be defined for `Traversable`." msgstr "" @@ -20918,8 +21017,8 @@ msgid "" "of the tree. This means the order of effect execution is root-left-right, " "instead of left-root-right as was done for the previous in-order traverse " "exercise. _Hint_: No additional instances need to be defined, and you don't " -"need to call any of the the functions defined earlier. Applicative do " -"notation (`ado`) is the easiest way to write this function." +"need to call any of the functions defined earlier. Applicative do notation " +"(`ado`) is the easiest way to write this function." msgstr "" #. type: Bullet: ' 1. ' @@ -20981,8 +21080,8 @@ msgstr "" msgid "" "However, in general, applicative functors are more general than this. The " "applicative functor laws do not impose any ordering on the side-effects that " -"their computations perform. In fact, it would be valid for an applicative " -"functor to perform its side-effects in parallel." +"their computations perform. It would be valid for an applicative functor to " +"perform its side-effects in parallel." msgstr "" #. type: Plain text @@ -21001,8 +21100,8 @@ msgstr "" msgid "" "As a second example, the `parallel` package provides a type class `Parallel` " "which supports _parallel computations_. `Parallel` provides a function " -"`parallel` which uses some `Applicative` functor to compute the result of " -"its input computation _in parallel_:" +"`parallel` that uses some `Applicative` functor to compute the result of its " +"input computation _in parallel_:" msgstr "" #. type: Fenced code block (haskell) @@ -21034,7 +21133,7 @@ msgstr "" #: text/chapter7.md:690 #, markdown-text msgid "" -"Applicative functors are a natural way to capture side-effects which can be " +"Applicative functors are a natural way to capture side-effects that can be " "combined in parallel." msgstr "" @@ -21049,7 +21148,7 @@ msgstr "" #, markdown-text msgid "" "We introduced the concept of an _applicative functor_ which generalizes the " -"idea of function application to type constructors which capture some notion " +"idea of function application to type constructors that captures some notion " "of side-effect." msgstr "" @@ -21057,9 +21156,9 @@ msgstr "" #: text/chapter7.md:698 #, markdown-text msgid "" -"We saw how applicative functors gave a solution to the problem of validating " -"data structures, and how by switching the applicative functor we could " -"change from reporting a single error to reporting all errors across a data " +"We saw how applicative functors solved the problem of validating data " +"structures and how by switching the applicative functor, we could change " +"from reporting a single error to reporting all errors across a data " "structure." msgstr "" @@ -21076,13 +21175,13 @@ msgstr "" #: text/chapter7.md:700 #, markdown-text msgid "" -"Applicative functors are an interesting abstraction which provide neat " +"Applicative functors are an interesting abstraction that provides neat " "solutions to a number of problems. We will see them a few more times " "throughout the book. In this case, the validation applicative functor " "provided a way to write validators in a declarative style, allowing us to " "define _what_ our validators should validate and not _how_ they should " "perform that validation. In general, we will see that applicative functors " -"are a useful tool for the design of _domain specific languages_." +"are a useful tool for the design of _domain specific languages." msgstr "" #. type: Plain text @@ -21103,17 +21202,17 @@ msgstr "" #: text/chapter8.md:6 #, markdown-text msgid "" -"In the last chapter, we introduced applicative functors, an abstraction " -"which we used to deal with _side-effects_: optional values, error messages " -"and validation. This chapter will introduce another abstraction for dealing " -"with side-effects in a more expressive way: _monads_." +"In the last chapter, we introduced applicative functors, an abstraction we " +"used to deal with _side-effects_: optional values, error messages, and " +"validation. This chapter will introduce another abstraction for dealing with " +"side-effects more expressively: _monads_." msgstr "" #. type: Plain text #: text/chapter8.md:8 #, markdown-text msgid "" -"The goal of this chapter is to explain why monads are a useful abstraction, " +"The goal of this chapter is to explain why monads are a useful abstraction " "and their connection with _do notation_." msgstr "" @@ -21127,18 +21226,16 @@ msgstr "" #: text/chapter8.md:15 #, markdown-text msgid "" -"`effect` - defines the `Effect` monad, the subject of the second half of the " +"`effect` – defines the `Effect` monad, the subject of the second half of the " "chapter. This dependency is often listed in every starter project (it's been " -"a dependency of every chapter so far), so you'll rarely have to explicitly " -"install it." +"a dependency of every chapter so far), so you'll rarely have to install it " +"explicitly." msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:15 #, markdown-text -msgid "" -"`react-basic-hooks` - a web framework that we will use for our Address Book " -"app." +msgid "`react-basic-hooks` – a web framework we will use for our Address Book app." msgstr "" #. type: Title ## @@ -21180,15 +21277,15 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:25 #, markdown-text -msgid "If the sum of `x` and `y` is `n` then return the pair `[x, y]`, else fail." +msgid "If the sum of `x` and `y` is `n`, return the pair `[x, y]`, else fail." msgstr "" #. type: Plain text #: text/chapter8.md:27 #, markdown-text msgid "" -"Array comprehensions allow us to write this non-deterministic algorithm in a " -"natural way:" +"Array comprehensions allow us to write this non-deterministic algorithm " +"naturally:" msgstr "" #. type: Fenced code block (hs) @@ -21237,13 +21334,13 @@ msgstr "" #: text/chapter8.md:52 #, markdown-text msgid "" -"In general, a _monad_ for some type constructor `m` provides a way to use do " +"Generally, a _monad_ for some type constructor `m` provides a way to use do " "notation with values of type `m a`. Note that in the array comprehension " "above, every line contains a computation of type `Array a` for some type " "`a`. In general, every line of a do notation block will contain a " "computation of type `m a` for some type `a` and our monad `m`. The monad `m` " -"must be the same on every line (i.e. we fix the side-effect), but the types " -"`a` can differ (i.e. individual computations can have different result " +"must be the same on every line (i.e., we fix the side-effect), but the types " +"`a` can differ (i.e., individual computations can have different result " "types)." msgstr "" @@ -21266,7 +21363,7 @@ msgstr "" #: text/chapter8.md:60 #, markdown-text msgid "" -"which looks for a child element of a node, and returns `Nothing` if no such " +"Which looks for a child element of a node and returns `Nothing` if no such " "element exists." msgstr "" @@ -21274,8 +21371,8 @@ msgstr "" #: text/chapter8.md:62 #, markdown-text msgid "" -"In this case, we can look for a deeply-nested element by using do " -"notation. Suppose we wanted to read a user's city from a user profile which " +"In this case, we can look for a deeply-nested element using do " +"notation. Suppose we wanted to read a user's city from a user profile that " "had been encoded as an XML document:" msgstr "" @@ -21296,10 +21393,10 @@ msgstr "" #, markdown-text msgid "" "The `userCity` function looks for a child element `profile`, an element " -"`address` inside the `profile` element, and finally an element `city` inside " -"the `address` element. If any of these elements are missing, the return " -"value will be `Nothing`. Otherwise, the return value is constructed using " -"`Just` from the `city` node." +"`address` inside the `profile` element, and finally, an element `city` " +"inside the `address` element. If any of these elements are missing, the " +"return value will be `Nothing`. Otherwise, the return value is constructed " +"using `Just` from the `city` node." msgstr "" #. type: Plain text @@ -21348,7 +21445,7 @@ msgstr "" #, markdown-text msgid "" "The `Monad` type class extends `Bind` with the operations of the " -"`Applicative` type class that we have already seen." +"`Applicative` type class we've already seen." msgstr "" #. type: Plain text @@ -21403,7 +21500,7 @@ msgstr "" #, markdown-text msgid "" "Let's see how the `Bind` type class is related to do notation. Consider a " -"simple do notation block which starts by binding a value from the result of " +"simple do notation block that starts by binding a value from the result of " "some computation:" msgstr "" @@ -21472,10 +21569,10 @@ msgstr "" #: text/chapter8.md:143 #, markdown-text, no-wrap msgid "" -"It is worth noting that code expressed using do notation is often much " -"clearer than the equivalent code using the `>>=` operator. However, writing " -"binds explicitly using `>>=` can often lead to opportunities to write code " -"in _point-free_ form - but the usual warnings about readability apply.\n" +"Notably, code expressed using do notation is often much clearer than the " +"equivalent code using the `>>=` operator. However, writing binds explicitly " +"using `>>=` can often lead to opportunities to write code in _point-free_ " +"form – but the usual warnings about readability apply.\n" msgstr "" #. type: Title ## @@ -21593,9 +21690,9 @@ msgstr "" #: text/chapter8.md:192 #, markdown-text msgid "" -"Each of these computations involves three monadic expression `m1`, `m2` and " -"`m3`. In each case, the result of `m1` is eventually bound to the name `x`, " -"and the result of `m2` is bound to the name `y`." +"Each of these computations involves three monadic expressions `m1`, `m2`, " +"and `m3`. In each case, the result of `m1` is eventually bound to the name " +"`x`, and the result of `m2` is bound to the name `y`." msgstr "" #. type: Plain text @@ -21610,7 +21707,7 @@ msgstr "" #: text/chapter8.md:196 #, markdown-text msgid "" -"In `c2`, all three expressions `m1`, `m2` and `m3` appear in the same do " +"In `c2`, all three expressions `m1`, `m2`, and `m3` appear in the same do " "notation block." msgstr "" @@ -21652,10 +21749,10 @@ msgstr "" #, markdown-text msgid "" "As an example of working with monads abstractly, this section will present a " -"function which works with any type constructor in the `Monad` type " -"class. This should serve to solidify the intuition that monadic code " -"corresponds to programming \"in a larger language\" with side-effects, and " -"also illustrate the generality which programming with monads brings." +"function that works with any type constructor in the `Monad` type " +"class. This should solidify the intuition that monadic code corresponds to " +"programming \"in a larger language\" with side-effects, and also illustrate " +"the generality which programming with monads brings." msgstr "" #. type: Plain text @@ -21663,8 +21760,7 @@ msgstr "" #, markdown-text msgid "" "The function we will write is called `foldM`. It generalizes the `foldl` " -"function that we met earlier to a monadic context. Here is its type " -"signature:" +"function we met earlier to a monadic context. Here is its type signature:" msgstr "" #. type: Fenced code block (hs) @@ -21696,7 +21792,7 @@ msgstr "" #, markdown-text msgid "" "For example, if we picked `m` to be `Maybe`, then our fold would be allowed " -"to fail by returning `Nothing` at any stage - every step returns an optional " +"to fail by returning `Nothing` at any stage – every step returns an optional " "result, and the result of the fold is therefore also optional." msgstr "" @@ -21706,7 +21802,7 @@ msgstr "" msgid "" "If we picked `m` to be the `Array` type constructor, then every step of the " "fold would be allowed to return zero or more results, and the fold would " -"proceed to the next step independently for each result. At the end, the set " +"proceed to the next step independently for each result. In the end, the set " "of results would consist of all folds over all possible paths. This " "corresponds to a traversal of a graph!" msgstr "" @@ -21769,14 +21865,14 @@ msgstr "" #, markdown-text msgid "" "Note that this implementation is almost identical to that of `foldl` on " -"lists, with the exception of do notation." +"lists, except for do notation." msgstr "" #. type: Plain text #: text/chapter8.md:251 #, markdown-text msgid "" -"We can define and test this function in PSCi. Here is an example - suppose " +"We can define and test this function in PSCi. Here is an example – suppose " "we defined a \"safe division\" function on integers, which tested for " "division by zero and used the `Maybe` type constructor to indicate failure:" msgstr "" @@ -21812,7 +21908,7 @@ msgstr "" #, markdown-text msgid "" "The `foldM safeDivide` function returns `Nothing` if a division by zero was " -"attempted at any point. Otherwise it returns the result of repeatedly " +"attempted at any point. Otherwise, it returns the result of repeatedly " "dividing the accumulator, wrapped in the `Just` constructor." msgstr "" @@ -21863,7 +21959,7 @@ msgstr "" #, markdown-text msgid "" "The interested reader can check that `ap` agrees with `apply` for the monads " -"we have already encountered: `Array`, `Maybe` and `Either e`." +"we have already encountered: `Array`, `Maybe`, and `Either e`." msgstr "" #. type: Plain text @@ -21885,7 +21981,7 @@ msgid "" "But monads allow us to do more than we could do with just applicative " "functors, and the key difference is highlighted by the syntax of do " "notation. Consider the `userCity` example again, in which we looked for a " -"user's city in an XML document which encoded their user profile:" +"user's city in an XML document that encoded their user profile:" msgstr "" #. type: Plain text @@ -21916,14 +22012,14 @@ msgid "" "express parallelism. This was precisely because the function arguments being " "lifted were independent of one another. Since the `Monad` type class allows " "computations to depend on the results of previous computations, the same " -"does not apply - a monad has to combine its side-effects in sequence." +"does not apply – a monad has to combine its side-effects in sequence." msgstr "" #. type: Bullet: ' 1. ' #: text/chapter8.md:312 #, markdown-text msgid "" -"(Easy) Write a function `third` which returns the third element of an array " +"(Easy) Write a function `third` that returns the third element of an array " "with three or more elements. Your function should return an appropriate " "`Maybe` type. _Hint:_ Look up the types of the `head` and `tail` functions " "from the `Data.Array` module in the `arrays` package. Use do notation with " @@ -21964,7 +22060,7 @@ msgstr "" msgid "" " _Hint_: This function can be written as a one-liner using `foldM`. You " "might want to use the `nub` and `sort` functions to remove duplicates and " -"sort the result respectively.\n" +"sort the result.\n" " 1. (Medium) Confirm that the `ap` function and the `apply` operator agree " "for the `Maybe` monad. _Note:_ There are no tests for this exercise.\n" " 1. (Medium) Verify that the monad laws hold for the `Monad` instance for " @@ -22020,7 +22116,7 @@ msgstr "" #: text/chapter8.md:345 #, markdown-text, no-wrap msgid "" -" where the `Apply` instance uses the `ap` function defined above. Recall " +" Where the `Apply` instance uses the `ap` function defined above. Recall " "that `lift2` was defined as follows:\n" msgstr "" @@ -22051,8 +22147,8 @@ msgstr "" #: text/chapter8.md:356 #, markdown-text msgid "" -"We will now look at one particular monad which is of central importance in " -"PureScript - the `Effect` monad." +"We will now look at one particular monad of central importance in PureScript " +"– the `Effect` monad." msgstr "" #. type: Plain text @@ -22068,7 +22164,7 @@ msgstr "" #: text/chapter8.md:360 #, markdown-text msgid "" -"What are native side-effects? They are the side-effects which distinguish " +"What are native side-effects? They are the side-effects that distinguish " "JavaScript expressions from idiomatic PureScript expressions, which " "typically are free from side-effects. Some examples of native effects are:" msgstr "" @@ -22150,12 +22246,12 @@ msgstr "" #, markdown-text msgid "" "Note that the distinction is subtle. It is true, for example, that an error " -"message is a possible side-effect of a JavaScript expression, in the form of " +"message is a possible side-effect of a JavaScript expression in the form of " "an exception. In that sense, exceptions do represent native side-effects, " "and it is possible to represent them using `Effect`. However, error messages " "implemented using `Either` are not a side-effect of the JavaScript runtime, " "and so it is not appropriate to implement error messages in that style using " -"`Effect`. So it is not the effect itself which is native, but rather how it " +"`Effect`. So it is not the effect itself, which is native, but rather how it " "is implemented at runtime." msgstr "" @@ -22169,18 +22265,18 @@ msgstr "" #: text/chapter8.md:384 #, markdown-text msgid "" -"In a pure language like PureScript, one question which presents itself is: " -"without side-effects, how can one write useful real-world code?" +"In a pure language like PureScript, one question presents itself: without " +"side-effects, how can one write useful real-world code?" msgstr "" #. type: Plain text #: text/chapter8.md:386 #, markdown-text msgid "" -"The answer is that PureScript does not aim to eliminate side-effects. It " -"aims to represent side-effects in such a way that pure computations can be " -"distinguished from computations with side-effects in the type system. In " -"this sense, the language is still pure." +"The answer is that PureScript does not aim to eliminate side-effects but to " +"represent them in such a way that pure computations can be distinguished " +"from computations with side-effects in the type system. In this sense, the " +"language is still pure." msgstr "" #. type: Plain text @@ -22188,23 +22284,23 @@ msgstr "" #, markdown-text msgid "" "Values with side-effects have different types from pure values. As such, it " -"is not possible to pass a side-effecting argument to a function, for " -"example, and have side-effects performed unexpectedly." +"is impossible to pass a side-effecting argument to a function, for example, " +"and have side-effects performed unexpectedly." msgstr "" #. type: Plain text #: text/chapter8.md:390 #, markdown-text msgid "" -"The only way in which side-effects managed by the `Effect` monad will be " -"presented is to run a computation of type `Effect a` from JavaScript." +"The only way side-effects managed by the `Effect` monad will be presented is " +"to run a computation of type `Effect a` from JavaScript." msgstr "" #. type: Plain text #: text/chapter8.md:392 #, markdown-text msgid "" -"The Spago build tool (and other tools) provide a shortcut, by generating " +"The Spago build tool (and other tools) provide a shortcut by generating " "additional JavaScript to invoke the `main` computation when the application " "starts. `main` is required to be a computation in the `Effect` monad." msgstr "" @@ -22218,24 +22314,31 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:399 +#: text/chapter8.md:398 #, markdown-text msgid "" -"Let's take a closer look at the return type of the familiar `log` " -"function. `Effect` indicates that this function produces a native effect, " -"console IO in this case. `Unit` indicates that no _meaningful_ data is " -"returned. You can think of `Unit` as being analogous to the `void` keyword " -"in other languages, such as C, Java, etc." +"Let's look at the return type of the familiar `log` function. `Effect` " +"indicates that this function produces a native effect, console IO in this " +"case." msgstr "" -#. type: Fenced code block (hs) +#. type: Plain text #: text/chapter8.md:400 +#, markdown-text +msgid "" +"`Unit` indicates that no _meaningful_ data is returned. You can think of " +"`Unit` as analogous to the `void` keyword in other languages, such as C, " +"Java, etc." +msgstr "" + +#. type: Fenced code block (hs) +#: text/chapter8.md:401 #, no-wrap msgid "log :: String -> Effect Unit\n" msgstr "" #. type: Plain text -#: text/chapter8.md:409 +#: text/chapter8.md:410 #, markdown-text, no-wrap msgid "" "> _Aside:_ You may encounter IDE suggestions for the more general (and more " @@ -22252,7 +22355,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:411 +#: text/chapter8.md:412 #, markdown-text msgid "" "Now let's consider an `Effect` that returns meaningful data. The `random` " @@ -22260,13 +22363,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:412 +#: text/chapter8.md:413 #, no-wrap msgid "random :: Effect Number\n" msgstr "" #. type: Plain text -#: text/chapter8.md:417 +#: text/chapter8.md:418 #, markdown-text msgid "" "Here's a full example program (found in `test/Random.purs` of this chapter's " @@ -22274,13 +22377,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:418 +#: text/chapter8.md:419 #, no-wrap msgid "{{#include ../exercises/chapter8/test/Random.purs}}\n" msgstr "" #. type: Plain text -#: text/chapter8.md:423 +#: text/chapter8.md:424 #, markdown-text msgid "" "Because `Effect` is a monad, we use do notation to _unwrap_ the data it " @@ -22289,7 +22392,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:424 +#: text/chapter8.md:425 #, no-wrap msgid "" "main :: Effect Unit\n" @@ -22297,19 +22400,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:430 +#: text/chapter8.md:431 #, markdown-text msgid "Try running this yourself with:" msgstr "" #. type: Fenced code block (shell) -#: text/chapter8.md:431 +#: text/chapter8.md:432 #, no-wrap msgid "spago run --main Test.Random\n" msgstr "" #. type: Plain text -#: text/chapter8.md:436 +#: text/chapter8.md:437 #, markdown-text msgid "" "You should see a randomly chosen number between `0.0` and `1.0` printed to " @@ -22317,17 +22420,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:438 +#: text/chapter8.md:439 #, markdown-text, no-wrap msgid "" "> _Aside:_ `spago run` defaults to searching in the `Main` module for a " "`main` function. You may also specify an alternate module as an entry point " -"with the `--main` flag, as is done in the above example. Just be sure that " -"this alternate module also contains a `main` function.\n" +"with the `--main` flag, as in the above example. Just be sure that this " +"alternate module also contains a `main` function.\n" msgstr "" #. type: Plain text -#: text/chapter8.md:440 +#: text/chapter8.md:441 #, markdown-text msgid "" "Note that it's also possible to generate \"random\" (technically " @@ -22336,42 +22439,42 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:442 +#: text/chapter8.md:443 #, markdown-text msgid "" "As mentioned previously, the `Effect` monad is of central importance to " -"PureScript. The reason why it's central is because it is the conventional " -"way to interoperate with PureScript's `Foreign Function Interface`, which " +"PureScript. The reason why it's central is that it is the conventional way " +"to interoperate with PureScript's `Foreign Function Interface`, which " "provides the mechanism to execute a program and perform side effects. While " -"it's desireable to avoid using the `Foreign Function Interface`, it's fairly " +"it's desirable to avoid using the `Foreign Function Interface`, it's fairly " "critical to understand how it works and how to use it, so I recommend " "reading that chapter before doing any serious PureScript work. That said, " -"the `Effect` monad is fairly simple. It has a few helper functions, but " -"aside from that it doesn't do much except encapsulate side effects." +"the `Effect` monad is fairly simple. It has a few helper functions but " +"doesn't do much except encapsulate side effects." msgstr "" #. type: Plain text -#: text/chapter8.md:446 +#: text/chapter8.md:447 #, markdown-text msgid "" "Let's examine a function from the `node-fs` package that involves two " -"_native_ side effects: reading mutable state, and exceptions:" +"_native_ side effects: reading mutable state and exceptions:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:447 +#: text/chapter8.md:448 #, no-wrap msgid "readTextFile :: Encoding -> String -> Effect String\n" msgstr "" #. type: Plain text -#: text/chapter8.md:452 +#: text/chapter8.md:453 #, markdown-text msgid "If we attempt to read a file that does not exist:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:453 +#: text/chapter8.md:454 #, no-wrap msgid "" "import Node.Encoding (Encoding(..))\n" @@ -22384,13 +22487,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:464 +#: text/chapter8.md:465 #, markdown-text msgid "We encounter the following exception:" msgstr "" #. type: Fenced code block (text) -#: text/chapter8.md:465 +#: text/chapter8.md:466 #, no-wrap msgid "" " throw err;\n" @@ -22404,7 +22507,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:477 +#: text/chapter8.md:478 #, markdown-text msgid "" "To manage this exception gracefully, we can wrap the potentially problematic " @@ -22412,7 +22515,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:478 +#: text/chapter8.md:479 #, no-wrap msgid "" "main :: Effect Unit\n" @@ -22425,7 +22528,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:488 +#: text/chapter8.md:489 #, markdown-text msgid "" "`try` runs an `Effect` and returns eventual exceptions as a `Left` value. If " @@ -22433,22 +22536,22 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:489 +#: text/chapter8.md:490 #, no-wrap msgid "try :: forall a. Effect a -> Effect (Either Error a)\n" msgstr "" #. type: Plain text -#: text/chapter8.md:494 +#: text/chapter8.md:495 #, markdown-text msgid "" "We can also generate our own exceptions. Here is an alternative " -"implementation of `Data.List.head` which throws an exception if the list is " -"empty, rather than returning a `Maybe` value of `Nothing`." +"implementation of `Data.List.head` that throws an exception if the list is " +"empty rather than returning a `Maybe` value of `Nothing`." msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:495 +#: text/chapter8.md:496 #, no-wrap msgid "" "exceptionHead :: List Int -> Effect Int\n" @@ -22458,7 +22561,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:503 +#: text/chapter8.md:504 #, markdown-text msgid "" "Note that the `exceptionHead` function is a somewhat impractical example, as " @@ -22468,19 +22571,19 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter8.md:504 +#: text/chapter8.md:505 #, markdown-text, no-wrap msgid "Mutable State" msgstr "" #. type: Plain text -#: text/chapter8.md:507 +#: text/chapter8.md:508 #, markdown-text msgid "There is another effect defined in the core libraries: the `ST` effect." msgstr "" #. type: Plain text -#: text/chapter8.md:509 +#: text/chapter8.md:510 #, markdown-text msgid "" "The `ST` effect is used to manipulate mutable state. As pure functional " @@ -22490,7 +22593,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:511 +#: text/chapter8.md:512 #, markdown-text msgid "" "The `ST` effect is defined in the `Control.Monad.ST` module. To see how it " @@ -22498,7 +22601,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:512 +#: text/chapter8.md:513 #, no-wrap msgid "" "new :: forall a r. a -> ST r (STRef r a)\n" @@ -22511,27 +22614,27 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:523 +#: text/chapter8.md:524 #, markdown-text msgid "" "`new` is used to create a new mutable reference cell of type `STRef r a`, " -"which can be read using the `read` action, and modified using the `write` " -"and `modify` actions. The type `a` is the type of the value stored in the " -"cell, and the type `r` is used to indicate a _memory region_ (or _heap_) in " -"the type system." +"which can be read using the `read` action and modified using the `write` and " +"`modify` actions. The type `a` is the type of the value stored in the cell, " +"and the type `r` is used to indicate a _memory region_ (or _heap_) in the " +"type system." msgstr "" #. type: Plain text -#: text/chapter8.md:525 +#: text/chapter8.md:526 #, markdown-text msgid "" "Here is an example. Suppose we want to simulate the movement of a particle " -"falling under gravity by iterating a simple update function over a large " -"number of small time steps." +"falling under gravity by iterating a simple update function over many small " +"time steps." msgstr "" #. type: Plain text -#: text/chapter8.md:527 +#: text/chapter8.md:528 #, markdown-text msgid "" "We can do this by creating a mutable reference cell to hold the position and " @@ -22540,7 +22643,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:528 +#: text/chapter8.md:529 #, no-wrap msgid "" "import Prelude\n" @@ -22564,25 +22667,25 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:550 +#: text/chapter8.md:551 #, markdown-text msgid "" -"At the end of the computation, we read the final value of the reference " -"cell, and return the position of the particle." +"At the end of the computation, we read the final value of the reference cell " +"and return the position of the particle." msgstr "" #. type: Plain text -#: text/chapter8.md:552 +#: text/chapter8.md:553 #, markdown-text msgid "" -"Note that even though this function uses mutable state, it is still a pure " +"Note that even though this function uses a mutable state, it is still a pure " "function, so long as the reference cell `ref` is not allowed to be used by " -"other parts of the program. We will see that this is exactly what the `ST` " -"effect disallows." +"other program parts. We will see that this is exactly what the `ST` effect " +"disallows." msgstr "" #. type: Plain text -#: text/chapter8.md:554 +#: text/chapter8.md:555 #, markdown-text msgid "" "To run a computation with the `ST` effect, we have to use the `run` " @@ -22590,13 +22693,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:555 +#: text/chapter8.md:556 #, no-wrap msgid "run :: forall a. (forall r. ST r a) -> a\n" msgstr "" #. type: Plain text -#: text/chapter8.md:560 +#: text/chapter8.md:561 #, markdown-text msgid "" "The thing to notice here is that the region type `r` is quantified _inside " @@ -22605,17 +22708,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:562 +#: text/chapter8.md:563 #, markdown-text msgid "" "However, once a reference cell has been created by `new`, its region type is " "already fixed, so it would be a type error to try to use the reference cell " -"outside the code delimited by `run`. This is what allows `run` to safely " -"remove the `ST` effect, and turn `simulate` into a pure function!" +"outside the code delimited by `run`. This allows `run` to safely remove the " +"`ST` effect and turn `simulate` into a pure function!" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:563 +#: text/chapter8.md:564 #, no-wrap msgid "" "simulate' :: Number -> Number -> Int -> Number\n" @@ -22623,13 +22726,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:569 +#: text/chapter8.md:570 #, markdown-text msgid "You can even try running this function in PSCi:" msgstr "" #. type: Fenced code block (text) -#: text/chapter8.md:570 +#: text/chapter8.md:571 #, no-wrap msgid "" "> import Main\n" @@ -22651,7 +22754,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:590 +#: text/chapter8.md:591 #, markdown-text msgid "" "In fact, if we inline the definition of `simulate` at the call to `run`, as " @@ -22659,7 +22762,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:591 +#: text/chapter8.md:592 #, no-wrap msgid "" "simulate :: Number -> Number -> Int -> Number\n" @@ -22679,16 +22782,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:609 +#: text/chapter8.md:610 #, markdown-text msgid "" -"then the compiler will notice that the reference cell is not allowed to " -"escape its scope, and can safely turn `ref` into a `var`. Here is the " -"generated JavaScript for `simulate` inlined with `run`:" +"Then the compiler will notice that the reference cell cannot escape its " +"scope and can safely turn `ref` into a `var`. Here is the generated " +"JavaScript for `simulate` inlined with `run`:" msgstr "" #. type: Fenced code block (javascript) -#: text/chapter8.md:610 +#: text/chapter8.md:611 #, no-wrap msgid "" "var simulate = function (x0) {\n" @@ -22717,24 +22820,24 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:636 -#, markdown-text +#: text/chapter8.md:637 +#, markdown-text, no-wrap msgid "" -"Note that this resulting JavaScript is not as optimal as it could be. See " +"> Note that this resulting JavaScript is not as optimal as it could be. See " "[this " "issue](https://github.com/purescript-contrib/purescript-book/issues/121) for " "more details. The above snippet should be updated once that issue is " -"resolved." +"resolved.\n" msgstr "" #. type: Plain text -#: text/chapter8.md:638 +#: text/chapter8.md:639 #, markdown-text msgid "For comparison, this is the generated JavaScript of the non-inlined form:" msgstr "" #. type: Fenced code block (js) -#: text/chapter8.md:639 +#: text/chapter8.md:640 #, no-wrap msgid "" "var simulate = function (x0) {\n" @@ -22763,16 +22866,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:665 +#: text/chapter8.md:666 #, markdown-text msgid "" "The `ST` effect is a good way to generate short JavaScript when working with " "locally-scoped mutable state, especially when used together with actions " -"like `for`, `foreach`, and `while` which generate efficient loops." +"like `for`, `foreach`, and `while`, which generate efficient loops." msgstr "" #. type: Bullet: '1. ' -#: text/chapter8.md:671 +#: text/chapter8.md:672 #, markdown-text msgid "" "(Medium) Rewrite the `safeDivide` function as `exceptionDivide` and throw an " @@ -22781,7 +22884,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter8.md:671 +#: text/chapter8.md:672 #, markdown-text msgid "" "(Medium) Write a function `estimatePi :: Int -> Number` that uses `n` terms " @@ -22792,7 +22895,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter8.md:671 +#: text/chapter8.md:672 #, markdown-text msgid "" "(Medium) Write a function `fibonacci :: Int -> Int` to compute the `n`th " @@ -22802,13 +22905,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter8.md:672 +#: text/chapter8.md:673 #, markdown-text, no-wrap msgid "DOM Effects" msgstr "" #. type: Plain text -#: text/chapter8.md:675 +#: text/chapter8.md:676 #, markdown-text msgid "" "In the final sections of this chapter, we will apply what we have learned " @@ -22816,33 +22919,33 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:677 +#: text/chapter8.md:678 #, markdown-text msgid "" -"There are a number of PureScript packages for working directly with the DOM, " -"or with open-source DOM libraries. For example:" +"There are several PureScript packages for working directly with the DOM or " +"open-source DOM libraries. For example:" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 #, markdown-text msgid "" "[`web-dom`](https://github.com/purescript-web/purescript-web-dom) provides " -"type definitions and low level interface implementations for the W3C DOM " +"type definitions and low-level interface implementations for the W3C DOM " "spec." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 #, markdown-text msgid "" "[`web-html`](https://github.com/purescript-web/purescript-web-html) provides " -"type definitions and low level interface implementations for the W3C HTML5 " +"type definitions and low-level interface implementations for the W3C HTML5 " "spec." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 #, markdown-text msgid "" "[`jquery`](https://github.com/paf31/purescript-jquery) is a set of bindings " @@ -22850,41 +22953,40 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:683 +#: text/chapter8.md:684 #, markdown-text msgid "" -"There are also PureScript libraries which build abstractions on top of these " +"There are also PureScript libraries that build abstractions on top of these " "libraries, such as" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 #, markdown-text msgid "" -"[`thermite`](https://github.com/paf31/purescript-thermite), which builds on " +"[`thermite`](https://github.com/paf31/purescript-thermite) builds on " "[`react`](https://github.com/purescript-contrib/purescript-react)" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 #, markdown-text msgid "" -"[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-hooks), " -"which builds on " -"[`react-basic`](https://github.com/lumihq/purescript-react-basic)" +"[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-hooks) " +"builds on [`react-basic`](https://github.com/lumihq/purescript-react-basic)" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 #, markdown-text msgid "" -"[`halogen`](https://github.com/purescript-halogen/purescript-halogen) which " +"[`halogen`](https://github.com/purescript-halogen/purescript-halogen) " "provides a type-safe set of abstractions on top of a custom virtual DOM " "library." msgstr "" #. type: Plain text -#: text/chapter8.md:689 +#: text/chapter8.md:690 #, markdown-text msgid "" "In this chapter, we will use the `react-basic-hooks` library to add a user " @@ -22893,13 +22995,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter8.md:690 +#: text/chapter8.md:691 #, markdown-text, no-wrap msgid "An Address Book User Interface" msgstr "" #. type: Plain text -#: text/chapter8.md:693 +#: text/chapter8.md:694 #, markdown-text msgid "" "Using the `react-basic-hooks` library, we will define our application as a " @@ -22911,7 +23013,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:695 +#: text/chapter8.md:696 #, markdown-text msgid "" "A full tutorial for the React library is well beyond the scope of this " @@ -22921,18 +23023,18 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:697 +#: text/chapter8.md:698 #, markdown-text msgid "" -"We are going to build a form which will allow a user to add a new entry into " +"We are going to build a form that will allow a user to add a new entry into " "our address book. The form will contain text boxes for the various fields " -"(first name, last name, city, state, etc.), and an area in which validation " +"(first name, last name, city, state, etc.) and an area where validation " "errors will be displayed. As the user types text into the text boxes, the " "validation errors will be updated." msgstr "" #. type: Plain text -#: text/chapter8.md:699 +#: text/chapter8.md:700 #, markdown-text msgid "" "To keep things simple, the form will have a fixed shape: the different phone " @@ -22941,7 +23043,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:701 +#: text/chapter8.md:702 #, markdown-text msgid "" "You can launch the web app from the `exercises/chapter8` directory with the " @@ -22949,7 +23051,7 @@ msgid "" msgstr "" #. type: Fenced code block (shell) -#: text/chapter8.md:702 +#: text/chapter8.md:703 #, no-wrap msgid "" "$ npm install\n" @@ -22958,7 +23060,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:709 +#: text/chapter8.md:710 #, markdown-text msgid "" "If development tools such as `spago` and `parcel` are installed globally, " @@ -22968,11 +23070,11 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:711 +#: text/chapter8.md:712 #, markdown-text msgid "" "`parcel` should launch a browser window with our \"Address Book\" app. If " -"you keep the `parcel` terminal open, and rebuild with `spago` in another " +"you keep the `parcel` terminal open and rebuild with `spago` in another " "terminal, the page should automatically refresh with your latest edits. You " "can also configure automatic rebuilds (and therefore automatic page refresh) " "on file-save if you're using an " @@ -22983,33 +23085,33 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:713 +#: text/chapter8.md:714 #, markdown-text msgid "" -"In this Address Book app, you should be able to enter some values into the " -"form fields and see the validation errors printed onto the page." +"In this Address Book app, you can enter some values into the form fields and " +"see the validation errors printed onto the page." msgstr "" #. type: Plain text -#: text/chapter8.md:715 +#: text/chapter8.md:716 #, markdown-text msgid "Let's explore how it works." msgstr "" #. type: Plain text -#: text/chapter8.md:717 +#: text/chapter8.md:718 #, markdown-text msgid "The `src/index.html` file is minimal:" msgstr "" #. type: Fenced code block (html) -#: text/chapter8.md:718 +#: text/chapter8.md:719 #, no-wrap msgid "{{#include ../exercises/chapter8/src/index.html}}\n" msgstr "" #. type: Plain text -#: text/chapter8.md:723 +#: text/chapter8.md:724 #, markdown-text, no-wrap msgid "" "The ` pure $ D.text \"Hi! I'm an address book\"\n" msgstr "" #. type: Plain text -#: text/chapter8.md:795 +#: text/chapter8.md:796 #, markdown-text msgid "" "`props` are ignored, `D.text` returns `JSX`, and `pure` lifts to rendered " @@ -23178,21 +23280,21 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:797 +#: text/chapter8.md:798 #, markdown-text msgid "" -"Next we'll examine some of the additional complexities of the full Address " +"Next, we'll examine some of the additional complexities of the full Address " "Book component." msgstr "" #. type: Plain text -#: text/chapter8.md:799 +#: text/chapter8.md:800 #, markdown-text msgid "These are the first few lines of our full component:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:800 +#: text/chapter8.md:801 #, no-wrap msgid "" "mkAddressBookApp :: Effect (ReactComponent {})\n" @@ -23202,30 +23304,29 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:808 +#: text/chapter8.md:809 #, markdown-text msgid "We track `person` as a piece of state with the `useState` hook." msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:809 +#: text/chapter8.md:810 #, no-wrap msgid "Tuple person setPerson <- useState examplePerson\n" msgstr "" #. type: Plain text -#: text/chapter8.md:814 +#: text/chapter8.md:815 #, markdown-text msgid "" "Note that you are free to break-up component state into multiple pieces of " "state with multiple calls to `useState`. For example, we could rewrite this " "app to use a separate piece of state for each record field of `Person`, but " -"that happens to result in a slightly less convenient architecture in this " -"case." +"that results in a slightly less convenient architecture in this case." msgstr "" #. type: Plain text -#: text/chapter8.md:816 +#: text/chapter8.md:817 #, markdown-text msgid "" "In other examples, you may encounter the `/\\` infix operator for " @@ -23233,13 +23334,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:817 +#: text/chapter8.md:818 #, no-wrap msgid "firstName /\\ setFirstName <- useState p.firstName\n" msgstr "" #. type: Plain text -#: text/chapter8.md:822 +#: text/chapter8.md:823 #, markdown-text msgid "" "`useState` takes a default initial value and returns the current value and a " @@ -23248,7 +23349,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:823 +#: text/chapter8.md:824 #, no-wrap msgid "" "useState ::\n" @@ -23258,7 +23359,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:831 +#: text/chapter8.md:832 #, markdown-text msgid "" "We can strip the `Hook (UseState state)` wrapper off of the return value " @@ -23267,13 +23368,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:833 +#: text/chapter8.md:834 #, markdown-text msgid "So now we can observe the following signatures:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:834 +#: text/chapter8.md:835 #, no-wrap msgid "" "person :: state\n" @@ -23281,7 +23382,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:840 +#: text/chapter8.md:841 #, markdown-text msgid "" "The specific type of `state` is determined by our initial default " @@ -23290,23 +23391,23 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:842 +#: text/chapter8.md:843 #, markdown-text msgid "`person` is how we access the current state at each rerender." msgstr "" #. type: Plain text -#: text/chapter8.md:844 +#: text/chapter8.md:845 #, markdown-text msgid "" -"`setPerson` is how we update the state. We simply provide a function that " -"describes how to transform the current state to the new state. The record " -"update syntax is perfect for this when the type of `state` happens to be a " -"`Record`, for example:" +"`setPerson` is how we update the state. We provide a function describing how " +"to transform the current state into the new one. The record update syntax is " +"perfect for this when the type of `state` happens to be a `Record`, for " +"example:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:845 +#: text/chapter8.md:846 #, no-wrap msgid "" "setPerson (\\currentPerson -> currentPerson {firstName = \"NewName\"})\n" @@ -23314,19 +23415,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:851 +#: text/chapter8.md:852 #, markdown-text -msgid "or as shorthand:" +msgid "Or as shorthand:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:852 +#: text/chapter8.md:853 #, no-wrap msgid "setPerson _ {firstName = \"NewName\"}\n" msgstr "" #. type: Plain text -#: text/chapter8.md:857 +#: text/chapter8.md:858 #, markdown-text msgid "" "Non-`Record` states can also follow this update pattern. See [this " @@ -23335,7 +23436,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:859 +#: text/chapter8.md:860 #, markdown-text msgid "" "Recall that `useState` is used within an `R.do` block. `R.do` is a special " @@ -23347,7 +23448,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:861 +#: text/chapter8.md:862 #, markdown-text msgid "" "Another possible state management strategy is with `useReducer`, but that is " @@ -23355,13 +23456,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:863 +#: text/chapter8.md:864 #, markdown-text msgid "Rendering `JSX` occurs here:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:864 +#: text/chapter8.md:865 #, no-wrap msgid "" "pure\n" @@ -23400,25 +23501,25 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:896 +#: text/chapter8.md:897 #, markdown-text msgid "" -"Here we produce `JSX` which represents the intended state of the DOM. This " +"Here we produce `JSX`, which represents the intended state of the DOM. This " "JSX is typically created by applying functions corresponding to HTML tags " -"(e.g. `div`, `form`, `h3`, `li`, `ul`, `label`, `input`) which create single " -"HTML elements. These HTML elements are actually React components themselves, " +"(e.g., `div`, `form`, `h3`, `li`, `ul`, `label`, `input`) which create " +"single HTML elements. These HTML elements are React components themselves, " "converted to JSX. There are usually three variants of each of these " "functions:" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:900 +#: text/chapter8.md:901 #, markdown-text msgid "`div_`: Accepts an array of child elements. Uses default attributes." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:900 +#: text/chapter8.md:901 #, markdown-text msgid "" "`div`: Accepts a `Record` of attributes. An array of child elements may be " @@ -23426,7 +23527,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:900 +#: text/chapter8.md:901 #, markdown-text msgid "" "`div'`: Same as `div`, but returns the `ReactComponent` before conversion to " @@ -23434,7 +23535,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:902 +#: text/chapter8.md:903 #, markdown-text msgid "" "To display validation errors (if any) at the top of our form, we create a " @@ -23443,13 +23544,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:903 +#: text/chapter8.md:904 #, no-wrap msgid "{{#include ../exercises/chapter8/src/Main.purs:renderValidationErrors}}\n" msgstr "" #. type: Plain text -#: text/chapter8.md:908 +#: text/chapter8.md:909 #, markdown-text msgid "" "Note that since we are simply manipulating regular data structures here, we " @@ -23457,13 +23558,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:909 +#: text/chapter8.md:910 #, no-wrap msgid "children: [ D.ul_ (map renderError xs)]\n" msgstr "" #. type: Plain text -#: text/chapter8.md:914 +#: text/chapter8.md:915 #, markdown-text msgid "" "We use the `className` property to define classes for CSS styling. We're " @@ -23474,13 +23575,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:915 +#: text/chapter8.md:916 #, no-wrap msgid "className: \"alert alert-danger row\"\n" msgstr "" #. type: Plain text -#: text/chapter8.md:920 +#: text/chapter8.md:921 #, markdown-text msgid "" "A second helper function is `formField`, which creates a text input for a " @@ -23488,13 +23589,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:921 +#: text/chapter8.md:922 #, no-wrap msgid "{{#include ../exercises/chapter8/src/Main.purs:formField}}\n" msgstr "" #. type: Plain text -#: text/chapter8.md:926 +#: text/chapter8.md:927 #, markdown-text msgid "" "Putting the `input` and display `text` in a `label` aids in accessibility " @@ -23502,7 +23603,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:928 +#: text/chapter8.md:929 #, markdown-text msgid "" "The `onChange` attribute allows us to describe how to respond to user " @@ -23510,7 +23611,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:929 +#: text/chapter8.md:930 #, no-wrap msgid "" "handler :: forall a. EventFn SyntheticEvent a -> (a -> Effect Unit) -> " @@ -23518,7 +23619,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:934 +#: text/chapter8.md:935 #, markdown-text msgid "" "For the first argument to `handler` we use `targetValue`, which provides the " @@ -23528,22 +23629,22 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:935 +#: text/chapter8.md:936 #, no-wrap msgid "targetValue :: EventFn SyntheticEvent (Maybe String)\n" msgstr "" #. type: Plain text -#: text/chapter8.md:940 +#: text/chapter8.md:941 #, markdown-text msgid "" -"In JavaScript, the `input` element's `onChange` event is actually " -"accompanied by a `String` value, but since strings in JavaScript can be " -"null, `Maybe` is used for safety." +"In JavaScript, the `input` element's `onChange` event is accompanied by a " +"`String` value, but since strings in JavaScript can be null, `Maybe` is used " +"for safety." msgstr "" #. type: Plain text -#: text/chapter8.md:942 +#: text/chapter8.md:943 #, markdown-text, no-wrap msgid "" "The second argument to `handler`, `(a -> Effect Unit)`, must therefore have " @@ -23551,13 +23652,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:943 +#: text/chapter8.md:944 #, no-wrap msgid "Maybe String -> Effect Unit\n" msgstr "" #. type: Plain text -#: text/chapter8.md:948 +#: text/chapter8.md:949 #, markdown-text msgid "" "It is a function that describes how to convert this `Maybe String` value " @@ -23566,7 +23667,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:949 +#: text/chapter8.md:950 #, no-wrap msgid "" "onChange:\n" @@ -23579,7 +23680,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:960 +#: text/chapter8.md:961 #, markdown-text msgid "" "`setValue` is the function we provided to each `formField` call that takes a " @@ -23587,19 +23688,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:962 +#: text/chapter8.md:963 #, markdown-text msgid "Note that `handleValue` can be substituted as:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:963 +#: text/chapter8.md:964 #, no-wrap msgid "onChange: handler targetValue $ traverse_ setValue\n" msgstr "" #. type: Plain text -#: text/chapter8.md:968 +#: text/chapter8.md:969 #, markdown-text msgid "" "Feel free to investigate the definition of `traverse_` to see how both forms " @@ -23607,16 +23708,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:970 +#: text/chapter8.md:971 #, markdown-text msgid "" "That covers the basics of our component implementation. However, you should " -"read the source accompanying this chapter in order to get a full " -"understanding of the way the component works." +"read the source accompanying this chapter to get a full understanding of the " +"way the component works." msgstr "" #. type: Plain text -#: text/chapter8.md:972 +#: text/chapter8.md:973 #, markdown-text msgid "" "Obviously, this user interface can be improved in a number of ways. The " @@ -23625,7 +23726,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:976 +#: text/chapter8.md:977 #, markdown-text msgid "" "Modify `src/Main.purs` in the following exercises. There are no unit tests " @@ -23633,22 +23734,22 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter8.md:979 +#: text/chapter8.md:980 #, markdown-text msgid "(Easy) Modify the application to include a work phone number text box." msgstr "" #. type: Bullet: '1. ' -#: text/chapter8.md:979 +#: text/chapter8.md:980 #, markdown-text msgid "" -"(Medium) Right now the application shows validation errors collected in a " +"(Medium) Right now, the application shows validation errors collected in a " "single \"pink-alert\" background. Modify to give each validation error its " "own pink-alert background by separating them with blank lines." msgstr "" #. type: Plain text -#: text/chapter8.md:982 +#: text/chapter8.md:983 #, markdown-text, no-wrap msgid "" " _Hint_: Instead of using a `ul` element to show the validation errors in " @@ -23660,16 +23761,16 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:984 +#: text/chapter8.md:985 #, markdown-text, no-wrap msgid "" -" _Hint_: the error type returned by the validator should be extended to " +" _Hint_: The error type returned by the validator should be extended to " "indicate which field caused the error. You might want to use the following " "modified `Errors` type:\n" msgstr "" #. type: Plain text -#: text/chapter8.md:992 +#: text/chapter8.md:993 #, markdown-text, no-wrap msgid "" " ```hs\n" @@ -23682,13 +23783,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:994 +#: text/chapter8.md:995 #, markdown-text, no-wrap msgid " data ValidationError = ValidationError String Field\n" msgstr "" #. type: Plain text -#: text/chapter8.md:997 +#: text/chapter8.md:998 #, markdown-text, no-wrap msgid "" " type Errors = Array ValidationError\n" @@ -23696,15 +23797,15 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:999 +#: text/chapter8.md:1000 #, markdown-text, no-wrap msgid "" -" You will need to write a function which extracts the validation error " -"for a particular `Field` from the `Errors` structure.\n" +" You will need to write a function that extracts the validation error for " +"a particular `Field` from the `Errors` structure.\n" msgstr "" #. type: Plain text -#: text/chapter8.md:1003 +#: text/chapter8.md:1004 #, markdown-text msgid "" "This chapter has covered a lot of ideas about handling side-effects in " @@ -23712,29 +23813,29 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 #, markdown-text -msgid "We met the `Monad` type class, and its connection to do notation." +msgid "We met the `Monad` type class and its connection to do notation." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 #, markdown-text msgid "" -"We introduced the monad laws, and saw how they allow us to transform code " +"We introduced the monad laws and saw how they allow us to transform code " "written using do notation." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 #, markdown-text msgid "" -"We saw how monads can be used abstractly, to write code which works with " +"We saw how monads can be used abstractly to write code that works with " "different side-effects." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 #, markdown-text msgid "" "We saw how monads are examples of applicative functors, how both allow us to " @@ -23742,15 +23843,15 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 #, markdown-text msgid "" "The concept of native effects was defined, and we met the `Effect` monad, " -"which is used to handle native side-effects." +"which handles native side-effects." msgstr "" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 #, markdown-text msgid "" "We used the `Effect` monad to handle a variety of effects: random number " @@ -23759,7 +23860,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter8.md:1011 +#: text/chapter8.md:1012 #, markdown-text msgid "" "The `Effect` monad is a fundamental tool in real-world PureScript code. It " @@ -23780,8 +23881,8 @@ msgid "" "This chapter focuses on the `Aff` monad, which is similar to the `Effect` " "monad, but represents _asynchronous_ side-effects. We'll demonstrate " "examples of asynchronously interacting with the filesystem and making HTTP " -"requests. We'll also cover how to manage sequential and parallel execution " -"of asynchronous effects." +"requests. We'll also cover managing sequential and parallel execution of " +"asynchronous effects." msgstr "" #. type: Plain text @@ -23819,7 +23920,7 @@ msgstr "" #, markdown-text msgid "" "When running outside of the browser (such as in our Node.js environment), " -"the `affjax` library requires the `xhr2` NPM module, which is listed as " +"the `affjax` library requires the `xhr2` NPM module, which is listed as a " "dependency in the `package.json` of this chapter. Install that by running:" msgstr "" @@ -23877,7 +23978,7 @@ msgstr "" #, markdown-text msgid "" "It is also possible to use callbacks or synchronous functions, but those are " -"less desireable because:" +"less desirable because:" msgstr "" #. type: Bullet: '- ' @@ -23928,9 +24029,9 @@ msgstr "" #, markdown-text msgid "" "It is also possible to re-write the above snippet using callbacks or " -"synchronous functions (for example with `Node.FS.Async` and `Node.FS.Sync` " +"synchronous functions (for example, with `Node.FS.Async` and `Node.FS.Sync`, " "respectively), but those share the same downsides as discussed earlier with " -"JavaScript, and so that coding style is not recommended." +"JavaScript, so that coding style is not recommended." msgstr "" #. type: Plain text @@ -23938,7 +24039,7 @@ msgstr "" #, markdown-text msgid "" "The syntax for working with `Aff` is very similar to working with " -"`Effect`. They are both monads, and can therefore be written with do " +"`Effect`. They are both monads and can therefore be written with do " "notation." msgstr "" @@ -24009,9 +24110,7 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter9.md:90 #, markdown-text -msgid "" -"(Easy) Write a `concatenateFiles` function which concatenates two text " -"files." +msgid "(Easy) Write a `concatenateFiles` function that concatenates two text files." msgstr "" #. type: Bullet: ' 1. ' @@ -24019,8 +24118,8 @@ msgstr "" #, markdown-text msgid "" "(Medium) Write a function `concatenateMany` to concatenate multiple text " -"files, given an array of input file names and an output file name. _Hint_: " -"use `traverse`." +"files, given an array of input and output file names. _Hint_: use " +"`traverse`." msgstr "" #. type: Bullet: ' 1. ' @@ -24042,7 +24141,7 @@ msgstr "" #: text/chapter9.md:98 #, markdown-text msgid "" -"If you haven't already taken a look at the [official Aff " +"If you haven't already looked at the [official Aff " "guide](https://pursuit.purescript.org/packages/purescript-aff/), skim " "through that now. It's not a direct prerequisite for completing the " "remaining exercises in this chapter, but you may find it helpful to lookup " @@ -24078,30 +24177,37 @@ msgid "A HTTP Client" msgstr "" #. type: Plain text -#: text/chapter9.md:109 +#: text/chapter9.md:107 #, markdown-text msgid "" "The `affjax` library offers a convenient way to make asynchronous AJAX HTTP " -"requests with `Aff`. Depending on what environment you are targeting you " +"requests with `Aff`. Depending on what environment you are targeting, you " "need to use either the " "[purescript-affjax-web](https://github.com/purescript-contrib/purescript-affjax-web) " "or the " "[purescript-affjax-node](https://github.com/purescript-contrib/purescript-affjax-node) " -"library. In the rest of this chapter we will be targeting node and thus " -"using `purescript-affjax-node`. Consult the [Affjax " +"library." +msgstr "" + +#. type: Plain text +#: text/chapter9.md:110 +#, markdown-text +msgid "" +"In the rest of this chapter, we will be targeting node and thus using " +"`purescript-affjax-node`. Consult the [Affjax " "docs](https://pursuit.purescript.org/packages/purescript-affjax) for more " "usage information. Here is an example that makes HTTP GET requests at a " "provided URL and returns the response body or an error message:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter9.md:110 +#: text/chapter9.md:111 #, no-wrap msgid "{{#include ../exercises/chapter9/test/HTTP.purs:getUrl}}\n" msgstr "" #. type: Plain text -#: text/chapter9.md:115 +#: text/chapter9.md:116 #, markdown-text msgid "" "When calling this in the repl, `launchAff_` is required to convert the `Aff` " @@ -24109,7 +24215,7 @@ msgid "" msgstr "" #. type: Fenced code block (shell) -#: text/chapter9.md:116 +#: text/chapter9.md:117 #, no-wrap msgid "" "$ spago repl\n" @@ -24130,7 +24236,7 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter9.md:136 +#: text/chapter9.md:137 #, markdown-text msgid "" "(Easy) Write a function `writeGet` which makes an HTTP `GET` request to a " @@ -24138,13 +24244,13 @@ msgid "" msgstr "" #. type: Title ## -#: text/chapter9.md:137 +#: text/chapter9.md:138 #, markdown-text, no-wrap msgid "Parallel Computations" msgstr "" #. type: Plain text -#: text/chapter9.md:140 +#: text/chapter9.md:141 #, markdown-text msgid "" "We've seen how to use the `Aff` monad and do notation to compose " @@ -24154,19 +24260,19 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:142 +#: text/chapter9.md:143 #, markdown-text msgid "" -"The `parallel` package defines a type class `Parallel` for monads like `Aff` " -"which support parallel execution. When we met applicative functors earlier " -"in the book, we observed how applicative functors can be useful for " +"The `parallel` package defines a type class `Parallel` for monads like " +"`Aff`, which support parallel execution. When we met applicative functors " +"earlier in the book, we observed how applicative functors can be useful for " "combining parallel computations. In fact, an instance for `Parallel` defines " "a correspondence between a monad `m` (such as `Aff`) and an applicative " -"functor `f` which can be used to combine computations in parallel:" +"functor `f` that can be used to combine computations in parallel:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter9.md:143 +#: text/chapter9.md:144 #, no-wrap msgid "" "class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where\n" @@ -24175,13 +24281,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:150 +#: text/chapter9.md:151 #, markdown-text msgid "The class defines two functions:" msgstr "" #. type: Bullet: '- ' -#: text/chapter9.md:153 +#: text/chapter9.md:154 #, markdown-text msgid "" "`parallel`, which takes computations in the monad `m` and turns them into " @@ -24189,24 +24295,24 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter9.md:153 +#: text/chapter9.md:154 #, markdown-text msgid "`sequential`, which performs a conversion in the opposite direction." msgstr "" #. type: Plain text -#: text/chapter9.md:155 +#: text/chapter9.md:156 #, markdown-text msgid "" "The `aff` library provides a `Parallel` instance for the `Aff` monad. It " -"uses mutable references to combine `Aff` actions in parallel, by keeping " +"uses mutable references to combine `Aff` actions in parallel by keeping " "track of which of the two continuations has been called. When both results " "have been returned, we can compute the final result and pass it to the main " "continuation." msgstr "" #. type: Plain text -#: text/chapter9.md:157 +#: text/chapter9.md:158 #, markdown-text msgid "" "Because applicative functors support lifting of functions of arbitrary " @@ -24216,17 +24322,17 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:159 +#: text/chapter9.md:160 #, markdown-text msgid "" -"We can also combine parallel computations with sequential portions of code, " +"We can also combine parallel computations with sequential portions of code " "by using applicative combinators in a do notation block, or vice versa, " "using `parallel` and `sequential` to change type constructors where " "appropriate." msgstr "" #. type: Plain text -#: text/chapter9.md:163 +#: text/chapter9.md:164 #, markdown-text msgid "" "To demonstrate the difference between sequential and parallel execution, " @@ -24237,13 +24343,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter9.md:164 +#: text/chapter9.md:165 #, no-wrap msgid "{{#include ../exercises/chapter9/test/ParallelDelay.purs:delays}}\n" msgstr "" #. type: Fenced code block (shell) -#: text/chapter9.md:168 +#: text/chapter9.md:169 #, no-wrap msgid "" "$ spago repl\n" @@ -24258,7 +24364,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:181 +#: text/chapter9.md:182 #, markdown-text msgid "" "Here's a more real-world example of making multiple HTTP requests in " @@ -24269,13 +24375,13 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter9.md:182 +#: text/chapter9.md:183 #, no-wrap msgid "{{#include ../exercises/chapter9/test/ParallelFetch.purs:fetchPar}}\n" msgstr "" #. type: Fenced code block (shell) -#: text/chapter9.md:186 +#: text/chapter9.md:187 #, no-wrap msgid "" "$ spago repl\n" @@ -24292,7 +24398,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:199 +#: text/chapter9.md:200 #, markdown-text msgid "" "A full listing of available parallel functions can be found in the " @@ -24304,16 +24410,16 @@ msgid "" msgstr "" #. type: Bullet: '1. ' -#: text/chapter9.md:203 +#: text/chapter9.md:204 #, markdown-text msgid "" -"(Easy) Write a `concatenateManyParallel` function which has the same " -"signature as the earlier `concatenateMany` function, but reads all input " -"files in parallel." +"(Easy) Write a `concatenateManyParallel` function with the same signature as " +"the earlier `concatenateMany` function but reads all input files in " +"parallel." msgstr "" #. type: Bullet: '1. ' -#: text/chapter9.md:207 +#: text/chapter9.md:208 #, markdown-text msgid "" "(Medium) Write a `getWithTimeout :: Number -> String -> Aff (Maybe String)` " @@ -24322,7 +24428,7 @@ msgid "" msgstr "" #. type: Bullet: ' - ' -#: text/chapter9.md:207 +#: text/chapter9.md:208 #, markdown-text msgid "" "`Nothing`: if the request takes longer than the provided timeout (in " @@ -24330,16 +24436,16 @@ msgid "" msgstr "" #. type: Bullet: ' - ' -#: text/chapter9.md:207 +#: text/chapter9.md:208 #, markdown-text msgid "The string response: if the request succeeds before the timeout elapses." msgstr "" #. type: Bullet: '1. ' -#: text/chapter9.md:209 +#: text/chapter9.md:210 #, markdown-text msgid "" -"(Difficult) Write a `recurseFiles` function which takes a \"root\" file and " +"(Difficult) Write a `recurseFiles` function that takes a \"root\" file and " "returns an array of all paths listed in that file (and listed in the listed " "files too). Read listed files in parallel. Paths are relative to the " "directory of the file they appear in. _Hint:_ The `node-path` module has " @@ -24347,13 +24453,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:211 +#: text/chapter9.md:212 #, markdown-text msgid "For example, if starting from the following `root.txt` file:" msgstr "" #. type: Fenced code block (shell) -#: text/chapter9.md:212 +#: text/chapter9.md:213 #, no-wrap msgid "" "$ cat root.txt\n" @@ -24375,37 +24481,84 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter9.md:232 +#: text/chapter9.md:233 #, markdown-text msgid "The expected output is:" msgstr "" #. type: Fenced code block (hs) -#: text/chapter9.md:233 +#: text/chapter9.md:234 #, no-wrap msgid "[\"root.txt\",\"a.txt\",\"b/a.txt\",\"b/b.txt\",\"b/c/a.txt\",\"c/a/a.txt\"]\n" msgstr "" #. type: Plain text -#: text/chapter9.md:240 +#: text/chapter9.md:241 #, markdown-text -msgid "In this chapter we covered asynchronous effects and learned how to:" +msgid "In this chapter, we covered asynchronous effects and learned how to:" msgstr "" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 #, markdown-text msgid "Run asynchronous code in the `Aff` monad with the `aff` library." msgstr "" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 #, markdown-text msgid "Make HTTP requests asynchronously with the `affjax` library." msgstr "" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 #, markdown-text msgid "Run asynchronous code in parallel with the `parallel` library." msgstr "" + +#. type: Title # +#: CONTRIBUTING.md:1 +#, markdown-text, no-wrap +msgid "Contributing" +msgstr "" + +#. type: Plain text +#: CONTRIBUTING.md:4 +#, markdown-text +msgid "Please open PRs or Issues if you find anything to improve in the book." +msgstr "" + +#. type: Plain text +#: CONTRIBUTING.md:6 +#, markdown-text +msgid "We appreciate your feedback." +msgstr "" + +#. type: Title ## +#: CONTRIBUTING.md:7 +#, markdown-text, no-wrap +msgid "Editing chapter text" +msgstr "" + +#. type: Plain text +#: CONTRIBUTING.md:10 +#, markdown-text +msgid "" +"To test changes to the text locally, install " +"[mdbook](https://github.com/rust-lang/mdBook), then run this command from " +"repo root:" +msgstr "" + +#. type: Fenced code block (sh) +#: CONTRIBUTING.md:11 +#, no-wrap +msgid "mdbook serve -o\n" +msgstr "" + +#. type: Plain text +#: CONTRIBUTING.md:15 +#, markdown-text +msgid "" +"The rendered webpage will automatically refresh with any changes to readme " +"files." +msgstr "" diff --git a/translation/ja.po b/translation/ja.po index 8774a4a8..6ca0f625 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -15,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" -"POT-Creation-Date: 2023-06-22 08:06+0900\n" -"PO-Revision-Date: 2023-06-22 08:18+0900\n" +"POT-Creation-Date: 2023-08-25 21:33+0900\n" +"PO-Revision-Date: 2023-08-25 21:37+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -154,9 +154,9 @@ msgid "" "to share, even if it's as simple as pointing out a confusing section that we " "could make more beginner-friendly." msgstr "" -"この本は言語の進化に伴って継続的に更新されているため、内容に関して発見したど" -"んな[問題](https://github.com/purescript-contrib/purescript-book/issues)でも" -"ご報告ください。\n" +"本書は言語の進化に伴って継続的に更新されているため、内容に関して発見したどん" +"な[問題](https://github.com/purescript-contrib/purescript-book/issues)でもご" +"報告ください。\n" "より初心者にやさしくできそうな分かりづらい節を指摘するような単純なものであ" "れ、共有いただいたどんなフィードバックにも感謝します。" @@ -167,8 +167,8 @@ msgid "" "answers to the exercises are correct. See [#79](https://github.com/" "purescript-contrib/purescript-book/issues/79) for the latest status on tests." msgstr "" -"それぞれの章には単体テストも加えられているので、演習への自分の回答が正しいか" -"どうか確かめることができます。\n" +"各章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確" +"かめることができます。\n" "テストの最新の状態については[#79](https://github.com/purescript-contrib/" "purescript-book/issues/79)を見てください。" @@ -212,8 +212,8 @@ msgid "" "language, from the basics (setting up a development environment) to the " "advanced." msgstr "" -"この本は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラ" -"ミング言語の始め方を示します。" +"本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミ" +"ング言語の始め方を示します。" #. type: Plain text #: README.md:22 @@ -223,9 +223,9 @@ msgid "" "be introduced. Here are some examples of problems that will be solved in " "this book:" msgstr "" -"それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程に" -"おいて、新しい関数型プログラミングの道具と技法が導入されていきます。\n" -"以下はこの本で解いていく課題の幾つかの例です。" +"各章は特定の課題により動機付けられており、その問題を解いていく過程において、" +"新しい関数型プログラミングの道具と技法が導入されていきます。\n" +"以下は本書で解いていく課題の幾つかの例です。" #. type: Bullet: '- ' #: README.md:31 @@ -287,12 +287,7 @@ msgid "" msgstr "" "The text of this book is licensed under the Creative Commons Attribution-" "NonCommercial-ShareAlike 3.0 Unported License: .\n" -"\n" -"※以降の原文の使用許諾に関する和訳は法的効力を持ちません。
\n" -"本書のテキストは表示 - 非営利 - 継承3.0非移植 (CC BY-NC-SA 3.0)のもとに使用が許" -"諾される。
" +"licenses/by-nc-sa/3.0/deed.en_US>." #. type: Plain text #: README.md:39 @@ -305,21 +300,12 @@ msgstr "" "Some text is derived from the [PureScript Documentation Repo](https://github." "com/purescript/documentation), which uses the same license, and is copyright " "[various contributors](https://github.com/purescript/documentation/blob/" -"master/CONTRIBUTORS.md).\n" -"\n" -"幾つかのテキストは[PureScriptのドキュメントリポジトリ](https://github." -"com/purescript/documentation)から派生している。\n" -"派生元も同じ使用許諾であり、[様々な形で貢献された方々](https://github.com/" -"purescript/documentation/blob/master/CONTRIBUTORS.md)の著作権が含まれる。" +"master/CONTRIBUTORS.md)." #. type: Plain text #: README.md:40 msgid "The exercises are licensed under the MIT license." -msgstr "" -"The exercises are licensed under the MIT license.\n" -"\n" -"演習はMITライセンスの下に使用が許諾される。" +msgstr "The exercises are licensed under the MIT license." #. type: Title ## #: text/chapter1.md:1 text/chapter4.md:23 @@ -346,7 +332,7 @@ msgstr "" #: text/chapter1.md:8 msgid "" "Libraries such as [UnderscoreJS](https://underscorejs.org) allow the " -"developer to leverage tried-and-trusted functions such as `map`, `filter` " +"developer to leverage tried-and-trusted functions such as `map`, `filter`, " "and `reduce` to create larger programs from smaller programs by composition:" msgstr "" "[UnderscoreJS](https://underscorejs.org)などのライブラリがあれば、開発者は" @@ -436,92 +422,102 @@ msgstr "" #. type: Plain text #: text/chapter1.md:38 msgid "" -"Functions enable a simple form of abstraction which can yield great " -"productivity gains. However, functional programming in JavaScript has its " -"own disadvantages: JavaScript is verbose, untyped, and lacks powerful forms " -"of abstraction. Unrestricted JavaScript code also makes equational reasoning " +"Functions enable a simple form of abstraction that can yield great " +"productivity gains. However, functional programming in JavaScript has " +"disadvantages: JavaScript is verbose, untyped, and lacks powerful forms of " +"abstraction. Unrestricted JavaScript code also makes equational reasoning " "very difficult." msgstr "" -"関数は単純な抽象化を可能にし、優れた生産性をもたらしてくれます。\n" +"関数は大幅な生産性の向上をもたらしうる単純な抽象化を可能にします。\n" "しかし、JavaScriptでの関数型プログラミングには欠点があります。\n" -"JavaScriptは冗長で、型付けされず、強力な抽象化を欠いているのです。\n" -"また、無秩序に書かれたJavaScriptコードでは、等式推論がとても困難です。" +"JavaScriptは冗長で、型付けされず、強力な抽象化の形式を欠いているのです。\n" +"また、野放図なJavaScriptコードは等式推論がとても困難です。" #. type: Plain text #: text/chapter1.md:40 msgid "" -"PureScript is a programming language which aims to address these issues. It " +"PureScript is a programming language that aims to address these issues. It " "features lightweight syntax, which allows us to write very expressive code " "which is still clear and readable. It uses a rich type system to support " "powerful abstractions. It also generates fast, understandable code, which is " -"important when interoperating with JavaScript, or other languages which " +"important when interoperating with JavaScript or other languages that " "compile to JavaScript. All in all, I hope to convince you that PureScript " "strikes a very practical balance between the theoretical power of purely " -"functional programming, and the fast-and-loose programming style of " +"functional programming and the fast-and-loose programming style of " "JavaScript." msgstr "" -"PureScriptはこのような問題を解決すべく作られたプログラミング言語です。\n" -"PureScriptは、とても表現力豊かでありながらわかりやすく読みやすいコードを書け" -"るようにする、軽量な構文を備えています。\n" -"強力な抽象化を提供する豊かな型システムも採用しています。\n" +"PureScriptはこうした課題への対処を目指すプログラミング言語です。\n" +"PureScriptは軽量な構文を備えていますが、この構文によりとても表現力豊かであり" +"ながら分かりやすく読みやすいコードが書けるのです。\n" +"強力な抽象化を支援する豊かな型システムも採用しています。\n" "また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに" "重要な、高速で理解しやすいコードを生成します。\n" -"PureScriptを一言で言えば、純粋関数型プログラミングの理論的な強力さと、" -"JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを" -"狙った言語だということを理解して頂けたらと思います。" +"概してPureScriptとは、純粋関数型プログラミングの理論的な強力さと、JavaScript" +"のお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語" +"だということを理解して頂けたらと思います。" + +#. type: Plain text +#: text/chapter1.md:42 +#, no-wrap +msgid "> Note that PureScript can target other backends, not only JavaScript, but this book focuses on targeting web browser and node environments.\n" +msgstr "> なお、PureScriptはJavaScriptのみならず他のバックエンドを対象にできますが、本書ではwebブラウザとnode環境に焦点を絞ります。\n" #. type: Title ## -#: text/chapter1.md:41 +#: text/chapter1.md:43 #, no-wrap msgid "Types and Type Inference" msgstr "型と型推論" #. type: Plain text -#: text/chapter1.md:44 +#: text/chapter1.md:46 msgid "" "The debate over statically typed languages versus dynamically typed " "languages is well-documented. PureScript is a _statically typed_ language, " -"meaning that a correct program can be given a _type_ by the compiler which " -"indicates its behavior. Conversely, programs which cannot be given a type " -"are _incorrect programs_, and will be rejected by the compiler. In " -"PureScript, unlike in dynamically typed languages, types exist only at " -"_compile-time_, and have no representation at runtime." +"meaning that a correct program can be given a _type_ by the compiler, which " +"indicates its behavior. Conversely, programs that cannot be given a type are " +"_incorrect programs_, and will be rejected by the compiler. In PureScript, " +"unlike in dynamically typed languages, types exist only at _compile-time_ " +"and have no representation at runtime." msgstr "" -"動的型付けの言語と静的型付けの言語をめぐる議論についてはよく知られています。" -"PureScriptは*静的型付け*の言語、つまり正しいプログラムはコンパイラによってそ" -"の動作を示すような*型*を与えられる言語です。逆にいえば、型を与えることができ" -"ないプログラムは _誤ったプログラム_ であり、コンパイラによって拒否されます。" -"動的型付けの言語とは異なり、PureScriptでは型は*コンパイル時*のみに存在し、実" -"行時には型の表現はありません。" +"動的型付けの言語と静的型付けの言語をめぐる議論については充分に文書化されてい" +"ます。\n" +"PureScriptは*静的型付け*の言語、つまり正しいプログラムはコンパイラによって*型" +"*を与えられる言語です。\n" +"またこの型は、その動作を示すものです。\n" +"逆に言えば、型を与えることができないプログラムは*誤ったプログラム*であり、コ" +"ンパイラによって拒否されます。\n" +"動的型付けの言語とは異なり、PureScriptでは型は*コンパイル時*にのみ存在し、実" +"行時には一切その表現がありません。" #. type: Plain text -#: text/chapter1.md:46 +#: text/chapter1.md:48 msgid "" -"It is important to note that in many ways, the types in PureScript are " +"It is important to note that, in many ways, the types in PureScript are " "unlike the types that you might have seen in other languages like Java or " "C#. While they serve the same purpose at a high level, the types in " "PureScript are inspired by languages like ML and Haskell. PureScript's types " "are expressive, allowing the developer to assert strong claims about their " "programs. Most importantly, PureScript's type system supports _type " -"inference_ - it requires far fewer explicit type annotations than other " +"inference_ – it requires far fewer explicit type annotations than other " "languages, making the type system a _tool_ rather than a hindrance. As a " "simple example, the following code defines a _number_, but there is no " "mention of the `Number` type anywhere in the code:" msgstr "" -"PureScriptの型は、これまでJavaやC#のような他の言語で見たような型とは、いろい" -"ろな意味で異なっていることにも注意することが大切です。\n" -"おおまかに言えばPureScriptの型はJavaやC#と同じ目的を持っているものの、" +"多くの点で、PureScriptの型とこれまでJavaやC#のような他の言語で見てきたであろ" +"う型が異なっていることにも、注意することが大切です。\n" +"大まかに言えばPureScriptの型はJavaやC#と同じ目的を持っているものの、" "PureScriptの型はMLやHaskellのような言語に影響を受けています。\n" -"開発者がプログラムについての強い主張を表明できるので、PureScriptの型は表現力" -"豊かなのです。\n" -"最も重要なのは、PureScriptの型システムは*型推論*に対応していることです。\n" -"型推論があれば他の言語より遥かに少ない型注釈で済み、型システムを厄介者ではな" -"く*道具*にしてくれます。\n" -"簡単な例を示すと、次のコードは*数*を定義していますが、それが `Number`型だとい" -"う注釈はコードのどこにもありません。" +"PureScriptの型は表現力豊かであり、開発者はプログラムについての強い主張を表明" +"できます。\n" +"最も重要なのはPureScriptの型システムが*型推論*に対応していることです。\n" +"型推論があれば他の言語より明示的な型注釈が遥かに少なく済み、型システムを厄介" +"者ではなく*道具*にしてくれます。\n" +"単純な一例として、次のコードは*数*を定義していますが、`Number`型への言及は" +"コードのどこにもありません。" #. type: Fenced code block (haskell) -#: text/chapter1.md:47 +#: text/chapter1.md:49 #, no-wrap msgid "" "iAmANumber =\n" @@ -533,18 +529,17 @@ msgstr "" " in square 42.0\n" #. type: Plain text -#: text/chapter1.md:54 +#: text/chapter1.md:56 msgid "" "A more involved example shows that type-correctness can be confirmed without " -"type annotations, even when there exist types which are _unknown to the " +"type annotations, even when there exist types that are _unknown to the " "compiler_:" msgstr "" -"次のもっと複雑な例では、 _コンパイラにとって未知_ の型が存在しているときでさ" -"えも、型注釈なしで型の正しさを確かめることができるということが示されていま" -"す。" +"より込み入った次の例では、*コンパイラにとって未知*の型が存在します。\n" +"それでも、型注釈なく型の正しさを確かめられていることを示しています。" #. type: Fenced code block (haskell) -#: text/chapter1.md:55 +#: text/chapter1.md:57 #, no-wrap msgid "" "iterate f 0 x = x\n" @@ -554,7 +549,7 @@ msgstr "" "iterate f n x = iterate f (n - 1) (f x)\n" #. type: Plain text -#: text/chapter1.md:61 +#: text/chapter1.md:63 msgid "" "Here, the type of `x` is unknown, but the compiler can still verify that " "`iterate` obeys the rules of the type system, no matter what type `x` might " @@ -564,7 +559,7 @@ msgstr "" "`iterate`が型システムの規則に従っていることをコンパイラは検証できます。" #. type: Plain text -#: text/chapter1.md:63 +#: text/chapter1.md:65 msgid "" "In this book, I will try to convince you (or reaffirm your belief) that " "static types are not only a means of gaining confidence in the correctness " @@ -582,38 +577,38 @@ msgstr "" "ングさえ楽しく対話的な体験にしてくれます。" #. type: Plain text -#: text/chapter1.md:65 +#: text/chapter1.md:67 msgid "" "In addition, the safety net provided by a type system enables more advanced " "forms of abstraction. In fact, PureScript provides a powerful form of " -"abstraction which is fundamentally type-driven: type classes, made popular " -"in the functional programming language Haskell." +"abstraction that is fundamentally type-driven: type classes, made popular in " +"the functional programming language Haskell." msgstr "" -"加えて、型システムによって提供されるこの安全網は、より高度な抽象化をも可能に" -"します。\n" -"実際に、関数型プログラミング言語Haskellによって知られるようになった、型駆動の" -"強力な抽象化の形式である『型クラス』をPureScriptは備えています。" +"加えて、型システムによって提供されるこの安全網は、より高度な抽象化を可能にし" +"ます。\n" +"実際に、根本的に型駆動な抽象化の強力な形式である型クラスをPureScriptは提供し" +"ています。\n" +"この型クラスとは、関数型プログラミング言語Haskellによって有名になりました。" #. type: Title ## -#: text/chapter1.md:66 +#: text/chapter1.md:68 #, no-wrap msgid "Polyglot Web Programming" -msgstr "多言語Webプログラミング" +msgstr "多言語webプログラミング" #. type: Plain text -#: text/chapter1.md:69 +#: text/chapter1.md:71 msgid "" -"Functional programming has its success stories - applications where it has " +"Functional programming has its success stories – applications where it has " "been particularly successful: data analysis, parsing, compiler " "implementation, generic programming, parallelism, to name a few." msgstr "" -"関数型プログラミングは既に多くの成功を収めています。\n" -"枚挙に暇がありませんが、特に成功している応用例を幾つか挙げると、データ解析、" -"構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理などがありま" -"す。" +"関数型プログラミングは成功を収めてきました。\n" +"特に成功している応用例を挙げると、データ解析、構文解析、コンパイラの実装、" +"ジェネリックプログラミング、並列処理といった具合に、枚挙に暇がありません。" #. type: Plain text -#: text/chapter1.md:71 +#: text/chapter1.md:73 msgid "" "It would be possible to practice end-to-end application development in a " "functional language like PureScript. PureScript provides the ability to " @@ -629,25 +624,25 @@ msgstr "" "この手法については本書の後半で見ていくことになります。" #. type: Plain text -#: text/chapter1.md:73 +#: text/chapter1.md:75 msgid "" "However, one of PureScript's strengths is its interoperability with other " "languages which target JavaScript. Another approach would be to use " -"PureScript for a subset of your application's development, and to use one or " +"PureScript for a subset of your application's development and to use one or " "more other languages to write the rest of the JavaScript." msgstr "" "しかし、PureScriptの強みの1つは、JavaScriptを対象とする他の言語との相互運用性" "にあります。\n" "アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分" -"を記述するのに他の言語を使用するという方法もあります。" +"を記述するのに1つ以上の他の言語を使用するという方法もあります。" #. type: Plain text -#: text/chapter1.md:75 +#: text/chapter1.md:77 msgid "Here are some examples:" msgstr "幾つかの例を示します。" #. type: Bullet: '- ' -#: text/chapter1.md:79 +#: text/chapter1.md:81 msgid "" "Core logic written in PureScript, with the user interface written in " "JavaScript." @@ -656,7 +651,7 @@ msgstr "" "述する" #. type: Bullet: '- ' -#: text/chapter1.md:79 +#: text/chapter1.md:81 msgid "" "Application written in JavaScript or another compile-to-JS language, with " "tests written in PureScript." @@ -665,7 +660,7 @@ msgstr "" "PureScriptでそのテストを書く" #. type: Bullet: '- ' -#: text/chapter1.md:79 +#: text/chapter1.md:81 msgid "" "PureScript used to automate user interface tests for an existing application." msgstr "" @@ -673,50 +668,51 @@ msgstr "" "PureScriptを使用する" #. type: Plain text -#: text/chapter1.md:81 +#: text/chapter1.md:83 msgid "" "In this book, we'll focus on solving small problems with PureScript. The " "solutions could be integrated into a larger application, but we will also " "look at how to call PureScript code from JavaScript, and vice versa." msgstr "" -"この本では小規模な課題をPureScriptで解決することに焦点を当てます。\n" +"本書では小規模な課題をPureScriptで解決することに焦点を当てます。\n" "ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、" "JavaScriptからPureScriptコードを呼び出す方法、及びその逆についても見ていきま" "す。" #. type: Title ## -#: text/chapter1.md:82 +#: text/chapter1.md:84 #, no-wrap msgid "Prerequisites" msgstr "ソフトウェア要件" #. type: Plain text -#: text/chapter1.md:85 +#: text/chapter1.md:87 msgid "" "The software requirements for this book are minimal: the first chapter will " "guide you through setting up a development environment from scratch, and the " "tools we will use are available in the standard repositories of most modern " "operating systems." msgstr "" -"この本でのソフトウェア要件は最小限です。\n" +"本書のソフトウェア要件は最小限です。\n" "第1章では開発環境の構築を一から案内します。\n" "これから使用するツールは、ほとんどの現代のオペレーティングシステムの標準リポ" "ジトリで使用できるものです。" #. type: Plain text -#: text/chapter1.md:87 +#: text/chapter1.md:89 msgid "" -"The PureScript compiler itself can be downloaded as a binary distribution, " -"or built from source on any system running an up-to-date installation of the " +"The PureScript compiler itself can be downloaded as a binary distribution or " +"built from source on any system running an up-to-date installation of the " "GHC Haskell compiler, and we will walk through this process in the next " "chapter." msgstr "" -"PureScriptコンパイラ自体はバイナリ形式でもダウンロードできますし、最新の" -"Haskellコンパイラが動くシステム上でソースからもビルドできます。\n" -"次の章ではこの手順を説明していきます。" +"PureScriptコンパイラ自体はバイナリの配布物としてもダウンロードできますし、最" +"新のGHC Haskellコンパイラが動く任意のシステム上でソースからのビルドもできま" +"す。\n" +"次の章ではこの手順を進めていきます。" #. type: Plain text -#: text/chapter1.md:90 +#: text/chapter1.md:92 msgid "" "The code in this version of the book is compatible with versions `0.15.*` of " "the PureScript compiler." @@ -725,13 +721,13 @@ msgstr "" "性があります。" #. type: Title ## -#: text/chapter1.md:91 +#: text/chapter1.md:93 #, no-wrap msgid "About You" msgstr "読者について" #. type: Plain text -#: text/chapter1.md:94 +#: text/chapter1.md:96 msgid "" "I will assume that you are familiar with the basics of JavaScript. Any prior " "familiarity with common tools from the JavaScript ecosystem, such as NPM and " @@ -744,23 +740,23 @@ msgstr "" "ですがそのような知識は必要ありません。" #. type: Plain text -#: text/chapter1.md:96 +#: text/chapter1.md:98 msgid "" "No prior knowledge of functional programming is required, but it certainly " "won't hurt. New ideas will be accompanied by practical examples, so you " -"should be able to form an intuition for the concepts from functional " +"should be able to form an intuition for the concepts from the functional " "programming that we will use." msgstr "" -"関数型プログラミングの予備知識は必要ありませんが、あっても害にはならないで" -"しょう。\n" -"新しい考えかたは実例とともに登場するので、これから使う関数型プログラミングか" -"らこうした概念に対する直感的な理解を得ることができるはずです。" +"関数型プログラミングの事前知識は必要ありませんが、あっても決して害にはならな" +"いでしょう。\n" +"新しい考えかたは実例と共に登場するため、これから使っていく関数型プログラミン" +"グからこうした概念に対する直感が形成されることでしょう。" #. type: Plain text -#: text/chapter1.md:98 +#: text/chapter1.md:100 msgid "" "Readers who are familiar with the Haskell programming language will " -"recognize a lot of the ideas and syntax presented in this book, because " +"recognize a lot of the ideas and syntax presented in this book because " "PureScript is heavily influenced by Haskell. However, those readers should " "understand that there are a number of important differences between " "PureScript and Haskell. It is not necessarily always appropriate to try to " @@ -768,24 +764,23 @@ msgid "" "presented here will have some interpretation in Haskell." msgstr "" "PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通" -"じている読者はこの本の中で提示された概念や構文の多くに見覚えがあるでしょ" -"う。\n" -"しかし、読者はPureScriptとHaskellの間には幾らか重要な違いがあることも理解して" -"おかなければなりません。\n" +"じている読者は本書で提示された概念や構文の多くに見覚えがあるでしょう。\n" +"しかし、PureScriptとHaskellの間には数多くの重要な違いがあることも理解しておく" +"と良いでしょう。\n" "ここで紹介する概念の多くはHaskellでも同じように解釈できるとはいえ、どちらかの" "言語での考え方を他方の言語でそのまま応用しようとすることは、必ずしも適切では" "ありません。" #. type: Title ## -#: text/chapter1.md:99 +#: text/chapter1.md:101 #, no-wrap msgid "How to Read This Book" msgstr "本書の読み進めかた" #. type: Plain text -#: text/chapter1.md:102 +#: text/chapter1.md:104 msgid "" -"The chapters in this book are largely self contained. A beginner with little " +"The chapters in this book are largely self-contained. A beginner with little " "functional programming experience would be well-advised, however, to work " "through the chapters in order. The first few chapters lay the groundwork " "required to understand the material later on in the book. A reader who is " @@ -794,19 +789,19 @@ msgid "" "able to gain a general understanding of the code in the later chapters of " "the book without reading the preceding chapters." msgstr "" -"本書の各章は、概ね章ごとに完結しています。\n" -"しかし、多少の関数型プログラミングの経験がある初心者でも、まずは各章を順番に" -"進めていくことをお勧めします。\n" -"最初の数章では、本書の後半の内容を理解するために必要な基礎知識を養います。\n" +"本書のほとんどの章が各章毎に完結しています。\n" +"しかし、関数型プログラミングの経験がほとんどない初心者の方は、各章を順番に進" +"めていくのが賢明です。\n" +"最初の数章は本書の後半の内容を理解するのに必要な下地作りです。\n" "関数型プログラミングの考え方に充分通じた読者(特にMLやHaskellのような強く型付" "けされた言語での経験を持つ読者)なら、本書の前半の章を読まなくても、後半の章" "のコードの大まかな理解を得ることが恐らく可能でしょう。" #. type: Plain text -#: text/chapter1.md:104 +#: text/chapter1.md:106 msgid "" "Each chapter will focus on a single practical example, providing the " -"motivation for any new ideas introduced. Code for each chapter are available " +"motivation for any new ideas introduced. Code for each chapter is available " "from the book's [GitHub repository](https://github.com/purescript-contrib/" "purescript-book). Some chapters will include code snippets taken from the " "chapter's source code, but for a full understanding, you should read the " @@ -814,21 +809,22 @@ msgid "" "sections will contain shorter snippets which you can execute in the " "interactive mode PSCi to test your understanding." msgstr "" -"各章ではそれぞれ1つの実用的な例に焦点をあて、新しい考え方を導入するための動機" -"付けとして用います。各章のコードは本書の[GitHubのリポジトリ](https://github." -"com/purescript-contrib/purescript-book)から入手できます。ソースコードから抜粋" -"したコード片が掲載されている章もありますが、完全に理解するためには本書に掲載" -"されたコードと平行してリポジトリのソースコードを読む必要があります。対話式環" -"境PSCiで実行し理解を確かめられるように、長めの節には短いコード片が掲載されて" -"いることがあります。" +"各章では1つの実用的な例に焦点を当て、新しい考え方を導入するための動機を与えま" +"す。\n" +"各章のコードは本書の[GitHubのリポジトリ](https://github.com/purescript-" +"contrib/purescript-book)から入手できます。\n" +"該当の章のソースコードから抜粋したコード片が含まれる章もありますが、本書の内" +"容に沿ってリポジトリのソースコードを読まれると良いでしょう。\n" +"長めの節には、理解を確かめられるように対話式モードのPSCiで実行できる短めの" +"コード片が含まれます。" #. type: Plain text -#: text/chapter1.md:106 -msgid "Code samples will appear in a monospaced font, as follows:" -msgstr "コード例は次のように等幅フォントで示されています。" +#: text/chapter1.md:108 +msgid "Code samples will appear in a monospaced font as follows:" +msgstr "コード例は次のように等幅フォントで示されます。" #. type: Fenced code block (haskell) -#: text/chapter1.md:107 +#: text/chapter1.md:109 #, no-wrap msgid "" "module Example where\n" @@ -844,31 +840,32 @@ msgstr "" "main = log \"Hello, World!\"\n" #. type: Plain text -#: text/chapter1.md:116 +#: text/chapter1.md:118 msgid "" "Commands which should be typed at the command line will be preceded by a " "dollar symbol:" msgstr "先頭にドル記号がついた行は、コマンドラインに入力されたコマンドです。" #. type: Fenced code block (text) -#: text/chapter1.md:117 text/chapter3.md:313 +#: text/chapter1.md:119 text/chapter3.md:330 #, no-wrap msgid "$ spago build\n" msgstr "$ spago build\n" #. type: Plain text -#: text/chapter1.md:122 +#: text/chapter1.md:124 msgid "" "Usually, these commands will be tailored to Linux/Mac OS users, so Windows " -"users may need to make small changes such as modifying the file separator, " +"users may need to make small changes, such as modifying the file separator " "or replacing shell built-ins with their Windows equivalents." msgstr "" -"通常、これらのコマンドはLinuxやMac OSの利用者ならそのまま適用できますが、" -"Windowsの利用者はファイル区切り文字を変更する、シェルの組み込み機能をWindows" -"の相当するものに置き換えるなどの小さな変更を加える必要があるかもしれません。" +"通常、これらのコマンドはLinuxやMac OSの利用者に合わせたものになっています。\n" +"そのためWindowsの利用者は小さな変更を加える必要があるかもしれません。\n" +"ファイル区切り文字を変更したり、シェルの組み込み機能をWindowsの相当するものに" +"置き換えるなどです。" #. type: Plain text -#: text/chapter1.md:124 +#: text/chapter1.md:126 msgid "" "Commands which should be typed at the PSCi interactive mode prompt will be " "preceded by an angle bracket:" @@ -877,7 +874,7 @@ msgstr "" "います。" #. type: Fenced code block (text) -#: text/chapter1.md:125 +#: text/chapter1.md:127 #, no-wrap msgid "" "> 1 + 2\n" @@ -887,38 +884,38 @@ msgstr "" "3\n" #. type: Plain text -#: text/chapter1.md:131 +#: text/chapter1.md:133 msgid "" -"Each chapter will contain exercises, labelled with their difficulty level. " -"It is strongly recommended that you attempt the exercises in each chapter to " +"Each chapter will contain exercises labelled with their difficulty level. It " +"is strongly recommended that you attempt the exercises in each chapter to " "fully understand the material." msgstr "" -"各章には演習が付いており、それぞれ難易度も示されています。各章の内容を完全に" -"理解するために、演習に取り組むことを強くお勧めします。" +"各章には演習が含まれており、難易度も示されています。\n" +"内容を完全に理解するために、各章の演習に取り組むことを強くお勧めします。" #. type: Plain text -#: text/chapter1.md:133 +#: text/chapter1.md:135 msgid "" "This book aims to provide an introduction to the PureScript language for " "beginners, but it is not the sort of book that provides a list of template " "solutions to problems. For beginners, this book should be a fun challenge, " "and you will get the most benefit if you read the material, attempt the " -"exercises, and most importantly of all, try to write some code of your own." +"exercises, and, most importantly of all, try to write some code of your own." msgstr "" -"この本は初心者にPureScriptへの導入を提供することを目的としており、問題につい" -"てのお決まりの解決策の一覧を提供するような種類の本ではありません。初心者に" -"とってこの本を読むのは楽しい挑戦になるはずですし、本書の内容を読み演習に挑戦" -"すればだいたいの利益を得られるでしょうが、なにより重要なのは、あなたが自分自" -"身のコードを書いてみることです。" +"本書は初心者にPureScriptへの導入を提供することを目的としており、課題に対する" +"お決まりの解決策の一覧を提供するような類の本ではありません。\n" +"初心者にとっては楽しい挑戦になるはずです。\n" +"内容を読んで演習に挑戦すれば得るものがあることでしょう。\n" +"そして何よりも大切なのは、自分自身でコードを書いてみることです。" #. type: Title ## -#: text/chapter1.md:134 +#: text/chapter1.md:136 #, no-wrap msgid "Getting Help" msgstr "困ったときには" #. type: Plain text -#: text/chapter1.md:137 +#: text/chapter1.md:139 msgid "" "If you get stuck at any point, there are a number of resources available " "online for learning PureScript:" @@ -927,30 +924,27 @@ msgstr "" "が沢山あります。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "The [PureScript Discord server](https://discord.gg/vKn9up84bp) is a great " "place to chat about issues you may be having. The server is dedicated to " -"chat about PureScript" +"chatting about PureScript" msgstr "" "[PureScriptのDiscordサーバ](https://discord.gg/vKn9up84bp)は抱えている問題に" "ついてチャットするのに良い場所です。\n" -"サーバはPureScriptについてのチャット専用です。" +"こちらのサーバはPureScriptについてのチャット専用です。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "The [Purescript Discourse Forum](https://discourse.purescript.org/) is " -"another good place to search for solutions to common problems. Questions you " -"ask here will be available to help future readers, whereas on Slack, message " -"history is only kept for approximately 2 weeks." +"another good place to search for solutions to common problems." msgstr "" "[PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくあ" -"る問題への解決策を探すのに良い場所です。メッセージ履歴が約2週間しか保たない" -"Slackとは違い、ここで質問した内容は将来の読者の助けとして使えるでしょう。" +"る問題への解決策を探すのに良い場所です。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "[PureScript: Jordan's Reference](https://github.com/jordanmartinez/" "purescript-jordans-reference) is an alternative learning resource that goes " @@ -959,11 +953,11 @@ msgid "" msgstr "" "[PureScript: Jordan's Reference](https://github.com/jordanmartinez/" "purescript-jordans-reference)は別のかなり深く踏み込んだ学習資料です。\n" -"この本の中のある概念が理解しにくかったら、そちらの参考書の対応する節を読むと" +"本書中の概念で理解しにくいものがあったら、そちらの参考書の対応する節を読むと" "よいでしょう。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "[Pursuit](https://pursuit.purescript.org) is a searchable database of " "PureScript types and functions. Read Pursuit's help page to [learn what " @@ -975,7 +969,7 @@ msgstr "" "(https://pursuit.purescript.org/help/users)。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "The unofficial [PureScript Cookbook](https://github.com/JordanMartinez/" "purescript-cookbook) provides answers via code to \"How do I do X?\"-type " @@ -986,10 +980,10 @@ msgstr "" "供します。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "The [PureScript documentation repository](https://github.com/purescript/" -"documentation) collects articles and examples on a wide variety of topics, " +"documentation) collects articles and examples on a wide variety of topics " "written by PureScript developers and users." msgstr "" "[PureScriptドキュメントリポジトリ](https://github.com/purescript/" @@ -997,59 +991,63 @@ msgstr "" "集まっています。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" "The [PureScript website](https://www.purescript.org) contains links to " -"several learning resources, including code samples, videos and other " +"several learning resources, including code samples, videos, and other " "resources for beginners." msgstr "" -"[PureScriptのWebサイト](https://www.purescript.org)には、コード例、映像、他の" -"初心者向け資料を含む幾つかの学習資料へのリンクがあります。" +"[PureScriptのwebサイト](https://www.purescript.org)には幾つかの学習資料へのリ" +"ンクがあります。\n" +"コード例、映像、他の初心者向け資料などです。" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 msgid "" -"[Try PureScript!](https://try.purescript.org) is a website which allows " -"users to compile PureScript code in the web browser, and contains several " -"simple examples of code." +"[Try PureScript!](https://try.purescript.org) is a website that allows users " +"to compile PureScript code in the web browser and contains several simple " +"examples of code." msgstr "" -"[Try PureScript!](https://try.purescript.org)は利用者がWebブラウザで" -"PureScriptのコードをコンパイルできるWebサイトです。\n" -"幾つかの簡単なコードの例があります。" +"[Try PureScript!](https://try.purescript.org)は利用者がwebブラウザで" +"PureScriptのコードをコンパイルできるwebサイトです。\n" +"幾つかの簡単なコードの例もあります。" #. type: Plain text -#: text/chapter1.md:148 +#: text/chapter1.md:150 msgid "" -"If you prefer to learn by reading examples, the `purescript`, `purescript-" -"node` and `purescript-contrib` GitHub organizations contain plenty of " -"examples of PureScript code." +"If you prefer to learn by reading examples, the [purescript](https://github." +"com/purescript), [purescript-node](https://github.com/purescript-node), and " +"[purescript-contrib](https://github.com/purescript-contrib) GitHub " +"organizations contain plenty of examples of PureScript code." msgstr "" -"もし例を読んで学ぶ方が好きでしたら、GitHubの `purescript`組織、`purescript-" -"node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。" +"もし例を読んで学ぶ方が好きでしたら、GitHubの[purescript](https://github.com/" +"purescript)、[purescript-node](https://github.com/purescript-node)、" +"[purescript-contrib](https://github.com/purescript-contrib)組織にはPureScript" +"コードの例が沢山あります。" #. type: Title ## -#: text/chapter1.md:149 +#: text/chapter1.md:151 #, no-wrap msgid "About the Author" msgstr "著者について" #. type: Plain text -#: text/chapter1.md:152 +#: text/chapter1.md:154 msgid "" "I am the original developer of the PureScript compiler. I'm based in Los " "Angeles, California, and started programming at an early age in BASIC on an " -"8-bit personal computer, the Amstrad CPC. Since then I have worked " +"8-bit personal computer, the Amstrad CPC. Since then, I have worked " "professionally in a variety of programming languages (including Java, Scala, " "C#, F#, Haskell and PureScript)." msgstr "" -"私はPureScriptコンパイラの最初の開発者です。私はカリフォルニア州ロサンゼルス" -"を拠点にしており、8ビットパーソナルコンピュータ、Amstrad CPC上のBASICでまだ幼" -"い時にプログラミングを始めました。\n" +"私はPureScriptコンパイラの最初の開発者です。\n" +"カリフォルニア州ロサンゼルスを拠点にしており、8ビットパーソナルコンピュータで" +"あるAmstrad CPC上のBASICでまだ幼い時にプログラミングを始めました。\n" "それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そし" -"てPureScript)で業務に携わってきました。" +"てPureScript)で専門的に業務に携わってきました。" #. type: Plain text -#: text/chapter1.md:154 +#: text/chapter1.md:156 msgid "" "Not long into my professional career, I began to appreciate functional " "programming and its connections with mathematics, and enjoyed learning " @@ -1060,7 +1058,7 @@ msgstr "" "楽しみました。" #. type: Plain text -#: text/chapter1.md:156 +#: text/chapter1.md:158 msgid "" "I started working on the PureScript compiler in response to my experience " "with JavaScript. I found myself using functional programming techniques that " @@ -1068,7 +1066,7 @@ msgid "" "environment in which to apply them. Solutions at the time included various " "attempts to compile Haskell to JavaScript while preserving its semantics " "(Fay, Haste, GHCJS), but I was interested to see how successful I could be " -"by approaching the problem from the other side - attempting to keep the " +"by approaching the problem from the other side – attempting to keep the " "semantics of JavaScript, while enjoying the syntax and type system of a " "language like Haskell." msgstr "" @@ -1078,12 +1076,13 @@ msgstr "" "いましたが、それを応用するためのもっと理に適った環境を求めていました。\n" "そのとき検討した案のなかには、Haskellからその意味論を維持しながらJavaScriptへ" "とコンパイルするいろいろな試み(Fay、Haste、GHCJS)もありました。\n" -"しかし私が興味を持っていたのはこの問題への別の切り口からのアプローチ、すなわ" -"ちHaskellのような言語の構文と型システムを楽しみながらJavaScriptの意味論も維持" -"するということが、どのようにすれば可能になるのかでした。" +"しかし私が興味を持っていたのは、この問題へ別の切り口からアプローチすると、ど" +"の程度うまくいくのかということでした。\n" +"そのアプローチとは、JavaScriptの意味論を維持しつつ、Haskellのような言語の構文" +"と型システムを楽しむことなのです。" #. type: Plain text -#: text/chapter1.md:158 +#: text/chapter1.md:160 msgid "" "I maintain [a blog](https://blog.functorial.com), and can be [reached on " "Twitter](https://twitter.com/paf31)." @@ -1092,43 +1091,44 @@ msgstr "" "(http://twitter.com/paf31)こともできます。" #. type: Title ## -#: text/chapter1.md:159 +#: text/chapter1.md:161 #, no-wrap msgid "Acknowledgements" msgstr "謝辞" #. type: Plain text -#: text/chapter1.md:162 +#: text/chapter1.md:164 msgid "" "I would like to thank the many contributors who helped PureScript to reach " "its current state. Without the huge collective effort which has been made on " -"the compiler, tools, libraries, documentation and tests, the project would " +"the compiler, tools, libraries, documentation, and tests, the project would " "certainly have failed." msgstr "" -"現在の状態に到達するまでPureScriptを手伝ってくれた多くの協力者に感謝したいと" -"思います。コンパイラやツール、ライブラリ、ドキュメント、テストでの組織的で弛" -"まぬ努力がなかったら、プロジェクトは間違いなく失敗していたことでしょう。" +"現在に至るまでPureScriptに手を貸してくださった多くの協力者に感謝したいと思い" +"ます。\n" +"コンパイラ、ツール、ライブラリ、ドキュメント、テストでの、巨大で組織的な尽力" +"なくしては、プロジェクトは間違いなく失敗していたことでしょう。" #. type: Plain text -#: text/chapter1.md:164 +#: text/chapter1.md:166 msgid "" "The PureScript logo which appears on the cover of this book was created by " -"Gareth Hughes, and is gratefully reused here under the terms of the " -"[Creative Commons Attribution 4.0 license](https://creativecommons.org/" -"licenses/by/4.0/)." +"Gareth Hughes and is gratefully reused here under the terms of the [Creative " +"Commons Attribution 4.0 license](https://creativecommons.org/licenses/" +"by/4.0/)." msgstr "" -"この本の表紙に表示されたPureScriptのロゴはGareth Hughesによって作成されたもの" -"で、[Creative Commons Attribution 4.0 license](https://creativecommons.org/" +"本書の表紙に示されたPureScriptのロゴはGareth Hughesによって作成されたもので、" +"[Creative Commons Attribution 4.0 license](https://creativecommons.org/" "licenses/by/4.0/)の条件の下で再利用させて頂いています 。" #. type: Plain text -#: text/chapter1.md:165 +#: text/chapter1.md:167 msgid "" "Finally, I would like to thank everyone who has given me feedback and " "corrections on the contents of this book." msgstr "" -"最後に、この本の内容に関する反応や訂正をくださった全ての方に、心より感謝した" -"いと思います。" +"最後に、本書の内容に関する反応や訂正をくださった全ての方に、心より感謝したい" +"と思います。" #. type: Title # #: text/chapter10.md:1 @@ -1149,14 +1149,14 @@ msgstr "この章の目標" #: text/chapter10.md:6 msgid "" "This chapter will introduce PureScript's _foreign function interface_ (or " -"_FFI_), which enables communication from PureScript code to JavaScript code, " +"_FFI_), which enables communication from PureScript code to JavaScript code " "and vice versa. We will cover how to:" msgstr "" -"この章でPureScriptの _外部関数インターフェース_ (foreign function interface; " -"_FFI_) を紹介します。\n" +"本章ではPureScriptの*外部関数インターフェース* (foreign function interface; " +"*FFI*) を紹介します。\n" "これによりPureScriptコードからJavaScriptコードへの呼び出し、及びその逆が可能" "になります。\n" -"これから扱うのは次のようなものです。" +"以下の方法を押さえていきます。" #. type: Bullet: '- ' #: text/chapter10.md:10 @@ -1200,17 +1200,23 @@ msgstr "" "フォームのデータを直列化してブラウザのローカルストレージに保存し、アプリケー" "ションが再起動したときにそれを再読み込みする" +# From WordNet (r) 3.0 (2006) [wn]: +# +# sought-after +# adj 1: being searched for; "the most sought-after item was the +# silver candelabrum" [syn: sought, sought-after(a)] #. type: Plain text #: text/chapter10.md:17 msgid "" -"There is also an addendum which covers some additional topics which are not " -"as commonly sought-after. Feel free to read these sections, but don't let " -"them stand in the way of progressing through the remainder of the book if " -"they're less relevant to your learning objectives:" +"There is also an addendum covering some additional topics that are not as " +"commonly sought-after. Feel free to read these sections, but don't let them " +"stand in the way of progressing through the remainder of the book if they're " +"less relevant to your learning objectives:" msgstr "" -"さらに一般にはそこまで重用されない幾つかの話題を押さえた補遺もあります。\n" -"ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本の" -"残りを読み進める妨げにならないようにしてください。" +"さらに一般にはそこまで重用されない幾つかの追加の話題を押さえた補遺もありま" +"す。\n" +"ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本書" +"の残りを読み進める妨げにならないようにしてください。" #. type: Bullet: '- ' #: text/chapter10.md:20 @@ -1235,12 +1241,12 @@ msgstr "プロジェクトの準備" #: text/chapter10.md:24 msgid "" "The source code for this module is a continuation of the source code from " -"chapters 3, 7 and 8. As such, the source tree includes the appropriate " +"chapters 3, 7, and 8. As such, the source tree includes the appropriate " "source files from those chapters." msgstr "" -"このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。そうし" -"たわけでソースツリーにはこれらの章からの適切なソースファイルが含まれていま" -"す。" +"このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。\n" +"そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれて" +"います。" #. type: Plain text #: text/chapter10.md:26 @@ -1285,16 +1291,16 @@ msgid "" "PureScript provides a straightforward foreign function interface to make " "working with JavaScript as simple as possible. However, it should be noted " "that the FFI is an _advanced_ feature of the language. To use it safely and " -"effectively, you should have an understanding of the runtime representation " -"of the data you plan to work with. This chapter aims to impart such an " -"understanding as pertains to code in PureScript's standard libraries." +"effectively, you should understand the runtime representation of the data " +"you plan to work with. This chapter aims to impart such an understanding as " +"pertains to code in PureScript's standard libraries." msgstr "" -"JavaScriptを扱う作業をできる限り簡単にするため、PureScriptは直感的な外部関数" -"インターフェースを提供しています。\n" -"しかし、FFIはPureScriptの*応用的な*機能であることには留意していただきたいと思" -"います。\n" -"FFIを安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現につい" -"てよく理解していなければなりません。\n" +"JavaScriptの扱いをできる限り単純にするため、PureScriptは直感的な外部関数イン" +"ターフェースを提供しています。\n" +"しかし、FFIはこの言語の*応用的な*機能であることには心に留めておかれると良いで" +"しょう。\n" +"安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現について理" +"解していなければなりません。\n" "この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝" "授することを目指します。" @@ -1302,16 +1308,15 @@ msgstr "" #: text/chapter10.md:36 msgid "" "PureScript's FFI is designed to be very flexible. In practice, this means " -"that developers have a choice, between giving their foreign functions very " -"simple types, or using the type system to protect against accidental misuses " +"that developers have a choice between giving their foreign functions very " +"simple types or using the type system to protect against accidental misuses " "of foreign code. Code in the standard libraries tends to favor the latter " "approach." msgstr "" "PureScriptのFFIはとても柔軟に設計されています。\n" -"実際には、外部関数に最低限の型だけを与えるか、それとも型システムを利用して外" -"部のコードの誤った使い方を防ぐようにするか、開発者が選べるということを意味し" -"ています。\n" -"標準ライブラリのコードは、後者の手法を好む傾向にあります。" +"実際には、外部関数にとても単純な型を与えるか、型システムを利用して外部のコー" +"ドの誤った使い方を防ぐようにするか、開発者が選べるようになっています。\n" +"標準ライブラリのコードは、後者の手法を採る傾向にあります。" #. type: Plain text #: text/chapter10.md:38 @@ -1377,8 +1382,10 @@ msgstr "" #. type: Plain text #: text/chapter10.md:53 #, no-wrap -msgid "This function has the correct runtime representation for the function type `String -> String`, since it takes non-null strings to non-null strings, and has no other side-effects.\n" -msgstr "`null`でない文字列から `null`でない文字列への関数であり、副作用を持っていないので、この関数は型 `String -> String`について適切な実行時表現を持っています。\n" +msgid "This function has the correct runtime representation for the function type `String -> String`, since it takes non-null strings to non-null strings and has no other side-effects.\n" +msgstr "" +"この関数は関数の型`String -> String`について適切な実行時表現を持っています。\n" +"`null`でない文字列を取って`null`でない文字列にするもので、副作用を持たないからです。\n" #. type: Plain text #: text/chapter10.md:55 @@ -1399,7 +1406,7 @@ msgstr "{{#include ../exercises/chapter10/test/URI.purs}}\n" #: text/chapter10.md:62 msgid "" "We also need to write a foreign JavaScript module to import it from. A " -"corresponding foreign JavaScript module is one of the same name but " +"corresponding foreign JavaScript module is one of the same name but the " "extension changed from `.purs` to `.js`. If the Purescript module above is " "saved as `URI.purs`, then the foreign JavaScript module is saved as `URI." "js`. Since `encodeURIComponent` is already defined, we have to export it as " @@ -1543,11 +1550,11 @@ msgstr "{{#include ../exercises/chapter10/test/Examples.purs:diagonal}}\n" #: text/chapter10.md:114 msgid "" "Recall that functions in PureScript are _curried_. `diagonal` is a function " -"that takes a `Number` and returns a _function_, that takes a `Number` and " +"that takes a `Number` and returns a _function_ that takes a `Number` and " "returns a `Number`." msgstr "" -"PureScriptの関数は _カリー化_ されていることを思い出してください。\n" -"`diagonal`は`Number`を取って _関数_ を返す関数です。\n" +"PureScriptの関数は*カリー化*されていることを思い出してください。\n" +"`diagonal`は`Number`を取って*関数*を返す関数です。\n" "そして返された関数は`Number`を取って`Number`を返します。" #. type: Fenced code block (js) @@ -1664,16 +1671,18 @@ msgid "" "module." msgstr "" "`Fn2`は3つの型引数を取ります。\n" -"`Fn2 a b c`は、型 `a`と `b`の2つの引数、返り値の型 `c`をもつカリー化されてい" -"ない関数の型を表現しています。\n" +"`Fn2 a b c`は、型`a`と`b`の2つの引数、返り値の型`c`を持つカリー化されていない" +"関数の型を表現しています。\n" "これを使って外部モジュールから`diagonalUncurried`をインポートしました。" #. type: Plain text #: text/chapter10.md:166 msgid "" -"We can then call it with `runFn2` which takes the uncurried function then " -"the arguments." -msgstr "カリー化されていない関数と引数を取る`runFn2`で呼び出すことができます。" +"We can then call it with `runFn2`, which takes the uncurried function and " +"then the arguments." +msgstr "" +"そうして`runFn2`を使って呼び出せます。\n" +"これはカリー化されていない関数と引数を取るものです。" #. type: Fenced code block (text) #: text/chapter10.md:167 @@ -1711,16 +1720,17 @@ msgstr "カリー化されていない関数についての補足" #. type: Plain text #: text/chapter10.md:181 msgid "" -"PureScript's curried functions has certain advantages. It allows us to " +"PureScript's curried functions have certain advantages. It allows us to " "partially apply functions, and to give type class instances for function " -"types - but it comes with a performance penalty. For performance critical " +"types – but it comes with a performance penalty. For performance-critical " "code, it is sometimes necessary to define uncurried JavaScript functions " "which accept multiple arguments." msgstr "" -"PureScriptのカリー化された関数にはもちろん利点があります。部分的に関数を適用" -"でき、関数型に型クラスインスタンスを与えられます。しかし効率上の代償も付いて" -"くるのです。効率性が決定的に重要なコードでは多変数を受け付けるカリー化されて" -"いないJavaScript関数を定義する必要が時々あります。" +"PureScriptのカリー化された関数には勿論利点があります。\n" +"部分的に関数を適用でき、関数型に型クラスインスタンスを与えられるのです。\n" +"しかし効率上の代償も付いてきます。\n" +"効率性が決定的に重要なコードでは時々、多変数を受け付けるカリー化されていない" +"JavaScript関数を定義する必要があります。" #. type: Plain text #: text/chapter10.md:183 @@ -1793,7 +1803,7 @@ msgstr "{{#include ../exercises/chapter10/test/Examples.purs:curried_add}}\n" #. type: Plain text #: text/chapter10.md:211 msgid "" -"and the resulting generated code, which is less compact due to the nested " +"And the resulting generated code, which is less compact due to the nested " "functions:" msgstr "" "そして生成結果のコードが以下です。\n" @@ -1828,7 +1838,7 @@ msgstr "現代的なJavaScriptの構文についての補足" #. type: Plain text #: text/chapter10.md:225 msgid "" -"The arrow function syntax we saw earlier is an ES6 feature, and so it is " +"The arrow function syntax we saw earlier is an ES6 feature, which is " "incompatible with some older browsers (namely IE11). As of writing, it is " "[estimated that arrow functions are unavailable for the 6% of users](https://" "caniuse.com/#feat=arrow-functions) who have not yet updated their web " @@ -1836,16 +1846,15 @@ msgid "" msgstr "" "前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しす" "ればIE11)と互換性がありません。\n" -"執筆時点でWebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことがで" +"執筆時点でwebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことがで" "きないと推計](https://caniuse.com/#feat=arrow-functions)されています。" #. type: Plain text #: text/chapter10.md:227 msgid "" -"In order to be compatible with the most users, the JavaScript code generated " -"by the PureScript compiler does not use arrow functions. It is also " -"recommended to **avoid arrow functions in public libraries** for the same " -"reason." +"To be compatible with the most users, the JavaScript code generated by the " +"PureScript compiler does not use arrow functions. It is also recommended to " +"**avoid arrow functions in public libraries** for the same reason." msgstr "" "ほとんどの利用者にとって互換性があるようにするため、PureScriptコンパイラに" "よって生成されるJavaScriptコードは矢印関数を使っていません。\n" @@ -1855,13 +1864,13 @@ msgstr "" #. type: Plain text #: text/chapter10.md:229 msgid "" -"You may still use arrow functions in your own FFI code, but then should " +"You may still use arrow functions in your own FFI code, but then you should " "include a tool such as [Babel](https://github.com/babel/babel#intro) in your " "deployment workflow to convert these back to ES5 compatible functions." msgstr "" "それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程で" "ES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/" -"babel#intro)などのツールを含めるべきです。" +"babel#intro)などのツールを含めると良いでしょう。" #. type: Plain text #: text/chapter10.md:231 @@ -1907,23 +1916,23 @@ msgid "" msgstr "本書の残りの例では入れ子の関数の代わりに矢印関数を使います。" #. type: Title ## -#: text/chapter10.md:246 text/chapter10.md:321 text/chapter10.md:476 -#: text/chapter10.md:714 text/chapter10.md:891 text/chapter10.md:1074 -#: text/chapter10.md:1311 text/chapter11.md:140 text/chapter11.md:224 -#: text/chapter11.md:343 text/chapter11.md:549 text/chapter11.md:716 -#: text/chapter11.md:915 text/chapter11.md:960 text/chapter12.md:153 +#: text/chapter10.md:246 text/chapter10.md:321 text/chapter10.md:478 +#: text/chapter10.md:716 text/chapter10.md:893 text/chapter10.md:1076 +#: text/chapter10.md:1313 text/chapter11.md:141 text/chapter11.md:223 +#: text/chapter11.md:342 text/chapter11.md:548 text/chapter11.md:715 +#: text/chapter11.md:914 text/chapter11.md:959 text/chapter12.md:153 #: text/chapter12.md:361 text/chapter12.md:555 text/chapter13.md:90 #: text/chapter13.md:137 text/chapter13.md:244 text/chapter13.md:387 #: text/chapter14.md:249 text/chapter14.md:352 text/chapter14.md:569 -#: text/chapter14.md:704 text/chapter2.md:124 text/chapter3.md:714 +#: text/chapter14.md:704 text/chapter2.md:124 text/chapter3.md:774 #: text/chapter4.md:70 text/chapter4.md:181 text/chapter4.md:363 #: text/chapter4.md:521 text/chapter4.md:615 text/chapter5.md:99 #: text/chapter5.md:228 text/chapter5.md:392 text/chapter5.md:465 #: text/chapter5.md:524 text/chapter6.md:130 text/chapter6.md:321 -#: text/chapter6.md:412 text/chapter6.md:609 text/chapter6.md:743 +#: text/chapter6.md:411 text/chapter6.md:608 text/chapter6.md:742 #: text/chapter7.md:381 text/chapter7.md:540 text/chapter7.md:642 -#: text/chapter8.md:308 text/chapter8.md:666 text/chapter8.md:973 -#: text/chapter9.md:87 text/chapter9.md:133 text/chapter9.md:200 +#: text/chapter8.md:308 text/chapter8.md:667 text/chapter8.md:974 +#: text/chapter9.md:87 text/chapter9.md:134 text/chapter9.md:201 #, no-wrap msgid "Exercises" msgstr "演習" @@ -1988,15 +1997,14 @@ msgstr "" #: text/chapter10.md:266 msgid "" "To demonstrate passing `Array`s, here's how to call a JavaScript function " -"which takes an `Array` of `Int` and returns the cumulative sum as another " -"array. Recall that, since JavaScript does not have a separate type for " -"`Int`, both `Int` and `Number` in PureScript translate to `Number` in " -"JavaScript." +"that takes an `Array` of `Int` and returns the cumulative sum as another " +"array. Recall that since JavaScript does not have a separate type for `Int`, " +"both `Int` and `Number` in PureScript translate to `Number` in JavaScript." msgstr "" -"`Array`の受け渡しを実演するために、以下に`Int`の`Array`を取って別の配列として" -"累計の和を返すJavaScriptの関数の呼び出し方を示します。前にありましたが、" -"JavaScriptは`Int`のための分離した型を持たないため、PureScriptでの`Int`と" -"`Number`はJavaScriptでの`Number`に翻訳されます。" +"`Array`を渡すところを実演するために、以下に`Int`の`Array`を取って別の配列とし" +"て累計の和を返すJavaScriptの関数の呼び出し方を示します。\n" +"前にありましたが、JavaScriptは`Int`のための分離した型を持たないため、" +"PureScriptでの`Int`と`Number`は両方共JavaScriptでの`Number`に翻訳されます。" #. type: Fenced code block (hs) #: text/chapter10.md:267 @@ -2048,12 +2056,12 @@ msgstr "" #: text/chapter10.md:292 msgid "" "To demonstrate passing `Records`, here's how to call a JavaScript function " -"which takes two `Complex` numbers as records, and returns their sum as " -"another record. Note that a `Record` in PureScript is represented as an " -"`Object` in JavaScript:" +"that takes two `Complex` numbers as records and returns their sum as another " +"record. Note that a `Record` in PureScript is represented as an `Object` in " +"JavaScript:" msgstr "" -"`Record`の受け渡しを実演するために、以下に2つの`Complex`な数をレコードとして" -"取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。\n" +"`Record`を渡すところを実演するために、以下に2つの`Complex`な数をレコードとし" +"て取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。\n" "PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意して" "ください。" @@ -2113,15 +2121,16 @@ msgstr "" #: text/chapter10.md:320 msgid "" "Note that the above techniques require trusting that JavaScript will return " -"the expected types, as PureScript is not able to apply type checking to " -"JavaScript code. We will describe this type safety concern in more detail " -"later on in the JSON section, as well as cover techniques to protect against " -"type mismatches." +"the expected types, as PureScript cannot apply type checking to JavaScript " +"code. We will describe this type safety concern in more detail later on in " +"the JSON section, as well as cover techniques to protect against type " +"mismatches." msgstr "" "なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要がありま" -"す。PureScriptはJavaScriptのコードに型検査を適用できないからです。この型安全" -"性の配慮について後のJSONの節でより詳しく記述していきます。型の不整合から身を" -"守る手法についても押さえます。" +"す。\n" +"PureScriptはJavaScriptのコードに型検査を適用できないからです。\n" +"この型安全性の配慮について後のJSONの節でより詳しく解説していきます。\n" +"型の不整合から身を守る手法についても押さえます。" #. type: Bullet: '1. ' #: text/chapter10.md:324 @@ -2296,44 +2305,48 @@ msgstr "forall a. (forall x. x -> Maybe x) -> (forall x. Maybe x) -> Array a -> #. type: Plain text #: text/chapter10.md:387 -msgid "and not:" +msgid "And not:" msgstr "以下ではないことに注意です。" #. type: Fenced code block (hs) #: text/chapter10.md:388 #, no-wrap -msgid "forall a. ( a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" -msgstr "forall a. ( a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" +msgid "forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" +msgstr "forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" #. type: Plain text -#: text/chapter10.md:394 +#: text/chapter10.md:393 msgid "" "While both forms work, the latter is more vulnerable to unwanted inputs in " -"place of `Just` and `Nothing`. For example, in the more vulnerable case we " -"could call it as follows:" +"place of `Just` and `Nothing`." msgstr "" "どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に" -"侵されやすくなります。例えばより脆弱な場合では以下のようにして呼ぶことができ" -"ます。" +"対してより脆弱です。" -#. type: Fenced code block (hs) +#. type: Plain text #: text/chapter10.md:395 +msgid "For example, in the more vulnerable case, we could call it as follows:" +msgstr "例えば、比較的脆い方では、以下のように呼び出せるでしょう。" + +#. type: Fenced code block (hs) +#: text/chapter10.md:396 #, no-wrap msgid "maybeHeadImpl (\\_ -> Just 1000) (Just 1000) [1,2,3]\n" msgstr "maybeHeadImpl (\\_ -> Just 1000) (Just 1000) [1,2,3]\n" #. type: Plain text #: text/chapter10.md:401 +msgid "Which returns `Just 1000` for any array input." +msgstr "これは如何なる配列の入力に対しても`Just 1000`を返します。" + +#. type: Plain text +#: text/chapter10.md:403 #, no-wrap -msgid "" -"which returns `Just 1000` for any array input.\n" -"This vulnerability is allowed because `(\\_ -> Just 1000)` and `Just 1000` match the signatures of `(a -> Maybe a)` and `Maybe a` respectively when `a` is `Int` (based on input array).\n" -msgstr "" -"これはいかなる配列についても`Just 1000`を返します。\n" -"この脆弱性は`a`が`Int`のときに(これは入力の配列に基づきます)`(\\_ -> Just 1000)`と`Just 1000`がシグネチャ`(a -> Maybe a)`と`Maybe a`にそれぞれ合致しているために許されているのです。\n" +msgid "This vulnerability is allowed because `(\\_ -> Just 1000)` and `Just 1000` match the signatures of `(a -> Maybe a)` and `Maybe a`, respectively, when `a` is `Int` (based on input array).\n" +msgstr "この脆弱性では、`a`が`Int`のときに(これは入力の配列に基づきます)`(\\_ -> Just 1000)`と`Just 1000`がシグネチャ`(a -> Maybe a)`と`Maybe a`にそれぞれ照合するために許容されてしまっています。\n" #. type: Plain text -#: text/chapter10.md:404 +#: text/chapter10.md:406 #, no-wrap msgid "" "In the more secure type signature, even when `a` is determined to be `Int` based on the input array, we still need to provide valid functions matching the signatures involving `forall x`.\n" @@ -2341,25 +2354,25 @@ msgid "" msgstr "より安全な型シグネチャでは、入力の配列に基づいて`a`が`Int`に決定されたとしても、`forall x`に絡むシグネチャに合致する妥当な関数を提供する必要があります。`(forall x. Maybe x)`の *唯一* の選択肢は`Nothing`ですが、それは`Just`値が`x`の型を前提にしてしまうと、もはや全ての`x`については妥当でなくなってしまうからです。`(forall x. x -> Maybe x)`の唯一の選択肢は`Just`(望まれている引数)と`(\\_ -> Nothing)`であり、後者は唯一残っている脆弱性になるのです。\n" #. type: Title ## -#: text/chapter10.md:405 +#: text/chapter10.md:407 #, no-wrap msgid "Defining Foreign Types" msgstr "外部型の定義" #. type: Plain text -#: text/chapter10.md:408 +#: text/chapter10.md:410 msgid "" -"Suppose instead of returning a `Maybe a`, we want to actually return " -"`arr[0]`. We want a type that represents a value either of type `a` or the " -"`undefined` value (but not `null`). We'll call this type `Undefined a`." +"Suppose instead of returning a `Maybe a`, we want to return `arr[0]`. We " +"want a type that represents a value either of type `a` or the `undefined` " +"value (but not `null`). We'll call this type `Undefined a`." msgstr "" -"`Maybe a`を返す代わりに実は`arr[0]`を返したいのだとしましょう。\n" +"`Maybe a`を返す代わりに`arr[0]`を返したいのだとしましょう。\n" "型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する" "型がほしいです。\n" "この型を`Undefined a`と呼びましょう。" #. type: Plain text -#: text/chapter10.md:410 +#: text/chapter10.md:412 msgid "" "We can define a _foreign type_ using a _foreign type declaration_. The " "syntax is similar to defining a foreign function:" @@ -2368,13 +2381,13 @@ msgstr "" "外部関数を定義するのと似ています。" #. type: Fenced code block (haskell) -#: text/chapter10.md:411 +#: text/chapter10.md:413 #, no-wrap msgid "foreign import data Undefined :: Type -> Type\n" msgstr "foreign import data Undefined :: Type -> Type\n" #. type: Plain text -#: text/chapter10.md:416 +#: text/chapter10.md:418 #, no-wrap msgid "The `data` keyword here indicates that we are defining a _type_, not a value. Instead of a type signature, we give the _kind_ of the new type. In this case, we declare the kind of `Undefined` to be `Type -> Type`. In other words, `Undefined` is a type constructor.\n" msgstr "" @@ -2385,12 +2398,12 @@ msgstr "" "言い換えれば`Undefined`は型構築子です。\n" #. type: Plain text -#: text/chapter10.md:418 -msgid "We can now simply reuse our original definition for `head`:" -msgstr "これで元の`head`の定義を単に再利用できます。" +#: text/chapter10.md:420 +msgid "We can now reuse our original definition for `head`:" +msgstr "これで元の`head`の定義を再利用できます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:419 +#: text/chapter10.md:421 #, no-wrap msgid "" "export const undefinedHead = arr =>\n" @@ -2400,57 +2413,57 @@ msgstr "" " arr[0];\n" #. type: Plain text -#: text/chapter10.md:425 +#: text/chapter10.md:427 msgid "And in the PureScript module:" msgstr "PureScriptモジュールには以下を追加します。" #. type: Fenced code block (haskell) -#: text/chapter10.md:426 +#: text/chapter10.md:428 #, no-wrap msgid "foreign import undefinedHead :: forall a. Array a -> Undefined a\n" msgstr "foreign import undefinedHead :: forall a. Array a -> Undefined a\n" #. type: Plain text -#: text/chapter10.md:431 +#: text/chapter10.md:433 msgid "" -"The body of the `undefinedHead` function returns `arr[0]` which may be " +"The body of the `undefinedHead` function returns `arr[0]`, which may be " "`undefined`, and the type signature correctly reflects that fact." msgstr "" "`undefinedHead`関数の本体は`undefined`かもしれない`arr[0]`を返します。\n" "そしてこの型シグネチャはその事実を正しく反映しています。" #. type: Plain text -#: text/chapter10.md:433 +#: text/chapter10.md:435 msgid "" -"This function has the correct runtime representation for its type, but is " +"This function has the correct runtime representation for its type, but it's " "quite useless since we have no way to use a value of type `Undefined a`. " "Well, not exactly. We can use this type in another FFI!" msgstr "" -"この関数はその型の適切な実行時表現を持っていますが、型 `Undefined a`の値を使" -"用する方法がないので、全く役に立ちません。\n" +"この関数はその型の適切な実行時表現を持っていますが、型`Undefined a`の値を使用" +"する方法がないので、全く役に立ちません。\n" "いや、言い過ぎました。\n" "別のFFIでこの型を使えますからね。" #. type: Plain text -#: text/chapter10.md:435 +#: text/chapter10.md:437 msgid "" "We can write a function that will tell us whether a value is undefined or " "not:" msgstr "値が未定義かどうかを教えてくれる関数を書くことができます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:436 +#: text/chapter10.md:438 #, no-wrap msgid "foreign import isUndefined :: forall a. Undefined a -> Boolean\n" msgstr "foreign import isUndefined :: forall a. Undefined a -> Boolean\n" #. type: Plain text -#: text/chapter10.md:441 +#: text/chapter10.md:443 msgid "This is defined in our foreign JavaScript module as follows:" msgstr "外部JavaScriptモジュールで次のように定義できます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:442 +#: text/chapter10.md:444 #, no-wrap msgid "" "export const isUndefined = value =>\n" @@ -2460,7 +2473,7 @@ msgstr "" " value === undefined;\n" #. type: Plain text -#: text/chapter10.md:448 +#: text/chapter10.md:450 msgid "" "We can now use `isUndefined` and `undefinedHead` together from PureScript to " "define a useful function:" @@ -2469,7 +2482,7 @@ msgstr "" "関数を定義できます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:449 +#: text/chapter10.md:451 #, no-wrap msgid "" "isEmpty :: forall a. Array a -> Boolean\n" @@ -2479,26 +2492,26 @@ msgstr "" "isEmpty = isUndefined <<< undefinedHead\n" #. type: Plain text -#: text/chapter10.md:455 +#: text/chapter10.md:457 msgid "" "Here, the foreign function we defined is very simple, which means we can " -"benefit from the use of PureScript's typechecker as much as possible. This " -"is good practice in general: foreign functions should be kept as small as " +"benefit from using PureScript's typechecker as much as possible. This is " +"good practice in general: foreign functions should be kept as small as " "possible, and application logic moved into PureScript code wherever possible." msgstr "" -"このように、定義したこの外部関数はとても簡単です。\n" +"このように、定義したこの外部関数はとても単純です。\n" "つまりPureScriptの型検査器を使うことによる利益が最大限得られるのです。\n" "一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理は" "PureScriptコードへ移動しておくことをお勧めします。" #. type: Title ## -#: text/chapter10.md:456 text/chapter8.md:365 text/chapter8.md:443 +#: text/chapter10.md:458 text/chapter8.md:365 text/chapter8.md:444 #, no-wrap msgid "Exceptions" msgstr "例外" #. type: Plain text -#: text/chapter10.md:459 +#: text/chapter10.md:461 msgid "" "Another option is to simply throw an exception in the case of an empty " "array. Strictly speaking, pure functions should not throw exceptions, but we " @@ -2511,19 +2524,19 @@ msgstr "" "安全性に欠けていることを関数名で示します。" #. type: Fenced code block (haskell) -#: text/chapter10.md:460 +#: text/chapter10.md:462 #, no-wrap msgid "foreign import unsafeHead :: forall a. Array a -> a\n" msgstr "foreign import unsafeHead :: forall a. Array a -> a\n" #. type: Plain text -#: text/chapter10.md:465 +#: text/chapter10.md:467 msgid "" "In our foreign JavaScript module, we can define `unsafeHead` as follows:" msgstr "JavaScriptモジュールでは、`unsafeHead`を以下のように定義できます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:466 +#: text/chapter10.md:468 #, no-wrap msgid "" "export const unsafeHead = arr => {\n" @@ -2543,7 +2556,7 @@ msgstr "" "};\n" #. type: Bullet: '1. ' -#: text/chapter10.md:479 +#: text/chapter10.md:481 msgid "" "(Medium) Given a record that represents a quadratic polynomial `a*x^2 + b*x " "+ c = 0`:" @@ -2552,7 +2565,7 @@ msgstr "" "ます。" #. type: Plain text -#: text/chapter10.md:487 +#: text/chapter10.md:489 #, no-wrap msgid "" " ```hs\n" @@ -2572,7 +2585,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter10.md:489 +#: text/chapter10.md:491 #, no-wrap msgid " Write a JavaScript function `quadraticRootsImpl` and a wrapper `quadraticRoots :: Quadratic -> Pair Complex` that uses the quadratic formula to find the roots of this polynomial. Return the two roots as a `Pair` of `Complex` numbers. _Hint:_ Use the `quadraticRoots` wrapper to pass a constructor for `Pair` to `quadraticRootsImpl`.\n" msgstr "" @@ -2581,7 +2594,7 @@ msgstr "" " *手掛かり*:梱包`quadraticRoots`を使って`Pair`の構築子を`quadraticRootsImpl`に渡してください。\n" #. type: Bullet: '1. ' -#: text/chapter10.md:491 +#: text/chapter10.md:493 msgid "" "(Medium) Write the function `toMaybe :: forall a. Undefined a -> Maybe a`. " "This function converts `undefined` to `Nothing` and `a` values to `Just`s." @@ -2590,13 +2603,13 @@ msgstr "" "この関数は`undefined`を`Nothing`に、`a`の値を`Just a`に変換します。" #. type: Bullet: '1. ' -#: text/chapter10.md:493 +#: text/chapter10.md:495 msgid "(Difficult) With `toMaybe` in place, we can rewrite `maybeHead` as" msgstr "" "(難しい)`toMaybe`が準備できたら、`maybeHead`を以下に書き換えられます。" #. type: Plain text -#: text/chapter10.md:498 +#: text/chapter10.md:500 #, no-wrap msgid "" " ```hs\n" @@ -2610,7 +2623,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter10.md:500 +#: text/chapter10.md:502 #, no-wrap msgid " Is this a better approach than our previous implementation? _Note:_ There is no unit test for this exercise.\n" msgstr "" @@ -2618,18 +2631,18 @@ msgstr "" " *補足*:この演習のための単体試験はありません。\n" #. type: Title ## -#: text/chapter10.md:501 +#: text/chapter10.md:503 #, no-wrap msgid "Using Type Class Member Functions" msgstr "型クラスメンバー関数を使う" #. type: Plain text -#: text/chapter10.md:504 +#: text/chapter10.md:506 msgid "" -"Just like our earlier guide on passing the `Maybe` constructor over FFI, " -"this is another case of writing PureScript that calls JavaScript, which in " -"turn calls PureScript functions again. Here we will explore how to pass type " -"class member functions over the FFI." +"Like our earlier guide on passing the `Maybe` constructor over FFI, this is " +"another case of writing PureScript that calls JavaScript, which calls " +"PureScript functions again. Here we will explore how to pass type class " +"member functions over the FFI." msgstr "" "つい先程までFFI越しに`Maybe`の構築子を渡す手引きをしましたが、今回は" "JavaScriptを呼び出すPureScriptを書く別の場合です。\n" @@ -2637,16 +2650,16 @@ msgstr "" "ここでは型クラスのメンバー関数をFFI越しに渡す方法を探ります。" #. type: Plain text -#: text/chapter10.md:506 +#: text/chapter10.md:508 msgid "" -"We start with writing a foreign JavaScript function which expects the " +"We start with writing a foreign JavaScript function that expects the " "appropriate instance of `show` to match the type of `x`." msgstr "" "型`x`に合う適切な`show`のインスタンスを期待する外部JavaScript関数を書くことか" "ら始めます。" #. type: Fenced code block (js) -#: text/chapter10.md:507 +#: text/chapter10.md:509 #, no-wrap msgid "" "export const boldImpl = show => x =>\n" @@ -2656,23 +2669,23 @@ msgstr "" " show(x).toUpperCase() + \"!!!\";\n" #. type: Plain text -#: text/chapter10.md:513 +#: text/chapter10.md:515 msgid "Then we write the matching signature:" msgstr "それから対応するシグネチャを書きます。" #. type: Fenced code block (hs) -#: text/chapter10.md:514 +#: text/chapter10.md:516 #, no-wrap msgid "foreign import boldImpl :: forall a. (a -> String) -> a -> String\n" msgstr "foreign import boldImpl :: forall a. (a -> String) -> a -> String\n" #. type: Plain text -#: text/chapter10.md:519 -msgid "and a wrapper function that passes the correct instance of `show`:" +#: text/chapter10.md:521 +msgid "And a wrapper function that passes the correct instance of `show`:" msgstr "そして`show`の正しいインスタンスを渡す梱包関数も書きます。" #. type: Fenced code block (hs) -#: text/chapter10.md:520 +#: text/chapter10.md:522 #, no-wrap msgid "" "bold :: forall a. Show a => a -> String\n" @@ -2682,12 +2695,12 @@ msgstr "" "bold x = boldImpl show x\n" #. type: Plain text -#: text/chapter10.md:526 -msgid "Alternatively in point-free form:" -msgstr "代わりにポイントフリー形式だとこうです。" +#: text/chapter10.md:528 +msgid "Alternatively, in point-free form:" +msgstr "代えてポイントフリー形式だとこうです。" #. type: Fenced code block (hs) -#: text/chapter10.md:527 +#: text/chapter10.md:529 #, no-wrap msgid "" "bold :: forall a. Show a => a -> String\n" @@ -2697,12 +2710,12 @@ msgstr "" "bold = boldImpl show\n" #. type: Plain text -#: text/chapter10.md:533 +#: text/chapter10.md:535 msgid "We can then call the wrapper:" msgstr "そうして梱包を呼び出すことができます。" #. type: Fenced code block (text) -#: text/chapter10.md:534 +#: text/chapter10.md:536 #, no-wrap msgid "" "$ spago repl\n" @@ -2720,7 +2733,7 @@ msgstr "" "\"(TUPLE 1 \\\"HAT\\\")!!!\"\n" #. type: Plain text -#: text/chapter10.md:544 +#: text/chapter10.md:546 msgid "" "Here's another example demonstrating passing multiple functions, including a " "function of multiple arguments (`eq`):" @@ -2729,7 +2742,7 @@ msgstr "" "これらの関数には複数引数の関数 (`eq`) が含まれます。" #. type: Fenced code block (js) -#: text/chapter10.md:545 +#: text/chapter10.md:547 #, no-wrap msgid "" "export const showEqualityImpl = eq => show => a => b => {\n" @@ -2749,7 +2762,7 @@ msgstr "" "}\n" #. type: Fenced code block (hs) -#: text/chapter10.md:555 +#: text/chapter10.md:557 #, no-wrap msgid "" "foreign import showEqualityImpl :: forall a. (a -> a -> Boolean) -> (a -> String) -> a -> a -> String\n" @@ -2763,7 +2776,7 @@ msgstr "" "showEquality = showEqualityImpl eq show\n" #. type: Fenced code block (text) -#: text/chapter10.md:562 +#: text/chapter10.md:564 #, no-wrap msgid "" "$ spago repl\n" @@ -2781,13 +2794,13 @@ msgstr "" "\"Nothing is not equal to (Just 5)\"\n" #. type: Title ## -#: text/chapter10.md:571 +#: text/chapter10.md:573 #, no-wrap msgid "Effectful Functions" msgstr "作用のある関数" #. type: Plain text -#: text/chapter10.md:574 +#: text/chapter10.md:576 msgid "" "Let's extend our `bold` function to log to the console. Logging is an " "`Effect`, and `Effect`s are represented in JavaScript as a function of zero " @@ -2799,7 +2812,7 @@ msgstr "" "つまり`()`と矢印記法だとこうです。" #. type: Fenced code block (js) -#: text/chapter10.md:575 +#: text/chapter10.md:577 #, no-wrap msgid "" "export const yellImpl = show => x => () =>\n" @@ -2809,7 +2822,7 @@ msgstr "" " console.log(show(x).toUpperCase() + \"!!!\");\n" #. type: Plain text -#: text/chapter10.md:581 +#: text/chapter10.md:583 msgid "" "The new foreign import is the same as before, except that the return type " "changed from `String` to `Effect Unit`." @@ -2818,7 +2831,7 @@ msgstr "" "外は以前と同じです。" #. type: Fenced code block (hs) -#: text/chapter10.md:582 +#: text/chapter10.md:584 #, no-wrap msgid "" "foreign import yellImpl :: forall a. (a -> String) -> a -> Effect Unit\n" @@ -2832,16 +2845,16 @@ msgstr "" "yell = yellImpl show\n" #. type: Plain text -#: text/chapter10.md:590 +#: text/chapter10.md:592 msgid "" "When testing this in the repl, notice that the string is printed directly to " -"the console (instead of being quoted) and a `unit` value is returned." +"the console (instead of being quoted), and a `unit` value is returned." msgstr "" "REPLで試すと文字列が(引用符で囲まれず)直接コンソールに印字され`unit`値が返" "ることがわかります。" #. type: Fenced code block (text) -#: text/chapter10.md:591 +#: text/chapter10.md:593 #, no-wrap msgid "" "$ spago repl\n" @@ -2861,7 +2874,7 @@ msgstr "" "unit\n" #. type: Plain text -#: text/chapter10.md:602 +#: text/chapter10.md:604 msgid "" "There are also `EffectFn` wrappers from `Effect.Uncurried`. These are " "similar to the `Fn` wrappers from `Data.Function.Uncurried` that we've " @@ -2874,12 +2887,12 @@ msgstr "" "ことができます。" #. type: Plain text -#: text/chapter10.md:604 +#: text/chapter10.md:606 msgid "" "You'd generally only use these if you want to call existing JavaScript " -"library APIs directly, rather than wrapping those APIs in curried functions. " +"library APIs directly rather than wrapping those APIs in curried functions. " "So it doesn't make much sense to present an example of uncurried `yell`, " -"where the JavaScript relies on PureScript type class members, since you " +"where the JavaScript relies on PureScript type class members since you " "wouldn't find that in the existing JavaScript ecosystem." msgstr "" "一般的にこれらを使うのは、こうしたAPIをカリー化された関数に包むのではなく、既" @@ -2889,7 +2902,7 @@ msgstr "" "それは既存のJavaScriptの生態系にそのメンバーが見付からないためです。" #. type: Plain text -#: text/chapter10.md:606 +#: text/chapter10.md:608 msgid "" "Instead, we'll modify our previous `diagonal` example to include logging in " "addition to returning the result:" @@ -2898,7 +2911,7 @@ msgstr "" "こうなります。" #. type: Fenced code block (js) -#: text/chapter10.md:607 +#: text/chapter10.md:609 #, no-wrap msgid "" "export const diagonalLog = function(w, h) {\n" @@ -2914,13 +2927,13 @@ msgstr "" "};\n" #. type: Fenced code block (hs) -#: text/chapter10.md:615 +#: text/chapter10.md:617 #, no-wrap msgid "foreign import diagonalLog :: EffectFn2 Number Number Number\n" msgstr "foreign import diagonalLog :: EffectFn2 Number Number Number\n" #. type: Fenced code block (text) -#: text/chapter10.md:619 +#: text/chapter10.md:621 #, no-wrap msgid "" "$ spago repl\n" @@ -2940,13 +2953,13 @@ msgstr "" "5.0\n" #. type: Title ## -#: text/chapter10.md:629 +#: text/chapter10.md:631 #, no-wrap msgid "Asynchronous Functions" msgstr "非同期関数" #. type: Plain text -#: text/chapter10.md:632 +#: text/chapter10.md:634 msgid "" "Promises in JavaScript translate directly to asynchronous effects in " "PureScript with the help of the `aff-promise` library. See that library's " @@ -2960,7 +2973,7 @@ msgstr "" "ここでは幾つかの例に触れるだけとします。" #. type: Plain text -#: text/chapter10.md:634 +#: text/chapter10.md:636 msgid "" "Suppose we want to use this JavaScript `wait` promise (or asynchronous " "function) in our PureScript project. It may be used to delay execution for " @@ -2971,20 +2984,20 @@ msgstr "" "`ms`ミリ秒分だけ送らせて実行させるのに使うことができます。" #. type: Fenced code block (js) -#: text/chapter10.md:635 +#: text/chapter10.md:637 #, no-wrap msgid "const wait = ms => new Promise(resolve => setTimeout(resolve, ms));\n" msgstr "const wait = ms => new Promise(resolve => setTimeout(resolve, ms));\n" #. type: Plain text -#: text/chapter10.md:640 +#: text/chapter10.md:642 msgid "" "We just need to export it wrapped as an `Effect` (function of zero " "arguments):" msgstr "単に`Effect`(無引数関数)に包んで公開するだけで大丈夫です。" #. type: Fenced code block (js) -#: text/chapter10.md:641 +#: text/chapter10.md:643 #, no-wrap msgid "" "export const sleepImpl = ms => () =>\n" @@ -2994,12 +3007,12 @@ msgstr "" " wait(ms);\n" #. type: Plain text -#: text/chapter10.md:647 +#: text/chapter10.md:649 msgid "Then import it as follows:" msgstr "そして以下のようにインポートします。" #. type: Fenced code block (hs) -#: text/chapter10.md:648 +#: text/chapter10.md:650 #, no-wrap msgid "" "foreign import sleepImpl :: Int -> Effect (Promise Unit)\n" @@ -3013,13 +3026,13 @@ msgstr "" "sleep = sleepImpl >>> toAffE\n" #. type: Plain text -#: text/chapter10.md:656 +#: text/chapter10.md:658 msgid "We can then run this `Promise` in an `Aff` block like so:" msgstr "" "そうして`Aff`ブロック中でこの`Promise`を以下のように走らせることができます。" #. type: Fenced code block (text) -#: text/chapter10.md:657 +#: text/chapter10.md:659 #, no-wrap msgid "" "$ spago repl\n" @@ -3055,19 +3068,19 @@ msgstr "" "done waiting\n" #. type: Plain text -#: text/chapter10.md:676 +#: text/chapter10.md:678 msgid "" -"Note that asynchronous logging in the repl just waits to print until the " -"entire block has finished executing. This code behaves more predictably when " -"run with `spago test` where there is a slight delay _between_ prints." +"Note that asynchronous logging in the repl waits to print until the entire " +"block has finished executing. This code behaves more predictably when run " +"with `spago test` where there is a slight delay _between_ prints." msgstr "" "REPLでの非同期ログ出力はブロック全体が実行を終了するまで印字を待機する点に注" "意しましょう。\n" -"このコードを`spago test`で走らせた場合、印字の _合間に_ 僅かな遅延があり、よ" -"り予測に近い挙動をします。" +"このコードを`spago test`で走らせた場合、印字の*合間に*僅かな遅延があり、より" +"予測に近い挙動をします。" #. type: Plain text -#: text/chapter10.md:678 +#: text/chapter10.md:680 msgid "" "Let's look at another example where we return a value from a promise. This " "function is written with `async` and `await`, which is just syntactic sugar " @@ -3078,7 +3091,7 @@ msgstr "" "に過ぎません。" #. type: Fenced code block (js) -#: text/chapter10.md:679 +#: text/chapter10.md:681 #, no-wrap msgid "" "async function diagonalWait(delay, w, h) {\n" @@ -3098,14 +3111,14 @@ msgstr "" " diagonalWait(delay, w, h);\n" #. type: Plain text -#: text/chapter10.md:690 +#: text/chapter10.md:692 msgid "" "Since we're returning a `Number`, we represent this type in the `Promise` " "and `Aff` wrappers:" msgstr "`Number`を返すため、この型を`Promise`と`Aff`の梱包の中で表現します。" #. type: Fenced code block (hs) -#: text/chapter10.md:691 +#: text/chapter10.md:693 #, no-wrap msgid "" "foreign import diagonalAsyncImpl :: Int -> Number -> Number -> Effect (Promise Number)\n" @@ -3119,7 +3132,7 @@ msgstr "" "diagonalAsync i x y = toAffE $ diagonalAsyncImpl i x y\n" #. type: Fenced code block (text) -#: text/chapter10.md:698 +#: text/chapter10.md:700 #, no-wrap msgid "" "$ spago repl\n" @@ -3151,7 +3164,7 @@ msgstr "" "5.0\n" #. type: Plain text -#: text/chapter10.md:717 +#: text/chapter10.md:719 msgid "" "Exercises for the above sections are still on the ToDo list. If you have any " "ideas for good exercises, please make a suggestion." @@ -3160,26 +3173,26 @@ msgstr "" "もし何か良い演習の考えがあればご提案ください。" #. type: Title ## -#: text/chapter10.md:718 +#: text/chapter10.md:720 #, no-wrap msgid "JSON" msgstr "JSON" #. type: Plain text -#: text/chapter10.md:721 +#: text/chapter10.md:723 msgid "" -"There are many reasons to use JSON in an application, for example, it's a " +"There are many reasons to use JSON in an application; for example, it's a " "common means of communicating with web APIs. This section will discuss other " -"use-cases too, beginning with a technique to improve type safety when " +"use-cases, too, beginning with a technique to improve type safety when " "passing structural data over the FFI." msgstr "" "アプリケーションでJSONを使うことには多くの理由があります。\n" -"例えばWebのAPIと疎通するよくある手段であるためです。\n" +"例えばwebのAPIと疎通するよくある手段であるためです。\n" "この節では他の用例についてもお話ししましょう。\n" -"構造的なデータをFFI越しに渡すことで型安全性を向上させる手法から始めます。" +"構造的なデータをFFI越しに渡す場合に型安全性を向上させる手法から始めます。" #. type: Plain text -#: text/chapter10.md:723 +#: text/chapter10.md:725 msgid "" "Let's revisit our earlier FFI functions `cumulativeSums` and `addComplex` " "and introduce a bug to each:" @@ -3188,7 +3201,7 @@ msgstr "" "入させてみましょう。" #. type: Fenced code block (js) -#: text/chapter10.md:724 +#: text/chapter10.md:726 #, no-wrap msgid "" "export const cumulativeSumsBroken = arr => {\n" @@ -3228,16 +3241,16 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:745 +#: text/chapter10.md:747 msgid "" "We can use the original type signatures, and the code will still compile, " -"despite the fact that the return types are incorrect." +"despite the incorrect return types." msgstr "" "実際は返る型が正しくないのですが、元々の型シグネチャを使うことができ、依然と" "してコードはコンパイルされます。" #. type: Fenced code block (hs) -#: text/chapter10.md:746 +#: text/chapter10.md:748 #, no-wrap msgid "" "foreign import cumulativeSumsBroken :: Array Int -> Array Int\n" @@ -3249,7 +3262,7 @@ msgstr "" "foreign import addComplexBroken :: Complex -> Complex -> Complex\n" #. type: Plain text -#: text/chapter10.md:753 +#: text/chapter10.md:755 msgid "" "We can even execute the code, which might either produce unexpected results " "or a runtime error:" @@ -3258,7 +3271,7 @@ msgstr "" "ります。" #. type: Fenced code block (text) -#: text/chapter10.md:754 +#: text/chapter10.md:756 #, no-wrap msgid "" "$ spago repl\n" @@ -3304,7 +3317,7 @@ msgstr "" "TypeError: Cannot read property 'toString' of undefined\n" #. type: Plain text -#: text/chapter10.md:778 +#: text/chapter10.md:780 msgid "" "For example, our resulting `sums` is no-longer a valid `Array Int`, now that " "a `String` is included in the Array. And further operations produce " @@ -3318,7 +3331,7 @@ msgstr "" "これでは捜索の難しいバグになりかねませんね。" #. type: Plain text -#: text/chapter10.md:780 +#: text/chapter10.md:782 msgid "" "Likewise, there are no errors when calling `addComplexBroken`; however, " "accessing the `imag` field of our `Complex` result will either produce " @@ -3331,7 +3344,7 @@ msgstr "" "しょう。" #. type: Plain text -#: text/chapter10.md:782 +#: text/chapter10.md:784 msgid "" "Let's use JSON to make our PureScript code more impervious to bugs in " "JavaScript code." @@ -3340,7 +3353,7 @@ msgstr "" "を使いましょう。" #. type: Plain text -#: text/chapter10.md:784 +#: text/chapter10.md:786 msgid "" "The `argonaut` library contains the JSON decoding and encoding capabilities " "we need. That library has excellent [documentation](https://github.com/" @@ -3354,16 +3367,16 @@ msgstr "" "けを押さえます。" #. type: Plain text -#: text/chapter10.md:786 +#: text/chapter10.md:788 msgid "" "If we create an alternate foreign import that defines the return type as " "`Json`:" msgstr "" -"返る型を`Json`として定義するようにして、代わりとなる外部インポートをつくると" -"こうなります。" +"返る型を`Json`として定義するようにして、代わりとなる外部インポートを作るとこ" +"うなります。" #. type: Fenced code block (hs) -#: text/chapter10.md:787 +#: text/chapter10.md:789 #, no-wrap msgid "" "foreign import cumulativeSumsJson :: Array Int -> Json\n" @@ -3373,12 +3386,12 @@ msgstr "" "foreign import addComplexJson :: Complex -> Complex -> Json\n" #. type: Plain text -#: text/chapter10.md:793 +#: text/chapter10.md:795 msgid "Note that we're simply pointing to our existing broken functions:" msgstr "単純に既存の壊れた関数を指している点に注意します。" #. type: Fenced code block (js) -#: text/chapter10.md:794 +#: text/chapter10.md:796 #, no-wrap msgid "" "export const cumulativeSumsJson = cumulativeSumsBroken\n" @@ -3388,12 +3401,12 @@ msgstr "" "export const addComplexJson = addComplexBroken\n" #. type: Plain text -#: text/chapter10.md:800 +#: text/chapter10.md:802 msgid "And then write a wrapper to decode the returned foreign `Json` value:" msgstr "そして返された`Json`の値をデコードする梱包を書きます。" #. type: Fenced code block (hs) -#: text/chapter10.md:801 +#: text/chapter10.md:803 #, no-wrap msgid "" "{{#include ../exercises/chapter10/test/Examples.purs:cumulativeSumsDecoded}}\n" @@ -3405,7 +3418,7 @@ msgstr "" "{{#include ../exercises/chapter10/test/Examples.purs:addComplexDecoded}}\n" #. type: Plain text -#: text/chapter10.md:808 +#: text/chapter10.md:810 msgid "" "Then any values that can't be successfully decoded to our return type appear " "as a `Left` error `String`:" @@ -3414,7 +3427,7 @@ msgstr "" "ラーとして表れます。" #. type: Fenced code block (text) -#: text/chapter10.md:809 +#: text/chapter10.md:811 #, no-wrap msgid "" "$ spago repl\n" @@ -3438,12 +3451,12 @@ msgstr "" "(Left \"JSON was missing expected field: imag\")\n" #. type: Plain text -#: text/chapter10.md:822 +#: text/chapter10.md:824 msgid "If we call the working versions, a `Right` value is returned." msgstr "正常に動作するバージョンで呼び出すと`Right`の値が返ります。" #. type: Plain text -#: text/chapter10.md:824 +#: text/chapter10.md:826 msgid "" "Try this yourself by modifying `test/Examples.js` with the following change " "to point to the working versions before running the next repl block." @@ -3452,7 +3465,7 @@ msgstr "" "Examples.js`へ以下の変更を加えて、手元で試してみましょう。" #. type: Fenced code block (js) -#: text/chapter10.md:825 +#: text/chapter10.md:827 #, no-wrap msgid "" "export const cumulativeSumsJson = cumulativeSums\n" @@ -3462,7 +3475,7 @@ msgstr "" "export const addComplexJson = addComplex\n" #. type: Fenced code block (text) -#: text/chapter10.md:830 +#: text/chapter10.md:832 #, no-wrap msgid "" "$ spago repl\n" @@ -3486,7 +3499,7 @@ msgstr "" "(Right { imag: 6.0, real: 4.0 })\n" #. type: Plain text -#: text/chapter10.md:843 +#: text/chapter10.md:845 msgid "" "Using JSON is also the easiest way to pass other structural types, such as " "`Map` and `Set`, through the FFI. Since JSON only consists of booleans, " @@ -3503,7 +3516,7 @@ msgstr "" "ているとします)、それから`Map`や`Set`に復元できるのです。" #. type: Plain text -#: text/chapter10.md:845 +#: text/chapter10.md:847 msgid "" "Here's an example of a foreign function signature that modifies a `Map` of " "`String` keys and `Int` values, along with the wrapper function that handles " @@ -3513,13 +3526,13 @@ msgstr "" "チャと、それに伴うJSONのエンコードとデコードを扱う梱包関数の例です。" #. type: Fenced code block (hs) -#: text/chapter10.md:846 +#: text/chapter10.md:848 #, no-wrap msgid "{{#include ../exercises/chapter10/test/Examples.purs:mapSetFooJson}}\n" msgstr "{{#include ../exercises/chapter10/test/Examples.purs:mapSetFooJson}}\n" #. type: Plain text -#: text/chapter10.md:851 +#: text/chapter10.md:853 msgid "" "Note that this is a prime use case for function composition. Both of these " "alternatives are equivalent to the above:" @@ -3528,7 +3541,7 @@ msgstr "" "以下の代案は両方とも上のものと等価です。" #. type: Fenced code block (hs) -#: text/chapter10.md:852 +#: text/chapter10.md:854 #, no-wrap msgid "" "mapSetFoo :: Map String Int -> Either JsonDecodeError (Map String Int)\n" @@ -3544,7 +3557,7 @@ msgstr "" "mapSetFoo = encodeJson >>> mapSetFooJson >>> decodeJson\n" #. type: Plain text -#: text/chapter10.md:861 +#: text/chapter10.md:863 msgid "" "Here is the JavaScript implementation. Note the `Array.from` step, which is " "necessary to convert the JavaScript `Map` into a JSON-friendly format before " @@ -3555,7 +3568,7 @@ msgstr "" "し、デコードでPureScriptの`Map`に変換し直すために必須です。" #. type: Fenced code block (js) -#: text/chapter10.md:862 +#: text/chapter10.md:864 #, no-wrap msgid "" "export const mapSetFooJson = j => {\n" @@ -3571,12 +3584,12 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:871 +#: text/chapter10.md:873 msgid "Now we can send and receive a `Map` over the FFI:" msgstr "これで`Map`をFFI越しに送ったり受け取ったりできます。" #. type: Fenced code block (text) -#: text/chapter10.md:872 +#: text/chapter10.md:874 #, no-wrap msgid "" "$ spago repl\n" @@ -3614,7 +3627,7 @@ msgstr "" "(Right (fromFoldable [(Tuple \"Foo\" 42),(Tuple \"cat\" 2),(Tuple \"hat\" 1)]))\n" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 msgid "" "(Medium) Write a JavaScript function and PureScript wrapper `valuesOfMap :: " "Map String Int -> Either JsonDecodeError (Set Int)` that returns a `Set` of " @@ -3626,7 +3639,7 @@ msgstr "" "ください。" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 msgid "" "(Easy) Write a new wrapper for the previous JavaScript function with the " "signature `valuesOfMapGeneric :: forall k v. Map k v -> Either " @@ -3638,31 +3651,31 @@ msgstr "" "い梱包を書いてください。\n" "シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either " "JsonDecodeError (Set v)`です。\n" -"なお`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。\n" +"なお、`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。\n" "コンパイラが導いてくれます。" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 msgid "" "(Medium) Rewrite the earlier `quadraticRoots` function as " -"`quadraticRootsSet` which returns the `Complex` roots as a `Set` via JSON " +"`quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON " "(instead of as a `Pair`)." msgstr "" -"(普通)少し前の`quadraticRoots`を書き換えて`quadraticRootSet`としてくださ" -"い。\n" +"(普通)少し前の`quadraticRoots`関数を書き換えて`quadraticRootSet`としてくだ" +"さい。\n" "この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返しま" "す。" #. type: Plain text -#: text/chapter10.md:900 +#: text/chapter10.md:902 #, no-wrap msgid "" -"1. (Difficult) Rewrite the earlier `quadraticRoots` function as `quadraticRootsSafe` which uses JSON to pass the `Pair` of `Complex` roots over FFI. Don't use the `Pair` constructor in JavaScript, but instead, just return the pair in a decoder-compatible format.\n" +"1. (Difficult) Rewrite the earlier `quadraticRoots` function as `quadraticRootsSafe` that uses JSON to pass the `Pair` of `Complex` roots over FFI. Don't use the `Pair` constructor in JavaScript, but instead, just return the pair in a decoder-compatible format.\n" "_Hint_: You'll need to write a `DecodeJson` instance for `Pair`. Consult the [argonaut docs](https://github.com/purescript-contrib/purescript-argonaut-codecs/tree/main/docs#writing-new-instances) for instruction on writing your own decode instance. Their [decodeJsonTuple](https://github.com/purescript-contrib/purescript-argonaut-codecs/blob/master/src/Data/Argonaut/Decode/Class.purs) instance may also be a helpful reference. Note that you'll need a `newtype` wrapper for `Pair` to avoid creating an \"orphan instance\".\n" "1. (Medium) Write a `parseAndDecodeArray2D :: String -> Either String (Array (Array Int))` function to parse and decode a JSON string containing a 2D array, such as `\"[[1, 2, 3], [4, 5], [6]]\"`. _Hint_: You'll need to use `jsonParser` to convert the `String` into `Json` before decoding.\n" "1. (Medium) The following data type represents a binary tree with values at the leaves:\n" msgstr "" -"1. (難しい)少し前の`quadraticRoots`を書き換えて`quadraticRootsSafe`としてください。\n" +"1. (難しい)少し前の`quadraticRoots`関数を書き換えて`quadraticRootsSafe`としてください。\n" " この関数はJSONを使って`Complex`の根の`Pair`をFFI越しに渡します。\n" " JavaScriptでは`Pair`構築子を使わないでください。\n" " その代わり、デコーダーに互換性のある形式で対を返すだけにしてください。\n" @@ -3676,7 +3689,7 @@ msgstr "" "1. (普通)以下のデータ型は値が葉にある二分木を表現します。\n" #. type: Plain text -#: text/chapter10.md:906 +#: text/chapter10.md:908 #, no-wrap msgid "" " ```haskell\n" @@ -3692,7 +3705,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter10.md:911 +#: text/chapter10.md:913 #, no-wrap msgid "" " Derive generic `EncodeJson` and `DecodeJson` instances for the `Tree` type.\n" @@ -3707,7 +3720,7 @@ msgstr "" "1. (難しい)以下の`data`型は整数か文字列かによってJSONで異なって表現されます。\n" #. type: Plain text -#: text/chapter10.md:917 +#: text/chapter10.md:919 #, no-wrap msgid "" " ```haskell\n" @@ -3723,7 +3736,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter10.md:919 +#: text/chapter10.md:921 #, no-wrap msgid " Write instances of `EncodeJson` and `DecodeJson` for the `IntOrString` data type which implement this behavior. _Hint_: The `alt` operator from `Control.Alt` may be helpful.\n" msgstr "" @@ -3731,16 +3744,16 @@ msgstr "" " *手掛かり*:`Control.Alt`の`alt`演算子が役立つかもしれません。\n" #. type: Title ## -#: text/chapter10.md:920 +#: text/chapter10.md:922 #, no-wrap msgid "Address book" msgstr "住所録" #. type: Plain text -#: text/chapter10.md:923 +#: text/chapter10.md:925 msgid "" -"In this section we will apply our newly-acquired FFI and JSON knowledge to " -"build on our address book example from chapter 8. We will add the following " +"In this section, we will apply our newly-acquired FFI and JSON knowledge to " +"build on our address book example from Chapter 8. We will add the following " "features:" msgstr "" "この節では新しく獲得したFFIとJSONの知識を応用して、第8章の住所録の例を構築し" @@ -3748,7 +3761,7 @@ msgstr "" "以下の機能を加えていきます。" #. type: Bullet: '- ' -#: text/chapter10.md:927 +#: text/chapter10.md:929 msgid "" "A Save button at the bottom of the form that, when clicked, serializes the " "state of the form to JSON and saves it in local storage." @@ -3757,7 +3770,7 @@ msgstr "" "に直列化してローカルストレージに保存します。" #. type: Bullet: '- ' -#: text/chapter10.md:927 +#: text/chapter10.md:929 msgid "" "Automatic retrieval of the JSON document from local storage upon page " "reload. The form fields are populated with the contents of this document." @@ -3766,23 +3779,23 @@ msgstr "" "フォームのフィールドにはこの文書の内容を入れます。" #. type: Bullet: '- ' -#: text/chapter10.md:927 +#: text/chapter10.md:929 msgid "A pop-up alert if there is an issue saving or loading the form state." msgstr "" "フォームの状態を保存したり読み込んだりするのに問題があればポップアップの警告" "を出します。" #. type: Plain text -#: text/chapter10.md:929 +#: text/chapter10.md:931 msgid "" "We'll start by creating FFI wrappers for the following Web Storage APIs in " "our `Effect.Storage` module:" msgstr "" -"`Effect.Storage`モジュールに以下のWebストレージAPIのためのFFIの梱包をつくるこ" -"とから始めていきます。" +"`Effect.Storage`モジュールに以下のwebストレージAPIのためのFFIの梱包を作ること" +"から始めていきます。" #. type: Bullet: '- ' -#: text/chapter10.md:932 +#: text/chapter10.md:934 msgid "" "`setItem` takes a key and a value (both strings), and returns a computation " "which stores (or updates) the value in local storage at the specified key." @@ -3791,7 +3804,7 @@ msgstr "" "レージに値を格納する計算を返します。" #. type: Bullet: '- ' -#: text/chapter10.md:932 +#: text/chapter10.md:934 msgid "" "`getItem` takes a key, and attempts to retrieve the associated value from " "local storage. However, since the `getItem` method on `window.localStorage` " @@ -3803,7 +3816,7 @@ msgstr "" "は`String`ではなく`Json`です。" #. type: Fenced code block (haskell) -#: text/chapter10.md:933 +#: text/chapter10.md:935 #, no-wrap msgid "" "foreign import setItem :: String -> String -> Effect Unit\n" @@ -3815,7 +3828,7 @@ msgstr "" "foreign import getItem :: String -> Effect Json\n" #. type: Plain text -#: text/chapter10.md:940 +#: text/chapter10.md:942 msgid "" "Here is the corresponding JavaScript implementation of these functions in " "`Effect/Storage.js`:" @@ -3824,7 +3837,7 @@ msgstr "" "す。" #. type: Fenced code block (js) -#: text/chapter10.md:941 +#: text/chapter10.md:943 #, no-wrap msgid "" "export const setItem = key => value => () =>\n" @@ -3840,12 +3853,12 @@ msgstr "" " window.localStorage.getItem(key);\n" #. type: Plain text -#: text/chapter10.md:950 +#: text/chapter10.md:952 msgid "We'll create a save button like so:" msgstr "以下のように保存ボタンを作ります。" #. type: Fenced code block (hs) -#: text/chapter10.md:951 +#: text/chapter10.md:953 #, no-wrap msgid "" "saveButton :: R.JSX\n" @@ -3875,7 +3888,7 @@ msgstr "" " }\n" #. type: Plain text -#: text/chapter10.md:967 +#: text/chapter10.md:969 msgid "" "And write our validated `person` as a JSON string with `setItem` in the " "`validateAndSave` function:" @@ -3884,7 +3897,7 @@ msgstr "" "`setItem`を使って書き込みます。" #. type: Fenced code block (hs) -#: text/chapter10.md:968 +#: text/chapter10.md:970 #, no-wrap msgid "" "validateAndSave :: Effect Unit\n" @@ -3906,14 +3919,14 @@ msgstr "" " log \"Saved\"\n" #. type: Plain text -#: text/chapter10.md:980 +#: text/chapter10.md:982 msgid "" "Note that if we attempt to compile at this stage, we'll encounter the " "following error:" -msgstr "なおこの段階でコンパイルしようとすると以下のエラーに遭遇します。" +msgstr "なお、この段階でコンパイルしようとすると以下のエラーに遭遇します。" #. type: Fenced code block (text) -#: text/chapter10.md:981 +#: text/chapter10.md:983 #, no-wrap msgid "" " No type class instance was found for\n" @@ -3923,21 +3936,21 @@ msgstr "" " Data.Argonaut.Encode.Class.EncodeJson PhoneType\n" #. type: Plain text -#: text/chapter10.md:987 +#: text/chapter10.md:989 msgid "" "This is because `PhoneType` in the `Person` record needs an `EncodeJson` " -"instance. We'll just derive a generic encode instance, and a decode instance " -"too while we're at it. More information how this works is available in the " +"instance. We'll also derive a generic encode instance and a decode instance " +"while we're at it. More information on how this works is available in the " "argonaut docs:" msgstr "" "これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンス" "を必要としているからです。\n" -"単純に汎用のエンコードインスタンスとデコードインスタンスを導出すれば完了で" -"す。\n" -"この仕組みについて、より詳しくはargonautのドキュメントで見られます。" +"また、ついでに汎用のエンコードインスタンスとデコードインスタンスを導出してい" +"きます。\n" +"この仕組みについての詳細情報はargonautのドキュメントにあります。" #. type: Fenced code block (hs) -#: text/chapter10.md:988 +#: text/chapter10.md:990 #, no-wrap msgid "" "{{#include ../exercises/chapter10/src/Data/AddressBook.purs:import}}\n" @@ -3949,7 +3962,7 @@ msgstr "" "{{#include ../exercises/chapter10/src/Data/AddressBook.purs:PhoneType_generic}}\n" #. type: Plain text -#: text/chapter10.md:995 +#: text/chapter10.md:997 msgid "" "Now we can save our `person` to local storage, but this isn't very useful " "unless we can retrieve the data. We'll tackle that next." @@ -3959,35 +3972,35 @@ msgstr "" "次はそれに取り掛かりましょう。" #. type: Plain text -#: text/chapter10.md:997 +#: text/chapter10.md:999 msgid "We'll start with retrieving the \"person\" string from local storage:" msgstr "ローカルストレージから「person」文字列で取得することから始めましょう。" #. type: Fenced code block (hs) -#: text/chapter10.md:998 +#: text/chapter10.md:1000 #, no-wrap msgid "item <- getItem \"person\"\n" msgstr "item <- getItem \"person\"\n" #. type: Plain text -#: text/chapter10.md:1003 +#: text/chapter10.md:1005 msgid "" -"Then we'll create a helper function to handle converting the string from " -"local storage to our `Person` record. Note that this string in storage may " -"be `null`, so we represent it as a foreign `Json` until it is successfully " -"decoded as a `String`. There are a number of other conversion steps along " -"the way - each of which return an `Either` value, so it makes sense to " -"organize these together in a `do` block." +"Then we'll create a helper function to convert the string from local storage " +"to our `Person` record. Note that this string in storage may be `null`, so " +"we represent it as a foreign `Json` until it is successfully decoded as a " +"`String`. There are a number of other conversion steps along the way – each " +"of which returns an `Either` value, so it makes sense to organize these " +"together in a `do` block." msgstr "" -"そうしてローカルストレージから、文字列から`Person`レコードへの変換を扱う補助" -"関数をつくります。\n" -"なおこのストレージ中の文字列は`null`かもしれないので、うまく`String`としてデ" -"コードされるまでは外部の`Json`として表現します。\n" +"そうしてローカルストレージ由来の文字列から`Person`レコードへ変換する補助関数" +"を作ります。\n" +"なお、このストレージ中の文字列は`null`かもしれないので、正常に`String`として" +"デコードされるまでは外部の`Json`として表現します。\n" "道中には他にも多くの変換工程があり、それぞれで`Either`の値を返します。\n" -"そのためこれらを`do`ブロックの中に纏めるのは理に適っています。" +"そのためこれらをまとめて`do`ブロックの中に纏めるのは理に適っています。" #. type: Fenced code block (hs) -#: text/chapter10.md:1004 +#: text/chapter10.md:1006 #, no-wrap msgid "" "processItem :: Json -> Either String Person\n" @@ -4003,10 +4016,10 @@ msgstr "" " decodeJson j\n" #. type: Plain text -#: text/chapter10.md:1013 +#: text/chapter10.md:1015 msgid "" -"Then we inspect this result to see if it succeeded. If it failed, we'll log " -"the errors and use our default `examplePerson`, otherwise we'll use the " +"Then we inspect this result to see if it succeeded. If it fails, we'll log " +"the errors and use our default `examplePerson`, otherwise, we'll use the " "person retrieved from local storage." msgstr "" "そうしてこの結果が成功しているかどうか調べます。\n" @@ -4014,7 +4027,7 @@ msgstr "" "そうでなければローカルストレージから取得した人物を使います。" #. type: Fenced code block (hs) -#: text/chapter10.md:1014 +#: text/chapter10.md:1016 #, no-wrap msgid "" "initialPerson <- case processItem item of\n" @@ -4030,7 +4043,7 @@ msgstr "" " Right p -> pure p\n" #. type: Plain text -#: text/chapter10.md:1023 +#: text/chapter10.md:1025 msgid "" "Finally, we'll pass this `initialPerson` to our component via the `props` " "record:" @@ -4038,7 +4051,7 @@ msgstr "" "最後にこの`initialPerson`を`props`レコードを介してコンポーネントに渡します。" #. type: Fenced code block (hs) -#: text/chapter10.md:1024 +#: text/chapter10.md:1026 #, no-wrap msgid "" "-- Create JSX node from react component.\n" @@ -4048,12 +4061,12 @@ msgstr "" "app = element addressBookApp { initialPerson }\n" #. type: Plain text -#: text/chapter10.md:1030 +#: text/chapter10.md:1032 msgid "And pick it up on the other side to use in our state hook:" msgstr "そして状態フックで使うために別の箇所で拾い上げます。" #. type: Fenced code block (hs) -#: text/chapter10.md:1031 +#: text/chapter10.md:1033 #, no-wrap msgid "" "mkAddressBookApp :: Effect (ReactComponent { initialPerson :: Person })\n" @@ -4067,16 +4080,16 @@ msgstr "" " Tuple person setPerson <- useState props.initialPerson\n" #. type: Plain text -#: text/chapter10.md:1039 +#: text/chapter10.md:1041 msgid "" "As a finishing touch, we'll improve the quality of our error messages by " "appending to the `String` of each `Left` value with `lmap`." msgstr "" -"仕上げとして、それぞれの`Left`値の`String`に`lmap`を使って前置し、エラー文言" -"の質を向上させます。" +"仕上げとして、各`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向" +"上させます。" #. type: Fenced code block (hs) -#: text/chapter10.md:1040 +#: text/chapter10.md:1042 #, no-wrap msgid "" "processItem :: Json -> Either String Person\n" @@ -4092,49 +4105,46 @@ msgstr "" " lmap (\"Cannot decode Person: \" <> _) $ decodeJson j\n" #. type: Plain text -#: text/chapter10.md:1049 +#: text/chapter10.md:1051 msgid "" -"Only the first error should ever occur during normal operation of this app. " -"You can trigger the other errors by opening your web browser's dev tools, " -"editing the saved \"person\" string in local storage, and refreshing the " -"page. How you modify the JSON string determines which error is triggered. " -"See if you can trigger each of them." +"Only the first error should ever occur during the normal operation of this " +"app. You can trigger the other errors by opening your web browser's dev " +"tools, editing the saved \"person\" string in local storage, and refreshing " +"the page. How you modify the JSON string determines which error is " +"triggered. See if you can trigger each of them." msgstr "" "最初のエラーのみがこのアプリの通常の操作内で起こります。\n" -"他のエラーはWebブラウザの開発ツールを開いてローカルストレージ中に保存された" +"他のエラーはwebブラウザの開発ツールを開いてローカルストレージ中に保存された" "「person」文字列を編集し、そのページを参照することで引き起こせます。\n" -"どのようにJSON文字列を変更したかが、どのエラーの引き金になるかを決定しま" -"す。\n" -"それぞれのエラーを引き起こせるかどうかやってみてください。" +"どのようにJSON文字列を変更したかが、どのエラーを引き起こすかを決定します。\n" +"各エラーを引き起こせるかご確認ください。" #. type: Plain text -#: text/chapter10.md:1051 +#: text/chapter10.md:1053 msgid "" -"That covers local storage. Next we'll implement the `alert` action, which is " -"very similar to the `log` action from the `Effect.Console` module. The only " -"difference is that the `alert` action uses the `window.alert` method, " -"whereas the `log` action uses the `console.log` method. As such, `alert` can " -"only be used in environments where `window.alert` is defined, such as a web " -"browser." +"That covers local storage. Next, we'll implement the `alert` action, similar " +"to the `log` action from the `Effect.Console` module. The only difference is " +"that the `alert` action uses the `window.alert` method, whereas the `log` " +"action uses the `console.log` method. As such, `alert` can only be used in " +"environments where `window.alert` is defined, such as a web browser." msgstr "" "これでローカルストレージについては押さえました。\n" -"次に`alert`アクションを実装していきます。\n" -"このアクションは`Effect.Console`モジュールの`log`アクションによく似ていま" -"す。\n" -"唯一の相違点は`alert`アクションが`window.alert`メソッドを使うことで、対して" -"`log`アクションは`console.log`メソッドを使っています。\n" +"次に`alert`動作を実装していきます。\n" +"この動作は`Effect.Console`モジュールの`log`動作に似ています。\n" +"唯一の相違点は`alert`動作が`window.alert`メソッドを使うことで、対して`log`動" +"作は`console.log`メソッドを使っています。\n" "そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができま" "す。\n" -"例えばWebブラウザなどです。" +"webブラウザなどです。" #. type: Fenced code block (hs) -#: text/chapter10.md:1052 +#: text/chapter10.md:1054 #, no-wrap msgid "foreign import alert :: String -> Effect Unit\n" msgstr "foreign import alert :: String -> Effect Unit\n" #. type: Fenced code block (js) -#: text/chapter10.md:1056 +#: text/chapter10.md:1058 #, no-wrap msgid "" "export const alert = msg => () =>\n" @@ -4144,28 +4154,28 @@ msgstr "" " window.alert(msg);\n" #. type: Plain text -#: text/chapter10.md:1062 +#: text/chapter10.md:1064 msgid "We want this alert to appear when either:" msgstr "この警告が次の何れかの場合に現れるようにしたいです。" #. type: Bullet: '- ' -#: text/chapter10.md:1065 +#: text/chapter10.md:1067 msgid "A user attempts to save a form with validation errors." msgstr "利用者が検証エラーを含むフォームを保存しようと試みている。" #. type: Bullet: '- ' -#: text/chapter10.md:1065 +#: text/chapter10.md:1067 msgid "The state cannot be retrieved from local storage." msgstr "状態がローカルストレージから取得できない。" #. type: Plain text -#: text/chapter10.md:1067 +#: text/chapter10.md:1069 msgid "" "That is accomplished by simply replacing `log` with `alert` on these lines:" msgstr "以上は単に以下の行で`log`を`alert`に置き換えるだけで達成できます。" #. type: Fenced code block (hs) -#: text/chapter10.md:1068 +#: text/chapter10.md:1070 #, no-wrap msgid "" "Left errs -> alert $ \"There are \" <> show (length errs) <> \" validation errors.\"\n" @@ -4177,7 +4187,7 @@ msgstr "" "alert $ \"Error: \" <> err <> \". Loading examplePerson\"\n" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 msgid "" "(Easy) Write a wrapper for the `removeItem` method on the `localStorage` " "object, and add your foreign function to the `Effect.Storage` module." @@ -4186,7 +4196,7 @@ msgstr "" "`Effect.Storage`モジュールに外部関数を追加してください" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 msgid "" "(Medium) Add a \"Reset\" button that, when clicked, calls the newly-created " "`removeItem` function to delete the \"person\" entry from local storage." @@ -4196,7 +4206,7 @@ msgstr "" "トレージから「人物」の項目を削除します。" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 msgid "" "(Easy) Write a wrapper for the `confirm` method on the JavaScript `Window` " "object, and add your foreign function to the `Effect.Alert` module." @@ -4205,7 +4215,7 @@ msgstr "" "`Effect.Alert`モジュールにその外部関数を追加してください。" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1080 +#: text/chapter10.md:1082 msgid "" "(Medium) Call this `confirm` function when a users clicks the \"Reset\" " "button to ask if they're sure they want to reset their address book." @@ -4214,73 +4224,74 @@ msgstr "" "出し、本当にアドレス帳を白紙にしたいか尋ねるようにしてください。" #. type: Title ## -#: text/chapter10.md:1081 text/chapter11.md:964 text/chapter12.md:594 -#: text/chapter13.md:401 text/chapter14.md:721 text/chapter2.md:129 -#: text/chapter3.md:722 text/chapter4.md:631 text/chapter5.md:529 -#: text/chapter6.md:758 text/chapter7.md:691 text/chapter8.md:1000 -#: text/chapter9.md:237 +#: text/chapter10.md:1083 text/chapter11.md:963 text/chapter12.md:594 +#: text/chapter13.md:401 text/chapter14.md:720 text/chapter2.md:129 +#: text/chapter3.md:782 text/chapter4.md:631 text/chapter5.md:529 +#: text/chapter6.md:757 text/chapter7.md:691 text/chapter8.md:1001 +#: text/chapter9.md:238 #, no-wrap msgid "Conclusion" msgstr "まとめ" #. type: Plain text -#: text/chapter10.md:1084 +#: text/chapter10.md:1086 msgid "" "In this chapter, we've learned how to work with foreign JavaScript code from " -"PureScript and we've seen the issues involved with writing trustworthy code " +"PureScript, and we've seen the issues involved with writing trustworthy code " "using the FFI:" msgstr "" -"この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。ま" -"た、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。" +"この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。\n" +"また、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。" #. type: Bullet: '- ' -#: text/chapter10.md:1088 +#: text/chapter10.md:1090 msgid "" "We've seen the importance of ensuring that foreign functions have correct " "representations." msgstr "外部関数が正しい表現を持っていることを確かめる重要性を見てきました。" #. type: Bullet: '- ' -#: text/chapter10.md:1088 +#: text/chapter10.md:1090 msgid "" "We learned how to deal with corner cases like null values and other types of " -"JavaScript data, by using foreign types, or the `Json` data type." +"JavaScript data by using foreign types or the `Json` data type." msgstr "" "外部型や`Json`データ型を使用することによって、null値やJavaScriptの他の型の" "データのような特殊な場合に対処する方法を学びました。" #. type: Bullet: '- ' -#: text/chapter10.md:1088 +#: text/chapter10.md:1090 msgid "We saw how to safely serialize and deserialize JSON data." msgstr "安全にJSONデータを直列化・直列化復元する方法を見ました。" #. type: Plain text -#: text/chapter10.md:1090 +#: text/chapter10.md:1092 msgid "" -"For more examples, the `purescript`, `purescript-contrib` and `purescript-" -"node` GitHub organizations provide plenty of examples of libraries which use " +"For more examples, the `purescript`, `purescript-contrib`, and `purescript-" +"node` GitHub organizations provide plenty of examples of libraries that use " "the FFI. In the remaining chapters, we will see some of these libraries put " "to use to solve real-world problems in a type-safe way." msgstr "" -"より多くの例については、Githubの `purescript`組織、`purescript-contrib`組織お" -"よび `purescript-node`組織が、FFIを使用するライブラリの例を多数提供していま" -"す。残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリ" -"を幾つか見ていきます。" +"より多くの例については、GitHubの`purescript`組織、`purescript-contrib`組織、" +"及び`purescript-node`組織が、FFIを使用するライブラリの例を多数提供していま" +"す。\n" +"残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾" +"つか見ていきます。" #. type: Title ## -#: text/chapter10.md:1091 +#: text/chapter10.md:1093 #, no-wrap msgid "Addendum" msgstr "補遺" #. type: Title ### -#: text/chapter10.md:1093 +#: text/chapter10.md:1095 #, no-wrap msgid "Calling PureScript from JavaScript" msgstr "JavaScriptからPureScriptを呼び出す" #. type: Plain text -#: text/chapter10.md:1096 +#: text/chapter10.md:1098 msgid "" "Calling a PureScript function from JavaScript is very simple, at least for " "functions with simple types." @@ -4289,12 +4300,12 @@ msgstr "" "すのはとても簡単です。" #. type: Plain text -#: text/chapter10.md:1098 +#: text/chapter10.md:1100 msgid "Let's take the following simple module as an example:" msgstr "例として以下のような簡単なモジュールを見てみましょう。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1099 +#: text/chapter10.md:1101 #, no-wrap msgid "" "module Test where\n" @@ -4304,7 +4315,7 @@ msgid "" "gcd n 0 = n\n" "gcd n m\n" " | n > m = gcd (n - m) m\n" -" | otherwise = gcd (m - n) n\n" +" | otherwise = gcd (m – n) n\n" msgstr "" "module Test where\n" "\n" @@ -4313,10 +4324,10 @@ msgstr "" "gcd n 0 = n\n" "gcd n m\n" " | n > m = gcd (n - m) m\n" -" | otherwise = gcd (m - n) n\n" +" | otherwise = gcd (m – n) n\n" #. type: Plain text -#: text/chapter10.md:1111 +#: text/chapter10.md:1113 msgid "" "This function finds the greatest common divisor of two numbers by repeated " "subtraction. It is a nice example of a case where you might like to use " @@ -4332,7 +4343,7 @@ msgstr "" "なっていますが、JavaScriptからそれを呼び出すためには条件があります。" #. type: Plain text -#: text/chapter10.md:1113 +#: text/chapter10.md:1115 msgid "" "To understand how this function can be called from JavaScript, it is " "important to realize that PureScript functions always get turned into " @@ -4344,7 +4355,7 @@ msgstr "" "していかなければならないということです。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1114 +#: text/chapter10.md:1116 #, no-wrap msgid "" "import Test from 'Test.js';\n" @@ -4354,20 +4365,20 @@ msgstr "" "Test.gcd(15)(20);\n" #. type: Plain text -#: text/chapter10.md:1120 +#: text/chapter10.md:1122 msgid "" -"Here, I am assuming that the code was compiled with `spago build`, which " -"compiles PureScript modules to ES modules. For that reason, I was able to " -"reference the `gcd` function on the `Test` object, after importing the " -"`Test` module using `import`." +"Here, I assume the code was compiled with `spago build`, which compiles " +"PureScript modules to ES modules. For that reason, I could reference the " +"`gcd` function on the `Test` object, after importing the `Test` module using " +"`import`." msgstr "" -"ここでは、コードがPureScriptモジュールをESモジュールにコンパイルする `spago " -"build`でコンパイルされていると仮定しています。そのため、 `import`を使って " -"`Test`モジュールをインポートした後、 `Test`オブジェクトの `gcd`関数を参照でき" -"ました。" +"ここでは`spago build`でコンパイルされていることを前提としています。\n" +"SpagoはPureScriptモジュールをESモジュールにコンパイルするものです。\n" +"そのため、`import`を使って`Test`モジュールをインポートした後、`Test`オブジェ" +"クトの`gcd`関数を参照できました。" #. type: Plain text -#: text/chapter10.md:1122 +#: text/chapter10.md:1124 msgid "" "You can also use the `spago bundle-app` and `spago bundle-module` commands " "to bundle your generated JavaScript into a single file. Consult [the " @@ -4380,25 +4391,26 @@ msgstr "" "spago#bundle-a-project-into-a-single-js-file)をあたってください。" #. type: Title ### -#: text/chapter10.md:1123 +#: text/chapter10.md:1125 #, no-wrap msgid "Understanding Name Generation" msgstr "名前の生成を理解する" #. type: Plain text -#: text/chapter10.md:1126 +#: text/chapter10.md:1128 msgid "" "PureScript aims to preserve names during code generation as much as " -"possible. In particular, most identifiers which are neither PureScript nor " +"possible. In particular, most identifiers that are neither PureScript nor " "JavaScript keywords can be expected to be preserved, at least for names of " "top-level declarations." msgstr "" -"PureScriptはコード生成時にできるだけ名前を保存することを目的としています。具" -"体的には、少なくともトップレベルで宣言される名前については、PureScriptや" -"JavaScriptのキーワードでなければほとんどの識別子が保存されます。" +"PureScriptはコード生成時にできるだけ名前を保持することを目指します。\n" +"とりわけ、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存" +"されることが期待できます。\n" +"少なくとも最上位で宣言される名前についてはそうです。" #. type: Plain text -#: text/chapter10.md:1128 +#: text/chapter10.md:1130 msgid "" "If you decide to use a JavaScript keyword as an identifier, the name will be " "escaped with a double dollar symbol. For example," @@ -4408,24 +4420,24 @@ msgstr "" "例えば次のPureScriptコードを考えてみます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1129 +#: text/chapter10.md:1131 #, no-wrap msgid "null = []\n" msgstr "null = []\n" #. type: Plain text -#: text/chapter10.md:1134 text/chapter10.md:1146 -msgid "generates the following JavaScript:" +#: text/chapter10.md:1136 text/chapter10.md:1148 +msgid "Generates the following JavaScript:" msgstr "これは以下のJavaScriptを生成します。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1135 +#: text/chapter10.md:1137 #, no-wrap msgid "var $$null = [];\n" msgstr "var $$null = [];\n" #. type: Plain text -#: text/chapter10.md:1140 +#: text/chapter10.md:1142 msgid "" "In addition, if you would like to use special characters in your identifier " "names, they will be escaped using a single dollar symbol. For example," @@ -4435,56 +4447,54 @@ msgstr "" "例えばこのPureScriptコードを考えます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1141 +#: text/chapter10.md:1143 #, no-wrap msgid "example' = 100\n" msgstr "example' = 100\n" #. type: Fenced code block (javascript) -#: text/chapter10.md:1147 +#: text/chapter10.md:1149 #, no-wrap msgid "var example$prime = 100;\n" msgstr "var example$prime = 100;\n" #. type: Plain text -#: text/chapter10.md:1152 +#: text/chapter10.md:1154 msgid "" "Where compiled PureScript code is intended to be called from JavaScript, it " -"is recommended that identifiers only use alphanumeric characters, and avoid " +"is recommended that identifiers only use alphanumeric characters and avoid " "JavaScript keywords. If user-defined operators are provided for use in " "PureScript code, it is good practice to provide an alternative function with " "an alphanumeric name for use in JavaScript." msgstr "" "コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図してい" -"る場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めし" -"ます。\n" -"ユーザ定義演算子がPureScriptコードでの使用のために提供される場合でも、" -"JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧め" -"します。" +"る場合、識別子は英数字のみを使用し、JavaScriptのキーワードを避けることをお勧" +"めします。\n" +"ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScript" +"から使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" #. type: Title ### -#: text/chapter10.md:1153 +#: text/chapter10.md:1155 #, no-wrap msgid "Runtime Data Representation" msgstr "実行時のデータ表現" #. type: Plain text -#: text/chapter10.md:1156 +#: text/chapter10.md:1158 msgid "" "Types allow us to reason at compile-time that our programs are \"correct\" " -"in some sense - that is, they will not break at runtime. But what does that " +"in some sense – that is, they will not break at runtime. But what does that " "mean? In PureScript, it means that the type of an expression should be " "compatible with its representation at runtime." msgstr "" -"型はプログラムがある意味で「正しい」ことをコンパイル時に判断できるようにしま" +"型はプログラムがある意味で「正しい」ことをコンパイル時に論証できるようにしま" "す。\n" "つまり、その点については壊れることがありません。\n" "しかし、これは何を意味するのでしょうか。\n" -"PureScriptでは式の型は実行時の表現と互換性がなければならないことを意味しま" -"す。" +"PureScriptでは、式の型は実行時の表現と互換性があることを意味します。" #. type: Plain text -#: text/chapter10.md:1158 +#: text/chapter10.md:1160 msgid "" "For that reason, it is important to understand the representation of data at " "runtime to be able to use PureScript and JavaScript code together " @@ -4498,7 +4508,7 @@ msgstr "" "うに評価されるかという挙動を理解できるべきだということです。" #. type: Plain text -#: text/chapter10.md:1160 +#: text/chapter10.md:1162 msgid "" "The good news is that PureScript expressions have particularly simple " "representations at runtime. It should always be possible to understand the " @@ -4508,7 +4518,7 @@ msgstr "" "型を考慮すれば式の実行時のデータ表現を把握することが常に可能です。" #. type: Plain text -#: text/chapter10.md:1162 +#: text/chapter10.md:1164 msgid "" "For simple types, the correspondence is almost trivial. For example, if an " "expression has the type `Boolean`, then its value `v` at runtime should " @@ -4525,62 +4535,61 @@ msgstr "" "特に`null`や `undefined`に評価される型`Boolean`なPureScriptの式はありません。" #. type: Plain text -#: text/chapter10.md:1164 +#: text/chapter10.md:1166 msgid "" -"A similar law holds for expressions of type `Int`, `Number`, and `String` - " +"A similar law holds for expressions of type `Int`, `Number`, and `String` – " "expressions of type `Int` or `Number` evaluate to non-null JavaScript " "numbers, and expressions of type `String` evaluate to non-null JavaScript " "strings. Expressions of type `Int` will evaluate to integers at runtime, " "even though they cannot be distinguished from values of type `Number` by " "using `typeof`." msgstr "" -"`Int`や`Number`や`String`の型の式についても同様のことが成り立ちます。\n" -"`Int`や`Number`型の式は `null`でないJavaScriptの数へと評価されますし、 " -"`String`型の式は `null`でないJavaScriptの文字列へと評価されます。\n" +"`Int`や`Number`や`String`の型の式についても似た法則が成り立ちます。\n" +"`Int`や`Number`型の式はnullでないJavaScriptの数へと評価されますし、`String`型" +"の式はnullでないJavaScriptの文字列へと評価されます。\n" "`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式" "は実行時に整数に評価されます。" #. type: Plain text -#: text/chapter10.md:1166 +#: text/chapter10.md:1168 msgid "" "What about `Unit`? Well, since `Unit` has only one inhabitant (`unit`) and " -"its value is not observable, it doesn't actually matter what it's " -"represented with at runtime. Old code tends to represent it using `{}`. " -"Newer code, however, tends to use `undefined`. So, although it doesn't " -"really matter what you use to represent `Unit`, it is recommended to use " -"`undefined` (not returning anything from a function also returns " -"`undefined`)." +"its value is not observable, it doesn't matter what it's represented with at " +"runtime. Old code tends to represent it using `{}`. Newer code, however, " +"tends to use `undefined`. So, although it doesn't matter what you use to " +"represent `Unit`, it is recommended to use `undefined` (not returning " +"anything from a function also returns `undefined`)." msgstr "" "`Unit`についてはどうでしょうか。\n" "`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何" "で表現されるかは重要ではありません。\n" "古いコードは`{}`を使って表現する傾向がありました。\n" "しかし比較的新しいコードでは`undefined`を使う傾向にあります。\n" -"なので、`Unit`を表現するのに使うものは本当に何でも問題にならないのですが、" +"なので、`Unit`を表現するのに使うものは何であれ差し支えありませんが、" "`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を" "返します)。" #. type: Plain text -#: text/chapter10.md:1168 +#: text/chapter10.md:1170 msgid "What about some more complex types?" msgstr "もっと複雑な型についてはどうでしょうか。" #. type: Plain text -#: text/chapter10.md:1170 +#: text/chapter10.md:1172 #, no-wrap -msgid "As we have already seen, PureScript functions correspond to JavaScript functions of a single argument. More precisely, if an expression `f` has type `a -> b` for some types `a` and `b`, and an expression `x` evaluates to a value with the correct runtime representation for type `a`, then `f` evaluates to a JavaScript function, which when applied to the result of evaluating `x`, has the correct runtime representation for type `b`. As a simple example, an expression of type `String -> String` evaluates to a function which takes non-null JavaScript strings to non-null JavaScript strings.\n" +msgid "As we have already seen, PureScript functions correspond to JavaScript functions of a single argument. More precisely, if an expression `f` has type `a -> b` for some types `a` and `b`, and an expression `x` evaluates to a value with the correct runtime representation for type `a`, then `f` evaluates to a JavaScript function, which, when applied to the result of evaluating `x`, has the correct runtime representation for type `b`. As a simple example, an expression of type `String -> String` evaluates to a function that takes non-null JavaScript strings to non-null JavaScript strings.\n" msgstr "" "既に見てきたように、PureScriptの関数は引数が1つのJavaScriptの関数に対応しています。\n" "厳密に言えばこうなります。\n" -"任意の型`a`と`b`について、式`f`の型が`a -> b`で、式`x`が型`a`についての適切な実行時表現の値へと評価されるとします。\n" -"このとき`f`はJavaScriptの関数へと評価され、`x`を評価した結果に`f`を適用すると型`b`の適切な実行時表現を持ちます。\n" -"簡単な例としては、 `String -> String`型の式は、 `null`でないJavaScript文字列から `null`でないJavaScript文字列への関数へと評価されます。\n" +"ある型`a`と`b`について、式`f`の型が`a -> b`で、式`x`が型`a`についての適切な実行時表現の値へと評価されるとします。\n" +"このとき`f`はJavaScriptの関数へと評価されますが、この関数は`x`を評価した結果に`f`を適用すると型`b`の適切な実行時表現を持ちます。\n" +"単純な例としては、`String -> String`型の式は、nullでないJavaScript文字列からnullでないJavaScript文字列への関数へと評価されます。\n" #. type: Plain text -#: text/chapter10.md:1172 +#: text/chapter10.md:1174 msgid "" "As you might expect, PureScript's arrays correspond to JavaScript arrays. " -"But remember - PureScript arrays are homogeneous, so every element has the " +"But remember – PureScript arrays are homogeneous, so every element has the " "same type. Concretely, if a PureScript expression `e` has type `Array a` for " "some type `a`, then `e` evaluates to a (non-null) JavaScript array, all of " "whose elements have the correct runtime representation for type `a`." @@ -4588,62 +4597,62 @@ msgstr "" "ご想像の通り、PureScriptの配列はJavaScriptの配列に対応しています。\n" "しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っているこ" "とは覚えておいてください。\n" -"具体的には、もしPureScriptの式 `e`が何らかの型 `a`について型 `Array a`を持つ" -"なら、 `e`は全ての要素が(`null`でない)型 `a`の適切な実行時表現を持った" -"JavaScript配列へと評価されます。" +"具体的には、もしPureScriptの式`e`が何らかの型`a`について型`Array a`を持つな" +"ら、`e`は(nullでない)JavaScript配列へと評価されます。\n" +"この配列の全ての要素は型`a`の適切な実行時表現を持ちます。" #. type: Plain text -#: text/chapter10.md:1174 +#: text/chapter10.md:1176 msgid "" "We've already seen that PureScript's records evaluate to JavaScript objects. " -"Just as for functions and arrays, we can reason about the runtime " -"representation of data in a record's fields by considering the types " -"associated with its labels. Of course, the fields of a record are not " -"required to be of the same type." +"As for functions and arrays, we can reason about the runtime representation " +"of data in a record's fields by considering the types associated with its " +"labels. Of course, the fields of a record are not required to be of the same " +"type." msgstr "" "PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てき" "ました。\n" -"ちょうど関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれ" -"ば、レコードのフィールドのデータの実行時の表現についても推論できます。\n" -"もちろん、レコードのそれぞれのフィールドは、同じ型である必要はありません。" +"関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レ" +"コードのフィールド中のデータの実行時の表現について論証できます。\n" +"勿論、レコードのフィールドは、同じ型である必要はありません。" #. type: Title ### -#: text/chapter10.md:1175 +#: text/chapter10.md:1177 #, no-wrap msgid "Representing ADTs" msgstr "ADTの表現" #. type: Plain text -#: text/chapter10.md:1178 +#: text/chapter10.md:1180 msgid "" "For every constructor of an algebraic data type, the PureScript compiler " "creates a new JavaScript object type by defining a function. Its " -"constructors correspond to functions which create new JavaScript objects " +"constructors correspond to functions that create new JavaScript objects " "based on those prototypes." msgstr "" -"PureScriptコンパイラは、代数的データ型の全ての構築子についてそれぞれを関数と" -"して定義し、新たなJavaScriptオブジェクト型を作成します。\n" -"これらの構築子は雛形に基づいて新しいJavaScriptオブジェクトを作成する関数に対" -"応しています。" +"代数的データ型の全ての構築子について、PureScriptコンパイラは関数を定義するこ" +"とで新たなJavaScriptオブジェクト型を作成します。\n" +"これらの構築子はプロトタイプに基づいて新しいJavaScriptオブジェクトを作成する" +"関数に対応しています。" #. type: Plain text -#: text/chapter10.md:1180 +#: text/chapter10.md:1182 msgid "For example, consider the following simple ADT:" msgstr "例えば次のような単純なADTを考えてみましょう。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1181 +#: text/chapter10.md:1183 #, no-wrap msgid "data ZeroOrOne a = Zero | One a\n" msgstr "data ZeroOrOne a = Zero | One a\n" #. type: Plain text -#: text/chapter10.md:1186 +#: text/chapter10.md:1188 msgid "The PureScript compiler generates the following code:" msgstr "PureScriptコンパイラは、次のようなコードを生成します。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1187 +#: text/chapter10.md:1189 #, no-wrap msgid "" "function One(value0) {\n" @@ -4673,20 +4682,20 @@ msgstr "" "Zero.value = new Zero();\n" #. type: Plain text -#: text/chapter10.md:1203 +#: text/chapter10.md:1205 msgid "" "Here, we see two JavaScript object types: `Zero` and `One`. It is possible " "to create values of each type by using JavaScript's `new` keyword. For " "constructors with arguments, the compiler stores the associated data in " "fields called `value0`, `value1`, etc." msgstr "" -"ここで2つのJavaScriptオブジェクト型 `Zero`と `One`を見てください。\n" -"JavaScriptのキーワード`new`を使用すると、それぞれの型の値を作成できます。\n" -"引数を持つ構築子については、コンパイラは `value0`、 `value1`などという名前の" +"ここで2つのJavaScriptオブジェクト型`Zero`と`One`を見てください。\n" +"JavaScriptのキーワード`new`を使用すると、各型の値を作成できます。\n" +"引数を持つ構築子については、コンパイラは`value0`、`value1`などという名前の" "フィールドに、対応するデータを格納します。" #. type: Plain text -#: text/chapter10.md:1205 +#: text/chapter10.md:1207 msgid "" "The PureScript compiler also generates helper functions. For constructors " "with no arguments, the compiler generates a `value` property, which can be " @@ -4702,32 +4711,32 @@ msgstr "" "築子を適用する `create`関数を生成します。" #. type: Plain text -#: text/chapter10.md:1207 +#: text/chapter10.md:1209 msgid "" "What about constructors with more than one argument? In that case, the " "PureScript compiler also creates a new object type, and a helper function. " -"This time, however, the helper function is curried function of two " +"This time, however, the helper function is a curried function of two " "arguments. For example, this algebraic data type:" msgstr "" -"2引数以上の構築子についてはどうでしょうか。\n" +"1引数より多く取る構築子についてはどうでしょうか。\n" "その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成しま" "す。\n" -"ここでは補助関数は2引数のカリー化された関数なのです。\n" +"ただしこの場合、補助関数は2引数のカリー化された関数です。\n" "例えば次のような代数的データ型を考えます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1208 +#: text/chapter10.md:1210 #, no-wrap msgid "data Two a b = Two a b\n" msgstr "data Two a b = Two a b\n" #. type: Plain text -#: text/chapter10.md:1213 -msgid "generates this JavaScript code:" +#: text/chapter10.md:1215 +msgid "Generates this JavaScript code:" msgstr "このコードからは、次のようなJavaScriptコードが生成されます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1214 +#: text/chapter10.md:1216 #, no-wrap msgid "" "function Two(value0, value1) {\n" @@ -4753,57 +4762,59 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:1228 +#: text/chapter10.md:1230 msgid "" -"Here, values of the object type `Two` can be created using the `new` " -"keyword, or by using the `Two.create` function." +"Here, values of the object type `Two` can be created using the `new` keyword " +"or by using the `Two.create` function." msgstr "" -"ここで、オブジェクト型 `Two`の値はキーワード`new`または `Two.create`関数を使" -"用すると作成できます。" +"ここで、オブジェクト型`Two`の値はキーワード`new`または`Two.create`関数を使用" +"すると作成できます。" #. type: Plain text -#: text/chapter10.md:1230 +#: text/chapter10.md:1232 msgid "" "The case of newtypes is slightly different. Recall that a newtype is like an " "algebraic data type, restricted to having a single constructor taking a " "single argument. In this case, the runtime representation of the newtype is " -"actually the same as the type of its argument." +"the same as its argument type." msgstr "" "newtypeの場合はまた少し異なります。\n" -"newtypeは単一の引数を取る単一の構築子を持つよう制限された代数的データ型である" -"ことを思い出してください。\n" -"この場合、実際のnewtypeの実行時表現は、その引数の型と同じになります。" +"newtypeは代数的データ型のようなもので、単一の引数を取る単一の構築子を持つよう" +"制限されていたことを思い出してください。\n" +"この場合、newtypeの実行時表現は、その引数の型と同じになります。" #. type: Plain text -#: text/chapter10.md:1232 -msgid "For example, this newtype representing telephone numbers:" -msgstr "例えば、電話番号を表す次のようなnewtypeを考えます。" +#: text/chapter10.md:1234 +msgid "" +"For example, this newtype represents telephone numbers is represented as a " +"JavaScript string at runtime:" +msgstr "" +"例えば、以下の電話番号を表すnewtypeは実行時にJavaScriptの文字列として表現され" +"ます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1233 +#: text/chapter10.md:1235 #, no-wrap msgid "newtype PhoneNumber = PhoneNumber String\n" msgstr "newtype PhoneNumber = PhoneNumber String\n" #. type: Plain text -#: text/chapter10.md:1238 +#: text/chapter10.md:1240 msgid "" -"is actually represented as a JavaScript string at runtime. This is useful " -"for designing libraries, since newtypes provide an additional layer of type " -"safety, but without the runtime overhead of another function call." +"This is useful for designing libraries since newtypes provide an additional " +"layer of type safety without the runtime overhead of another function call." msgstr "" -"これは実行時にJavaScriptの文字列として表されます。\n" -"newtypeは更なる型安全性のための層を提供しますが、実行時の関数呼び出しのオー" -"バーヘッドがないので、ライブラリを設計するのに役に立ちます。" +"newtypeは、関数呼び出しによる実行時のオーバーヘッドなく更なる型安全性のための" +"層を提供するため、ライブラリを設計するのに便利です。" #. type: Title ### -#: text/chapter10.md:1239 +#: text/chapter10.md:1241 #, no-wrap msgid "Representing Quantified Types" msgstr "量化された型の表現" #. type: Plain text -#: text/chapter10.md:1242 +#: text/chapter10.md:1244 msgid "" "Expressions with quantified (polymorphic) types have restrictive " "representations at runtime. In practice, there are relatively few " @@ -4815,18 +4826,18 @@ msgstr "" "的に推論できるのです。" #. type: Plain text -#: text/chapter10.md:1244 +#: text/chapter10.md:1246 msgid "Consider this polymorphic type, for example:" msgstr "例えば、次の多相型を考えてみます。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1245 +#: text/chapter10.md:1247 #, no-wrap msgid "forall a. a -> a\n" msgstr "forall a. a -> a\n" #. type: Plain text -#: text/chapter10.md:1250 +#: text/chapter10.md:1252 msgid "" "What sort of functions have this type? Well, there is certainly one function " "with this type:" @@ -4835,7 +4846,7 @@ msgstr "" "実は少なくとも1つ、この型を持つ関数が存在します。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1251 +#: text/chapter10.md:1253 #, no-wrap msgid "" "identity :: forall a. a -> a\n" @@ -4845,13 +4856,13 @@ msgstr "" "identity a = a\n" #. type: Plain text -#: text/chapter10.md:1257 +#: text/chapter10.md:1259 #, no-wrap msgid "> Note that the actual [`identity`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Category#v:identity) function defined in `Prelude` has a slightly different type.\n" msgstr "> なお、`Prelude`に定義された実際の[`identity`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Category#v:identity)関数は僅かに違った型を持ちます。\n" #. type: Plain text -#: text/chapter10.md:1259 +#: text/chapter10.md:1261 msgid "" "In fact, the `identity` function is the _only_ (total) function with this " "type! This certainly seems to be the case (try writing an expression with " @@ -4865,31 +4876,31 @@ msgstr "" "型の実行時表現を考えることによって確かめられます。" #. type: Plain text -#: text/chapter10.md:1261 +#: text/chapter10.md:1263 #, no-wrap msgid "What is the runtime representation of a quantified type `forall a. t`? Well, any expression with the runtime representation for this type must have the correct runtime representation for the type `t` for any choice of type `a`. In our example above, a function of type `forall a. a -> a` must have the correct runtime representation for the types `String -> String`, `Number -> Number`, `Array Boolean -> Array Boolean`, and so on. It must take strings to strings, numbers to numbers, etc.\n" msgstr "量化された型 `forall a. t`の実行時表現はどうなっているのでしょうか。さて、この型の実行時表現を持つ任意の式は、型 `a`をどのように選んでも型 `t`の適切な実行時表現を持っていなければなりません。上の例では、型 `forall a. a -> a`の関数は、 `String -> String`、 `Number -> Number`、 `Array Boolean -> Array Boolean`などといった型について、適切な実行時表現を持っていなければなりません。 これらは、文字列から文字列、数から数の関数でなくてはなりません。\n" #. type: Plain text -#: text/chapter10.md:1263 +#: text/chapter10.md:1265 msgid "" -"But that is not enough - the runtime representation of a quantified type is " +"But that is not enough – the runtime representation of a quantified type is " "more strict than this. We require any expression to be _parametrically " -"polymorphic_ - that is, it cannot use any information about the type of its " +"polymorphic_ – that is, it cannot use any information about the type of its " "argument in its implementation. This additional condition prevents " "problematic implementations such as the following JavaScript function from " "inhabiting a polymorphic type:" msgstr "" "しかし、それだけでは充分ではありません。\n" -"量化された型の実行時表現は、これよりも更に厳しくなります。\n" -"任意の式が*パラメトリック多相的*でなければなりません。\n" +"量化された型の実行時表現は、これよりも更に厳しいものです。\n" +"任意の式が*パラメトリック多相的*であることを要求しています。\n" "つまり、その実装において、引数の型についてのどんな情報も使うことができないの" "です。\n" -"この追加の条件は、考えられる多相型のうち、以下のJavaScriptの関数のような問題" -"のある実装を防止します。" +"この追加の条件は、以下のJavaScriptの関数のような問題のある実装が多相型に現住" +"することを防止します。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1264 +#: text/chapter10.md:1266 #, no-wrap msgid "" "function invalid(a) {\n" @@ -4909,27 +4920,30 @@ msgstr "" "}\n" #. type: Plain text -#: text/chapter10.md:1275 +#: text/chapter10.md:1277 #, no-wrap -msgid "Certainly, this function takes strings to strings, numbers to numbers, etc. but it does not meet the additional condition, since it inspects the (runtime) type of its argument, so this function would not be a valid inhabitant of the type `forall a. a -> a`.\n" +msgid "Certainly, this function takes strings to strings, numbers to numbers, etc. But it does not meet the additional condition, since it inspects the (runtime) type of its argument, so this function would not be a valid inhabitant of the type `forall a. a -> a`.\n" msgstr "" -"確かにこの関数は文字列から文字列、数から数へというような関数ではありますが、追加条件を満たしていません。\n" -"引数の実行時の型を調べており、したがって、この関数は型 `forall a. a -> a`の正しい実装だとはいえないのです。\n" +"確かにこの関数は文字列を取って文字列を返し、数を取って数を返す、といったものです。\n" +"しかしこの関数は追加条件を満たしていません。\n" +"引数の実行時の型を調べており、型`forall a. a -> a`の正しい現住にはならないからです。\n" #. type: Plain text -#: text/chapter10.md:1277 +#: text/chapter10.md:1279 #, no-wrap -msgid "Without being able to inspect the runtime type of our function argument, our only option is to return the argument unchanged, and so `identity` is indeed the only inhabitant of the type `forall a. a -> a`.\n" -msgstr "関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけであり、したがって `id`はたしかに `forall a. a -> a`の唯一の実装なのです。\n" +msgid "Without being able to inspect the runtime type of our function argument, our only option is to return the argument unchanged. So `identity` is indeed the only inhabitant of the type `forall a. a -> a`.\n" +msgstr "" +"関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけです。\n" +"したがって`id`は確かに`forall a. a -> a`の唯一の現住なのです。\n" #. type: Plain text -#: text/chapter10.md:1279 +#: text/chapter10.md:1281 msgid "" "A full discussion of _parametric polymorphism_ and _parametricity_ is beyond " -"the scope of this book. Note however, that since PureScript's types are " +"the scope of this book. Note, however, that since PureScript's types are " "_erased_ at runtime, a polymorphic function in PureScript _cannot_ inspect " -"the runtime representation of its arguments (without using the FFI), and so " -"this representation of polymorphic data is appropriate." +"the runtime representation of its arguments (without using the FFI), so this " +"representation of polymorphic data is appropriate." msgstr "" "*パラメトリック多相*と*パラメトリック性*についての詳しい議論は本書の範囲を超" "えています。\n" @@ -4938,16 +4952,16 @@ msgstr "" "が適切になっているという点にはご留意ください。" #. type: Title ### -#: text/chapter10.md:1280 +#: text/chapter10.md:1282 #, no-wrap msgid "Representing Constrained Types" msgstr "制約のある型の表現" #. type: Plain text -#: text/chapter10.md:1283 +#: text/chapter10.md:1285 msgid "" "Functions with a type class constraint have an interesting representation at " -"runtime. Because the behavior of the function might depend on the type class " +"runtime. Because the function's behavior might depend on the type class " "instance chosen by the compiler, the function is given an additional " "argument, called a _type class dictionary_, which contains the " "implementation of the type class functions provided by the chosen instance." @@ -4959,16 +4973,16 @@ msgstr "" "す。" #. type: Plain text -#: text/chapter10.md:1285 +#: text/chapter10.md:1287 msgid "" "For example, here is a simple PureScript function with a constrained type " -"which uses the `Show` type class:" +"that uses the `Show` type class:" msgstr "" -"例えば、 `Show`型クラスを使った制約のある型を持つ、次のような単純なPureScript" -"関数について考えます。" +"例えば以下は、`Show`型クラスを使う制約付きの型を持つ、単純なPureScript関数で" +"す。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1286 +#: text/chapter10.md:1288 #, no-wrap msgid "" "shout :: forall a. Show a => a -> String\n" @@ -4978,12 +4992,12 @@ msgstr "" "shout a = show a <> \"!!!\"\n" #. type: Plain text -#: text/chapter10.md:1292 +#: text/chapter10.md:1294 msgid "The generated JavaScript looks like this:" msgstr "生成されるJavaScriptは次のようになります。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1293 +#: text/chapter10.md:1295 #, no-wrap msgid "" "var shout = function (dict) {\n" @@ -4999,7 +5013,7 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:1302 +#: text/chapter10.md:1304 msgid "" "Notice that `shout` is compiled to a (curried) function of two arguments, " "not one. The first argument `dict` is the type class dictionary for the " @@ -5011,7 +5025,7 @@ msgstr "" "`dict`には型 `a`の `show`関数の実装が含まれています。" #. type: Plain text -#: text/chapter10.md:1304 +#: text/chapter10.md:1306 msgid "" "We can call this function from JavaScript by passing an explicit type class " "dictionary from `Data.Show` as the first parameter:" @@ -5020,7 +5034,7 @@ msgstr "" "関数を呼び出すことができます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1305 +#: text/chapter10.md:1307 #, no-wrap msgid "" "import { showNumber } from 'Data.Show'\n" @@ -5032,12 +5046,12 @@ msgstr "" "shout(showNumber)(42);\n" #. type: Bullet: ' 1. ' -#: text/chapter10.md:1314 +#: text/chapter10.md:1316 msgid "(Easy) What are the runtime representations of these types?" msgstr "(簡単)これらの型の実行時の表現は何でしょうか。" #. type: Plain text -#: text/chapter10.md:1320 +#: text/chapter10.md:1322 #, no-wrap msgid "" " ```haskell\n" @@ -5053,7 +5067,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter10.md:1323 +#: text/chapter10.md:1325 #, no-wrap msgid "" " What can you say about the expressions which have these types?\n" @@ -5064,27 +5078,27 @@ msgstr "" " *手掛かり*:生成されたCommonJSモジュールがNodeJSモジュールのパスで使用できるように、出力パスを設定する必要があります。\n" #. type: Title ### -#: text/chapter10.md:1324 +#: text/chapter10.md:1326 #, no-wrap msgid "Representing Side Effects" msgstr "副作用の表現" #. type: Plain text -#: text/chapter10.md:1327 +#: text/chapter10.md:1329 msgid "" "The `Effect` monad is also defined as a foreign type. Its runtime " -"representation is quite simple - an expression of type `Effect a` should " +"representation is quite simple – an expression of type `Effect a` should " "evaluate to a JavaScript function of **no arguments**, which performs any " "side-effects and returns a value with the correct runtime representation for " "type `a`." msgstr "" "`Effect`モナドも外部型として定義されています。\n" -"その実行時表現はとても簡単です。\n" -"型 `Effect a`の式は**引数なしの**JavaScript関数へと評価されます。\n" -"この関数はあらゆる副作用を実行し型 `a`の適切な実行時表現で値を返します。" +"その実行時表現はとても単純です。\n" +"型`Effect a`の式は**引数なしの**JavaScript関数へと評価されます。\n" +"この関数はあらゆる副作用を実行し、型`a`の適切な実行時表現を持つ値を返します。" #. type: Plain text -#: text/chapter10.md:1329 +#: text/chapter10.md:1331 msgid "" "The definition of the `Effect` type constructor is given in the `Effect` " "module as follows:" @@ -5092,13 +5106,13 @@ msgstr "" "`Effect`型構築子の定義は、 `Effect`モジュールで次のように与えられています。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1330 +#: text/chapter10.md:1332 #, no-wrap msgid "foreign import data Effect :: Type -> Type\n" msgstr "foreign import data Effect :: Type -> Type\n" #. type: Plain text -#: text/chapter10.md:1335 +#: text/chapter10.md:1337 msgid "" "As a simple example, consider the `random` function defined in the `random` " "package. Recall that its type was:" @@ -5107,38 +5121,38 @@ msgstr "" "さい。その型は次のようなものでした。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1336 +#: text/chapter10.md:1338 #, no-wrap msgid "foreign import random :: Effect Number\n" msgstr "foreign import random :: Effect Number\n" #. type: Plain text -#: text/chapter10.md:1341 +#: text/chapter10.md:1343 msgid "The definition of the `random` function is given here:" msgstr "`random`関数の定義は次のように与えられます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1342 +#: text/chapter10.md:1344 #, no-wrap msgid "export const random = Math.random;\n" msgstr "export const random = Math.random;\n" #. type: Plain text -#: text/chapter10.md:1347 +#: text/chapter10.md:1349 msgid "" "Notice that the `random` function is represented at runtime as a function of " -"no arguments. It performs the side effect of generating a random number, and " +"no arguments. It performs the side effect of generating a random number, " "returns it, and the return value matches the runtime representation of the " "`Number` type: it is a non-null JavaScript number." msgstr "" "`random`関数は実行時には引数なしの関数として表現されていることに注目してくだ" "さい。\n" -"この関数は乱数生成という副作用を実行して返しますが、返り値は `Number`型の実行" +"この関数は乱数生成という副作用を実行して返しますが、返り値は`Number`型の実行" "時表現と一致します。\n" -"`Number`型は`null`でないJavaScriptの数です。" +"`Number`型はnullでないJavaScriptの数です。" #. type: Plain text -#: text/chapter10.md:1349 +#: text/chapter10.md:1351 msgid "" "As a slightly more interesting example, consider the `log` function defined " "by the `Effect.Console` module in the `console` package. The `log` function " @@ -5148,18 +5162,18 @@ msgstr "" "定義された `log`関数を考えてみましょう。 `log`関数は次の型を持っています。" #. type: Fenced code block (haskell) -#: text/chapter10.md:1350 +#: text/chapter10.md:1352 #, no-wrap msgid "foreign import log :: String -> Effect Unit\n" msgstr "foreign import log :: String -> Effect Unit\n" #. type: Plain text -#: text/chapter10.md:1355 +#: text/chapter10.md:1357 msgid "And here is its definition:" msgstr "この定義は次のようになっています。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1356 +#: text/chapter10.md:1358 #, no-wrap msgid "" "export const log = function (s) {\n" @@ -5175,17 +5189,18 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:1365 +#: text/chapter10.md:1367 msgid "" "The representation of `log` at runtime is a JavaScript function of a single " "argument, returning a function of no arguments. The inner function performs " "the side-effect of writing a message to the console." msgstr "" "実行時の `log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返しま" -"す。内側の関数はコンソールにメッセージを書き込むという副作用を実行します。" +"す。\n" +"内側の関数はコンソールに文言を書き込むという副作用を実行します。" #. type: Plain text -#: text/chapter10.md:1367 +#: text/chapter10.md:1369 msgid "" "Expressions of type `Effect a` can be invoked from JavaScript like regular " "JavaScript methods. For example, since the `main` function is required to " @@ -5196,7 +5211,7 @@ msgstr "" "う型でなければならないので、次のように実行できます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1368 +#: text/chapter10.md:1370 #, no-wrap msgid "" "import { main } from 'Main'\n" @@ -5208,13 +5223,13 @@ msgstr "" "main();\n" #. type: Plain text -#: text/chapter10.md:1374 +#: text/chapter10.md:1376 msgid "" "When using `spago bundle-app --to` or `spago run`, this call to `main` is " -"generated automatically, whenever the `Main` module is defined." +"generated automatically whenever the `Main` module is defined." msgstr "" -"`spago bundle-app --to`または `spago run`を使用するときは、`Main`モジュールが" -"定義されている場合は常に、この `main`の呼び出しを自動的に生成できます。" +"`spago bundle-app --to`または`spago run`を使用する場合、`Main`モジュールが定" +"義されている場合は常に、この`main`の呼び出しを自動的に生成できます。" #. type: Title # #: text/chapter11.md:1 @@ -5227,15 +5242,15 @@ msgstr "モナドな冒険" msgid "" "The goal of this chapter will be to learn about _monad transformers_, which " "provide a way to combine side-effects provided by different monads. The " -"motivating example will be a text adventure game which can be played on the " +"motivating example will be a text adventure game that can be played on the " "console in NodeJS. The various side-effects of the game (logging, state, and " "configuration) will all be provided by a monad transformer stack." msgstr "" "この章の目標は*モナド変換子*について学ぶことです。\n" "モナド変換子は異なるモナドから提供された副作用を合成する方法を提供します。\n" -"NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームを題材とし" -"て扱います。\n" -"ゲームの様々な副作用(ロギング、状態、及び設定)が全てモナド変換子スタックに" +"動機付けとする例は、NodeJSのコンソール上で遊ぶことができるテキストアドベン" +"チャーゲームです。\n" +"ゲームの様々な副作用(ロギング、状態、及び構成)が全てモナド変換子スタックに" "よって提供されます。" #. type: Plain text @@ -5267,10 +5282,10 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter11.md:15 msgid "" -"`optparse`, which provides applicative parsers for processing command line " +"`optparse`, which provides applicative parsers for processing command-line " "arguments" msgstr "" -"`optparse` はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" +"`optparse`はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" #. type: Title ## #: text/chapter11.md:16 @@ -5285,8 +5300,8 @@ msgstr "プロジェクトを走らせるには`spago run`を使います。" #. type: Plain text #: text/chapter11.md:21 -msgid "By default you will see a usage message:" -msgstr "既定では使い方が表示されます。" +msgid "By default, you will see a usage message:" +msgstr "既定では使い方の文言が表示されます。" #. type: Fenced code block (text) #: text/chapter11.md:22 @@ -5315,20 +5330,25 @@ msgstr "" " -h,--help Show this help text\n" #. type: Plain text -#: text/chapter11.md:35 -#, no-wrap -msgid "To provide command line arguments, you can either call `spago run` with the `-a` option to pass additional arguments directly to your application, or you can call `spago bundle-app`, which will create an index.js file that can be run directly with `node`. \n" +#: text/chapter11.md:36 +msgid "" +"To provide command line arguments, you can either call `spago run` with the " +"`-a` option to pass additional arguments directly to your application or " +"call `spago bundle-app`, which will create an index.js file that can be run " +"directly with `node`." msgstr "" -"コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-a`オプション付きで`spago run`を呼び出すか、`spago bundle-app`とすればよいです。\n" -"2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。\n" +"コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-" +"a`オプション付きで`spago run`を呼び出すか、`spago bundle-app`とすればよいで" +"す。\n" +"2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。" #. type: Plain text -#: text/chapter11.md:37 +#: text/chapter11.md:38 msgid "For example, to provide the player name using the `-p` option:" msgstr "例えば`-p`オプションを使ってプレイヤー名を与えるには次のようにします。" #. type: Fenced code block (text) -#: text/chapter11.md:38 +#: text/chapter11.md:39 #, no-wrap msgid "" "$ spago run -a \"-p Phil\"\n" @@ -5338,7 +5358,7 @@ msgstr "" ">\n" #. type: Fenced code block (text) -#: text/chapter11.md:43 +#: text/chapter11.md:44 #, no-wrap msgid "" "$ spago bundle-app \n" @@ -5350,41 +5370,40 @@ msgstr "" ">\n" #. type: Plain text -#: text/chapter11.md:50 +#: text/chapter11.md:51 msgid "" "From the prompt, you can enter commands like `look`, `inventory`, `take`, " "`use`, `north`, `south`, `east`, and `west`. There is also a `debug` " -"command, which can be used to print the game state when the `--debug` " -"command line option is provided." +"command, which can print the game state when the `--debug` command line " +"option is provided." msgstr "" -"プロンプトからは、 `look`、 `inventory`、 `take`、 `use`、 `north`、" -"`south`、 `east`、 `west`などのコマンドを入力できます。\n" +"プロンプトからは、`look`、`inventory`、`take`、`use`、`north`、`south`、" +"`east`、`west`などのコマンドを入力できます。\n" "`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合" -"に、ゲームの状態を出力するのに使えます。" +"に、ゲームの状態を出力できます。" #. type: Plain text -#: text/chapter11.md:52 +#: text/chapter11.md:53 msgid "" "The game is played on a two-dimensional grid, and the player moves by " "issuing commands `north`, `south`, `east`, and `west`. The game contains a " -"collection of items which can either be in the player's possession (in the " -"user's _inventory_), or on the game grid at some location. Items can be " -"picked up by the player, using the `take` command." -msgstr "" -"ゲームは2次元の碁盤の目の上が舞台で、コマンド `north`、 `south`、`east`、 " -"`west`を発行することによってプレイヤーが移動します。\n" -"ゲームにはアイテムの集まりがあり、プレイヤーの所持アイテム一覧を表したり、" -"ゲーム盤上のその位置にあるアイテムの一覧を表すのに使われます。\n" -"`take`コマンドを使うと、プレイヤーの位置にあるアイテムを拾い上げることができ" -"ます。" +"collection of items that can either be in the player's possession (in the " +"user's _inventory_) or on the game grid at some location. Items can be " +"picked up by the player using the `take` command." +msgstr "" +"ゲームは2次元の碁盤の目の上が舞台で、コマンド`north`、`south`、`east`、`west`" +"を発行することによってプレイヤーが移動します。\n" +"ゲームにはアイテムの集まりがあり、プレイヤーの所有物であったり、ゲームの盤上" +"の特定の位置にあったりします。\n" +"`take`コマンドを使うと、プレイヤーはアイテムを拾い上げられます。" #. type: Plain text -#: text/chapter11.md:54 +#: text/chapter11.md:55 msgid "For reference, here is a complete walkthrough of the game:" msgstr "参考までに、このゲームのひと通りの流れは次のようになります。" #. type: Fenced code block (text) -#: text/chapter11.md:55 +#: text/chapter11.md:56 #, no-wrap msgid "" "$ spago run -a \"-p Phil\"\n" @@ -5444,23 +5463,24 @@ msgstr "" "You win!\n" #. type: Plain text -#: text/chapter11.md:86 +#: text/chapter11.md:87 msgid "" "The game is very simple, but the aim of the chapter is to use the " -"`transformers` package to build a library which will enable rapid " -"development of this type of game." +"`transformers` package to build a library that will enable rapid development " +"of this type of game." msgstr "" -"このゲームはとても単純ですが、この章の目的は `transformers`パッケージを使用し" -"てこのようなゲームを素早く開発できるようにするライブラリを構築することです。" +"このゲームはとても単純ですが、この章の目的は`transformers`パッケージを使用し" +"てこのような種類のゲームを素早く開発できるようにするライブラリを構築すること" +"です。" #. type: Title ## -#: text/chapter11.md:87 +#: text/chapter11.md:88 #, no-wrap msgid "The State Monad" msgstr "Stateモナド" #. type: Plain text -#: text/chapter11.md:90 +#: text/chapter11.md:91 msgid "" "We will start by looking at some of the monads provided by the " "`transformers` package." @@ -5469,10 +5489,10 @@ msgstr "" "しょう。" #. type: Plain text -#: text/chapter11.md:92 +#: text/chapter11.md:93 msgid "" "The first example is the `State` monad, which provides a way to model " -"_mutable state_ in pure code. We have already seen an approach to mutable " +"_mutable state_ in pure code. We have already seen an approach to a mutable " "state provided by the `Effect` monad. `State` provides an alternative." msgstr "" "最初の例は`State`モナドです。\n" @@ -5482,25 +5502,25 @@ msgstr "" "`State`はその代替を提供します。" #. type: Plain text -#: text/chapter11.md:94 +#: text/chapter11.md:95 msgid "" "The `State` type constructor takes two type parameters: the type `s` of the " -"state, and the return type `a`. Even though we speak of the \"`State` " +"state and the return type `a`. Even though we speak of the \"`State` " "monad\", the instance of the `Monad` type class is actually provided for the " -"`State s` type constructor, for any type `s`." +"`State s` type constructor for any type `s`." msgstr "" -"`State`型構築子は、状態の型 `s`、及び返り値の型 `a`という2種類の引数を取りま" +"`State`型構築子は、状態の型`s`、及び返り値の型`a`という2種類の引数を取りま" "す。\n" "「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのイ" -"ンスタンスが任意の型`s`についての `State s`型構築子に対して提供されています。" +"ンスタンスが任意の型`s`についての`State s`型構築子に対して提供されています。" #. type: Plain text -#: text/chapter11.md:96 +#: text/chapter11.md:97 msgid "The `Control.Monad.State` module provides the following API:" msgstr "`Control.Monad.State`モジュールは以下のAPIを提供しています。" #. type: Fenced code block (haskell) -#: text/chapter11.md:97 +#: text/chapter11.md:98 #, no-wrap msgid "" "get :: forall s. State s s\n" @@ -5516,36 +5536,37 @@ msgstr "" "modify_ :: forall s. (s -> s) -> State s Unit\n" #. type: Plain text -#: text/chapter11.md:106 +#: text/chapter11.md:107 msgid "" "Note that these API signatures are presented in a simplified form using the " -"`State` type constructor for now. The actual API involves `MonadState` which " -"we'll cover in the later \"Type Classes\" section of this chapter, so don't " -"worry if you see different signatures in your IDE tooltips or on Pursuit." +"`State` type constructor for now. The actual API involves `MonadState`, " +"which we'll cover in the later \"Type Classes\" section of this chapter, so " +"don't worry if you see different signatures in your IDE tooltips or on " +"Pursuit." msgstr "" -"なおここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式" -"で表されています。\n" +"なお、ここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形" +"式で表されています。\n" "実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきま" "す。\n" "ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないで" "ください。" #. type: Plain text -#: text/chapter11.md:108 +#: text/chapter11.md:109 msgid "" "Let's see an example. One use of the `State` monad might be to add the " "values in an array of integers to the current state. We could do that by " -"choosing `Int` as the state type `s`, and using `traverse_` to traverse the " +"choosing `Int` as the state type `s` and using `traverse_` to traverse the " "array, with a call to `modify` for each array element:" msgstr "" "例を見てみましょう。\n" -"`State`モナドの使いかたの1つとしては、整数の配列中の値を現在の状態に加えるも" -"のが考えられます。\n" -"状態の型`s`として`Int`を選択し、配列の走査に `traverse_`を使って、配列の要素" -"それぞれについて `modify`を呼び出すと、これを実現できます。" +"`State`モナドの使い方の1つとしては、整数の配列中の値を現在の状態に加えるもの" +"が考えられます。\n" +"状態の型`s`として`Int`を選択し、配列の走査に`traverse_`を使い、配列の各要素に" +"ついて`modify`を呼び出すと、これを実現できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:109 +#: text/chapter11.md:110 #, no-wrap msgid "" "import Data.Foldable (traverse_)\n" @@ -5563,7 +5584,7 @@ msgstr "" "sumArray = traverse_ \\n -> modify \\sum -> sum + n\n" #. type: Plain text -#: text/chapter11.md:119 +#: text/chapter11.md:120 msgid "" "The `Control.Monad.State` module provides three functions for running a " "computation in the `State` monad:" @@ -5572,7 +5593,7 @@ msgstr "" "を提供します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:120 +#: text/chapter11.md:121 #, no-wrap msgid "" "evalState :: forall s a. State s a -> s -> a\n" @@ -5584,19 +5605,19 @@ msgstr "" "runState :: forall s a. State s a -> s -> Tuple a s\n" #. type: Plain text -#: text/chapter11.md:127 +#: text/chapter11.md:128 msgid "" -"Each of these functions takes an initial state of type `s` and a computation " -"of type `State s a`. `evalState` only returns the return value, `execState` " -"only returns the final state, and `runState` returns both, expressed as a " -"value of type `Tuple a s`." +"Each function takes an initial state of type `s` and a computation of type " +"`State s a`. `evalState` only returns the return value, `execState` only " +"returns the final state, and `runState` returns both, expressed as a value " +"of type `Tuple a s`." msgstr "" -"3つの関数はそれぞれ型`s`の初期状態と型`State s a`の計算を引数にとります。\n" -"`evalState`は返り値だけを返し、 `execState`は最終的な状態だけを返し、 " -"`runState`は `Tuple a s`型の値として表現された両方を返します。" +"3つの各関数は型`s`の初期状態と型`State s a`の計算を引数に取ります。\n" +"`evalState`は返り値だけを返し、`execState`は最終的な状態だけを返し、" +"`runState`は`Tuple a s`型の値として表現された両方を返します。" #. type: Plain text -#: text/chapter11.md:129 +#: text/chapter11.md:130 msgid "" "Given the `sumArray` function above, we could use `execState` in PSCi to sum " "the numbers in several arrays as follows:" @@ -5605,7 +5626,7 @@ msgstr "" "うに複数の配列内の数字を合計できます。" #. type: Fenced code block (text) -#: text/chapter11.md:130 +#: text/chapter11.md:131 #, no-wrap msgid "" "> :paste\n" @@ -5633,15 +5654,16 @@ msgstr "" "(簡単)上の例で、`execState`を`runState`や`evalState`で置き換えると結果はど" "うなるでしょうか。" -#. type: Plain text +#. type: Bullet: ' 1. ' #: text/chapter11.md:145 -#, no-wrap msgid "" -" 1. (Medium) A string of parentheses is _balanced_ if it is obtained by either concatenating zero-or-more shorter balanced\n" -" strings, or by wrapping a shorter balanced string in a pair of parentheses.\n" +"(Medium) A string of parentheses is _balanced_ if it is obtained by either " +"concatenating zero-or-more shorter balanced strings or wrapping a shorter " +"balanced string in a pair of parentheses." msgstr "" -"1. (普通)括弧からなる文字列について、次の何れかであれば*平衡している*とします。\n" -" 1つは0個以上のより短い平衡した文字列を連結したもので、もう1つはより短い平衡した文字列を一対の括弧で囲んだものです。\n" +"(普通)括弧からなる文字列が*平衡している*のは、0個以上のより短い平衡した文字" +"列を連結したものか、より短い平衡した文字列を一対の括弧で囲んだものかの何れか" +"です。" #. type: Plain text #: text/chapter11.md:147 @@ -5662,18 +5684,15 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:154 +#: text/chapter11.md:153 #, no-wrap -msgid "" -" which tests whether or not a `String` of parentheses is balanced, by keeping track of the number of opening parentheses\n" -" which have not been closed. Your function should work as follows:\n" +msgid " which tests whether or not a `String` of parentheses is balanced by keeping track of the number of opening parentheses that have not been closed. Your function should work as follows:\n" msgstr "" -" これは `String`が括弧の対応が正しく付けられているかどうかを調べる関数です。\n" -" 調べるにはまだ閉じられていない開括弧の数を把握しておきます。\n" -" この関数は次のように動作しなくてはなりません。\n" +" これは、まだ閉じられていない開括弧の数を把握することで、括弧の`String`が平衡しているかどうかを調べる関数です。\n" +" この関数は次のように動作します。\n" #. type: Plain text -#: text/chapter11.md:158 +#: text/chapter11.md:157 #, no-wrap msgid "" " ```text\n" @@ -5685,7 +5704,7 @@ msgstr "" " true\n" #. type: Plain text -#: text/chapter11.md:161 +#: text/chapter11.md:160 #, no-wrap msgid "" " > testParens \"(()(())())\"\n" @@ -5695,7 +5714,7 @@ msgstr "" " true\n" #. type: Plain text -#: text/chapter11.md:164 +#: text/chapter11.md:163 #, no-wrap msgid "" " > testParens \")\"\n" @@ -5705,7 +5724,7 @@ msgstr "" " false\n" #. type: Plain text -#: text/chapter11.md:168 +#: text/chapter11.md:167 #, no-wrap msgid "" " > testParens \"(()()\"\n" @@ -5717,19 +5736,19 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:170 +#: text/chapter11.md:169 #, no-wrap msgid " _Hint_: you may like to use the `toCharArray` function from the `Data.String.CodeUnits` module to turn the input string into an array of characters.\n" msgstr " *手掛かり*:入力の文字列を文字の配列に変換するのに、`Data.String.CodeUnits`モジュールの `toCharArray`関数を使うと良いでしょう。\n" #. type: Title ## -#: text/chapter11.md:171 +#: text/chapter11.md:170 #, no-wrap msgid "The Reader Monad" msgstr "Readerモナド" #. type: Plain text -#: text/chapter11.md:174 +#: text/chapter11.md:173 msgid "" "Another monad provided by the `transformers` package is the `Reader` monad. " "This monad provides the ability to read from a global configuration. Whereas " @@ -5743,7 +5762,7 @@ msgstr "" "ナドは1つのデータの読み取り機能だけを提供します。" #. type: Plain text -#: text/chapter11.md:176 +#: text/chapter11.md:175 msgid "" "The `Reader` type constructor takes two type arguments: a type `r` which " "represents the configuration type, and the return type `a`." @@ -5752,12 +5771,12 @@ msgstr "" "ります。" #. type: Plain text -#: text/chapter11.md:178 +#: text/chapter11.md:177 msgid "The `Control.Monad.Reader` module provides the following API:" msgstr "`Control.Monad.Reader`モジュールは以下のAPIを提供します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:179 +#: text/chapter11.md:178 #, no-wrap msgid "" "ask :: forall r. Reader r r\n" @@ -5767,17 +5786,17 @@ msgstr "" "local :: forall r a. (r -> r) -> Reader r a -> Reader r a\n" #. type: Plain text -#: text/chapter11.md:185 +#: text/chapter11.md:184 msgid "" "The `ask` action can be used to read the current configuration, and the " "`local` action can be used to run a computation with a modified " "configuration." msgstr "" -"`ask`アクションは現在の設定を読み取るために使い、 `local`アクションは変更され" -"た設定で計算するために使います。" +"`ask`動作は現在の設定を読み取るために使い、`local`動作は変更された設定で計算" +"するために使います。" #. type: Plain text -#: text/chapter11.md:187 +#: text/chapter11.md:186 msgid "" "For example, suppose we were developing an application controlled by " "permissions, and we wanted to use the `Reader` monad to hold the current " @@ -5789,7 +5808,7 @@ msgstr "" "型 `r`を次のようなAPIを備えた型 `Permission`として選択できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:188 +#: text/chapter11.md:187 #, no-wrap msgid "" "hasPermission :: String -> Permissions -> Boolean\n" @@ -5799,7 +5818,7 @@ msgstr "" "addPermission :: String -> Permissions -> Permissions\n" #. type: Plain text -#: text/chapter11.md:194 +#: text/chapter11.md:193 msgid "" "Whenever we wanted to check if the user had a particular permission, we " "could use `ask` to retrieve the current permissions object. For example, " @@ -5810,7 +5829,7 @@ msgstr "" "例えば管理者だけが新しい利用者の作成を許可されているとしましょう。" #. type: Fenced code block (haskell) -#: text/chapter11.md:195 +#: text/chapter11.md:194 #, no-wrap msgid "" "createUser :: Reader Permissions (Maybe User)\n" @@ -5828,16 +5847,16 @@ msgstr "" " else pure Nothing\n" #. type: Plain text -#: text/chapter11.md:205 +#: text/chapter11.md:204 msgid "" "To elevate the user's permissions, we might use the `local` action to modify " "the `Permissions` object during the execution of some computation:" msgstr "" -"`local`アクションを使うと、計算の実行中に `Permissions`オブジェクトを変更し、" -"ユーザーの権限を昇格させることもできます。" +"`local`動作を使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユー" +"ザーの権限を昇格させることもできます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:206 +#: text/chapter11.md:205 #, no-wrap msgid "" "runAsAdmin :: forall a. Reader Permissions a -> Reader Permissions a\n" @@ -5847,7 +5866,7 @@ msgstr "" "runAsAdmin = local (addPermission \"admin\")\n" #. type: Plain text -#: text/chapter11.md:212 +#: text/chapter11.md:211 msgid "" "Then we could write a function to create a new user, even if the user did " "not have the `admin` permission:" @@ -5856,7 +5875,7 @@ msgstr "" "を作成できるような関数を書くことができます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:213 +#: text/chapter11.md:212 #, no-wrap msgid "" "createUserAsAdmin :: Reader Permissions (Maybe User)\n" @@ -5866,7 +5885,7 @@ msgstr "" "createUserAsAdmin = runAsAdmin createUser\n" #. type: Plain text -#: text/chapter11.md:219 +#: text/chapter11.md:218 msgid "" "To run a computation in the `Reader` monad, the `runReader` function can be " "used to provide the global configuration:" @@ -5874,13 +5893,13 @@ msgstr "" "`Reader`モナドを計算するには、大域的な設定を与える`runReader`関数を使います。" #. type: Fenced code block (haskell) -#: text/chapter11.md:220 +#: text/chapter11.md:219 #, no-wrap msgid "runReader :: forall r a. Reader r a -> r -> a\n" msgstr "runReader :: forall r a. Reader r a -> r -> a\n" #. type: Plain text -#: text/chapter11.md:227 +#: text/chapter11.md:226 #, no-wrap msgid " In these exercises, we will use the `Reader` monad to build a small library for rendering documents with indentation. The \"global configuration\" will be a number indicating the current indentation level:\n" msgstr "" @@ -5888,7 +5907,7 @@ msgstr "" "「大域的な設定」は、現在の字下げの深さを示す数になります。\n" #. type: Fenced code block (haskell) -#: text/chapter11.md:228 +#: text/chapter11.md:227 #, no-wrap msgid "" "type Level = Int\n" @@ -5900,16 +5919,16 @@ msgstr "" "type Doc = Reader Level String\n" #. type: Bullet: ' 1. ' -#: text/chapter11.md:235 +#: text/chapter11.md:234 msgid "" -"(Easy) Write a function `line` which renders a function at the current " +"(Easy) Write a function `line` that renders a function at the current " "indentation level. Your function should have the following type:" msgstr "" -"(簡単)現在の字下げの深さで文字列を出力する関数 `line`を書いてください。\n" -"関数は以下の型を持つ必要があります。" +"(簡単)現在の字下げの深さで関数を書き出す関数`line`を書いてください。\n" +"関数は以下の型を持ちます。" #. type: Plain text -#: text/chapter11.md:239 +#: text/chapter11.md:238 #, no-wrap msgid "" " ```haskell\n" @@ -5921,7 +5940,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:242 +#: text/chapter11.md:241 #, no-wrap msgid "" " _Hint_: use the `ask` function to read the current indentation level. The `power` function from `Data.Monoid` may be helpful too.\n" @@ -5932,7 +5951,7 @@ msgstr "" "1. (普通)`local`関数を使用して次の関数を書いてください。\n" #. type: Plain text -#: text/chapter11.md:246 +#: text/chapter11.md:245 #, no-wrap msgid "" " ```haskell\n" @@ -5944,7 +5963,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:249 +#: text/chapter11.md:248 #, no-wrap msgid "" " which increases the indentation level for a block of code.\n" @@ -5954,7 +5973,7 @@ msgstr "" "1. (普通)`Data.Traversable`で定義された `sequence`関数を使用して、次の関数を書いてください。\n" #. type: Plain text -#: text/chapter11.md:253 +#: text/chapter11.md:252 #, no-wrap msgid "" " ```haskell\n" @@ -5966,7 +5985,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:256 +#: text/chapter11.md:255 #, no-wrap msgid "" " which concatenates a collection of documents, separating them with new lines.\n" @@ -5976,7 +5995,7 @@ msgstr "" "1. (普通)`runReader`関数を使用して次の関数を書いてください。\n" #. type: Plain text -#: text/chapter11.md:260 +#: text/chapter11.md:259 #, no-wrap msgid "" " ```haskell\n" @@ -5988,19 +6007,19 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:262 +#: text/chapter11.md:261 #, no-wrap msgid " which renders a document as a String.\n" msgstr " この関数は文書を文字列として出力します。\n" #. type: Plain text -#: text/chapter11.md:264 +#: text/chapter11.md:263 #, no-wrap -msgid " You should now be able to use your library to write simple documents, as follows:\n" -msgstr " これで、このライブラリを次のように使うと、簡単な文書を書くことができるでしょう。\n" +msgid " You should now be able to use your library to write simple documents as follows:\n" +msgstr " これでライブラリを使って以下のような単純な文書を書けるようになりました。\n" #. type: Fenced code block (haskell) -#: text/chapter11.md:265 +#: text/chapter11.md:264 #, no-wrap msgid "" " render $ cat\n" @@ -6022,76 +6041,73 @@ msgstr "" " ]\n" #. type: Title ## -#: text/chapter11.md:276 +#: text/chapter11.md:275 #, no-wrap msgid "The Writer Monad" msgstr "Writerモナド" #. type: Plain text -#: text/chapter11.md:279 +#: text/chapter11.md:278 msgid "" -"The `Writer` monad provides the ability to accumulate a secondary value in " -"addition to the return value of a computation." -msgstr "" -"`Writer`モナドは、計算の返り値に加えて、もう1つの値を累積していく機能を提供し" -"ます。" +"The `Writer` monad allows accumulating a secondary value in addition to the " +"return value of a computation." +msgstr "`Writer`モナドでは、計算の返り値に加えてもう1つの値を累算できます。" #. type: Plain text -#: text/chapter11.md:281 +#: text/chapter11.md:280 msgid "" "A common use case is to accumulate a log of type `String` or `Array String`, " -"but the `Writer` monad is more general than this. It can actually be used to " -"accumulate a value in any monoid, so it might be used to keep track of an " -"integer total using the `Additive Int` monoid, or to track whether any of " -"several intermediate `Boolean` values were true, using the `Disj Boolean` " -"monoid." -msgstr "" -"よくある使い方としては型 `String`もしくは `Array String`でログを累積していく" -"というものなどがありますが、 `Writer`モナドはこれよりもっと一般的なもので" -"す。\n" -"累積するのに任意のモノイドの値を使うことができ、`Additive Int`モノイドを使っ" -"て、合計を追跡し続けるのに使ったり、 `Disj Boolean`モノイドを使って途中の " -"`Boolean`値の何れかが真であるかどうかを追跡するのに使うことができます。" +"but the `Writer` monad is more general than this. It can accumulate a value " +"in any monoid, so it might be used to keep track of an integer total using " +"the `Additive Int` monoid or to track whether any of several intermediate " +"`Boolean` values were true using the `Disj Boolean` monoid." +msgstr "" +"よくある使い方としては型`String`もしくは`Array String`でログを累算していくと" +"いうものなどがありますが、`Writer`モナドはこれよりもっと一般的なものです。\n" +"累算するのに任意のモノイドの値を使うことができるので、`Additive Int`モノイド" +"を使って整数の合計を追跡するのに使ったり、`Disj Boolean`モノイドを使って途中" +"の`Boolean`値の何れかが真であるかどうかを追跡するのに使えます。" #. type: Plain text -#: text/chapter11.md:283 +#: text/chapter11.md:282 msgid "" -"The `Writer` type constructor takes two type arguments: a type `w` which " +"The `Writer` type constructor takes two type arguments: a type `w` that " "should be an instance of the `Monoid` type class, and the return type `a`." msgstr "" -"`Writer`型の構築子は、 `Monoid`型クラスのインスタンスである型 `w`、および返り" -"値の型 `a`という2つの型引数を取ります。" +"`Writer`型構築子は2つの型引数を取ります。\n" +"`Monoid`型クラスのインスタンスである型`w`と返り値の型`a`です。" #. type: Plain text -#: text/chapter11.md:285 +#: text/chapter11.md:284 msgid "The key element of the `Writer` API is the `tell` function:" msgstr "`Writer`のAPIで重要なのは `tell`関数です。" #. type: Fenced code block (haskell) -#: text/chapter11.md:286 +#: text/chapter11.md:285 #, no-wrap msgid "tell :: forall w a. Monoid w => w -> Writer w Unit\n" msgstr "tell :: forall w a. Monoid w => w -> Writer w Unit\n" #. type: Plain text -#: text/chapter11.md:291 +#: text/chapter11.md:290 msgid "" "The `tell` action appends the provided value to the current accumulated " "result." -msgstr "`tell`アクションは、与えられた値を現在の累積結果に付け加えます。" +msgstr "`tell`動作は与えられた値を現在の累算結果に付け加えます。" #. type: Plain text -#: text/chapter11.md:293 +#: text/chapter11.md:292 msgid "" -"As an example, let's add a log to an existing function by using the `Array " +"As an example, let's add a log to an existing function using the `Array " "String` monoid. Consider our previous implementation of the _greatest common " "divisor_ function:" msgstr "" -"例として、 `Array String`モノイドを使用して、既存の関数にログ機能を追加してみ" -"ましょう。 _最大公約数_ 関数の以前の実装を考えてみます。" +"例として、`Array String`モノイドを使用して、既存の関数にログを追加してみま" +"しょう。\n" +"*最大公約数*関数の以前の実装を考えてみます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:294 +#: text/chapter11.md:293 #, no-wrap msgid "" "gcd :: Int -> Int -> Int\n" @@ -6109,7 +6125,7 @@ msgstr "" " else gcd n (m - n)\n" #. type: Plain text -#: text/chapter11.md:304 +#: text/chapter11.md:303 msgid "" "We could add a log to this function by changing the return type to `Writer " "(Array String) Int`:" @@ -6118,7 +6134,7 @@ msgstr "" "を追加できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:305 +#: text/chapter11.md:304 #, no-wrap msgid "" "import Control.Monad.Writer\n" @@ -6132,7 +6148,7 @@ msgstr "" "gcdLog :: Int -> Int -> Writer (Array String) Int\n" #. type: Plain text -#: text/chapter11.md:313 +#: text/chapter11.md:312 msgid "" "We only have to change our function slightly to log the two inputs at each " "step:" @@ -6140,7 +6156,7 @@ msgstr "" "各手順での2つの入力を記録するためには、少し関数を変更する必要があります。" #. type: Fenced code block (haskell) -#: text/chapter11.md:314 +#: text/chapter11.md:313 #, no-wrap msgid "" " gcdLog n 0 = pure n\n" @@ -6160,7 +6176,7 @@ msgstr "" " else gcdLog n (m - n)\n" #. type: Plain text -#: text/chapter11.md:325 +#: text/chapter11.md:324 msgid "" "We can run a computation in the `Writer` monad by using either of the " "`execWriter` or `runWriter` functions:" @@ -6169,7 +6185,7 @@ msgstr "" "使います。" #. type: Fenced code block (haskell) -#: text/chapter11.md:326 +#: text/chapter11.md:325 #, no-wrap msgid "" "execWriter :: forall w a. Writer w a -> w\n" @@ -6179,21 +6195,21 @@ msgstr "" "runWriter :: forall w a. Writer w a -> Tuple a w\n" #. type: Plain text -#: text/chapter11.md:332 +#: text/chapter11.md:331 msgid "" "Just like in the case of the `State` monad, `execWriter` only returns the " "accumulated log, whereas `runWriter` returns both the log and the result." msgstr "" -"ちょうど `State`モナドの場合と同じように、 `execWriter`が累積されたログだけを" -"返すのに対して、 `runWriter`は累積されたログと結果の両方を返します。" +"ちょうど `State`モナドの場合と同じように、 `execWriter`が累算されたログだけを" +"返すのに対して、 `runWriter`は累算されたログと結果の両方を返します。" #. type: Plain text -#: text/chapter11.md:334 +#: text/chapter11.md:333 msgid "We can test our modified function in PSCi:" msgstr "PSCiで改変した関数を試してみましょう。" #. type: Fenced code block (text) -#: text/chapter11.md:335 +#: text/chapter11.md:334 #, no-wrap msgid "" "> import Control.Monad.Writer\n" @@ -6209,7 +6225,7 @@ msgstr "" "Tuple 3 [\"gcdLog 21 15\",\"gcdLog 6 15\",\"gcdLog 6 9\",\"gcdLog 6 3\",\"gcdLog 3 3\"]\n" #. type: Bullet: ' 1. ' -#: text/chapter11.md:347 +#: text/chapter11.md:346 msgid "" "(Medium) Rewrite the `sumArray` function above using the `Writer` monad and " "the `Additive Int` monoid from the `monoid` package." @@ -6218,18 +6234,18 @@ msgstr "" "うに、上の `sumArray`関数を書き換えてください。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:347 +#: text/chapter11.md:346 msgid "" "(Medium) The _Collatz_ function is defined on natural numbers `n` as `n / 2` " -"when `n` is even, and `3 * n + 1` when `n` is odd. For example, the iterated " +"when `n` is even and `3 * n + 1` when `n` is odd. For example, the iterated " "Collatz sequence starting at `10` is as follows:" msgstr "" -"(普通)*コラッツ関数*は、自然数 `n`が偶数なら `n / 2`、 `n`が奇数なら `3 * " -"n + 1`であると定義されています。\n" -"例えば`10`で始まるコラッツ数列は次のようになります。" +"(普通)*コラッツ*関数は自然数`n`上で定義され、`n`が偶数なら`n / 2`、`n`が奇" +"数なら`3 * n + 1`です。\n" +"例えば`10`で始まるコラッツ数列は以下です。" #. type: Plain text -#: text/chapter11.md:351 +#: text/chapter11.md:350 #, no-wrap msgid "" " ```text\n" @@ -6241,43 +6257,43 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:353 +#: text/chapter11.md:352 #, no-wrap msgid " It is conjectured that the iterated Collatz sequence always reaches `1` after some finite number of applications of the Collatz function.\n" msgstr " コラッツ関数の有限回の適用を繰り返すと、コラッツ数列は必ず最終的に `1`になるということが予想されています。\n" #. type: Plain text -#: text/chapter11.md:355 +#: text/chapter11.md:354 #, no-wrap -msgid " Write a function which uses recursion to calculate how many iterations of the Collatz function are required before the sequence reaches `1`.\n" -msgstr " 数列が `1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する再帰的な関数を書いてください。\n" +msgid " Write a function that uses recursion to calculate how many iterations of the Collatz function are required before the sequence reaches `1`.\n" +msgstr " 再帰を使い、数列が`1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する関数を書いてください。\n" #. type: Plain text -#: text/chapter11.md:357 +#: text/chapter11.md:356 #, no-wrap msgid " Modify your function to use the `Writer` monad to log each application of the Collatz function.\n" -msgstr " `Writer`モナドを使用してコラッツ関数のそれぞれの適用の経過を記録するように、関数を変更してください。\n" +msgstr " `Writer`モナドを使用してコラッツ関数の各適用の経過を記録するように、関数を変更してください。\n" #. type: Title ## -#: text/chapter11.md:358 +#: text/chapter11.md:357 #, no-wrap msgid "Monad Transformers" msgstr "モナド変換子" #. type: Plain text -#: text/chapter11.md:361 +#: text/chapter11.md:360 msgid "" -"Each of the three monads above: `State`, `Reader` and `Writer`, are also " +"Each of the three monads above: `State`, `Reader`, and `Writer`, are also " "examples of so-called _monad transformers_. The equivalent monad " -"transformers are called `StateT`, `ReaderT`, and `WriterT` respectively." +"transformers are called `StateT`, `ReaderT`, and `WriterT`, respectively." msgstr "" "上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*" "の例となっています。\n" -"対応するモナド変換子はそれぞれ `StateT`、 `ReaderT`、 `WriterT`と呼ばれていま" +"対応する各モナド変換子はそれぞれ`StateT`、`ReaderT`、`WriterT`という名前で" "す。" #. type: Plain text -#: text/chapter11.md:363 +#: text/chapter11.md:362 msgid "" "What is a monad transformer? Well, as we have seen, a monad augments " "PureScript code with some type of side effect, which can be interpreted in " @@ -6304,30 +6320,28 @@ msgstr "" "この問題を解決するのが*モナド変換子*です。" #. type: Plain text -#: text/chapter11.md:365 +#: text/chapter11.md:364 msgid "" -"Note that we have already seen that the `Effect` monad provides a partial " -"solution to this problem. Monad transformers provide another solution, and " -"each approach has its own benefits and limitations." +"Note that we have already seen that the `Effect` monad partially solves this " +"problem. Monad transformers provide another solution, and each approach has " +"its own benefits and limitations." msgstr "" -"ただし`Effect`モナドがこの問題に対する部分的な解決策を提供していたことは既に" -"見てきました。\n" -"モナド変換子はまた違った解決策を提供しますが、これらの手法にはそれぞれ利点と" -"制約があります。" +"ただし`Effect`モナドがこの問題を部分的に解決することは既に見ました。\n" +"モナド変換子はまた違った解決策を提供しますが、これらの各手法には利点と制約が" +"あります。" #. type: Plain text -#: text/chapter11.md:367 +#: text/chapter11.md:366 msgid "" -"A monad transformer is a type constructor which is parameterized not only by " -"a type, but by another type constructor. It takes one monad and turns it " -"into another monad, adding its own variety of side-effects." +"A monad transformer is a type constructor parameterized by a type and " +"another type constructor. It takes one monad and turns it into another " +"monad, adding its own variety of side-effects." msgstr "" -"モナド変換子は型だけでなく別の型構築子もパラメータに取る型構築子です。モナド" -"変換子はモナドを1つ取り、独自のいろいろな副作用を追加した別のモナドへと変換し" -"ます。" +"モナド変換子は型と別の型構築子を引数に取る型構築子です。\n" +"モナドを1つ取り、独自の様々な副作用を追加した別のモナドへと変換します。" #. type: Plain text -#: text/chapter11.md:369 +#: text/chapter11.md:368 msgid "" "Let's see an example. The monad transformer version of the `State` monad is " "`StateT`, defined in the `Control.Monad.State.Trans` module. We can find the " @@ -6338,7 +6352,7 @@ msgstr "" "PSCiを使って `StateT`の種を見てみましょう。" #. type: Fenced code block (text) -#: text/chapter11.md:370 +#: text/chapter11.md:369 #, no-wrap msgid "" "> import Control.Monad.State.Trans\n" @@ -6350,7 +6364,7 @@ msgstr "" "Type -> (Type -> Type) -> Type -> Type\n" #. type: Plain text -#: text/chapter11.md:377 +#: text/chapter11.md:376 msgid "" "This looks quite confusing, but we can apply `StateT` one argument at a time " "to understand how to use it." @@ -6359,7 +6373,7 @@ msgstr "" "に1つ引数を与えてみましょう。" #. type: Plain text -#: text/chapter11.md:379 +#: text/chapter11.md:378 msgid "" "The first type argument is the type of the state we wish to use, as was the " "case for `State`. Let's use a state of type `String`:" @@ -6368,7 +6382,7 @@ msgstr "" "それでは型`String`を与えてみましょう。" #. type: Fenced code block (text) -#: text/chapter11.md:380 +#: text/chapter11.md:379 #, no-wrap msgid "" "> :kind StateT String\n" @@ -6378,7 +6392,7 @@ msgstr "" "(Type -> Type) -> Type -> Type\n" #. type: Plain text -#: text/chapter11.md:386 +#: text/chapter11.md:385 #, no-wrap msgid "The next argument is a type constructor of kind `Type -> Type`. It represents the underlying monad, which we want to add the effects of `StateT` to. For the sake of an example, let's choose the `Either String` monad:\n" msgstr "" @@ -6387,7 +6401,7 @@ msgstr "" "例として、 `Either String`モナドを選んでみます。\n" #. type: Fenced code block (text) -#: text/chapter11.md:387 +#: text/chapter11.md:386 #, no-wrap msgid "" "> :kind StateT String (Either String)\n" @@ -6397,7 +6411,7 @@ msgstr "" "Type -> Type\n" #. type: Plain text -#: text/chapter11.md:393 +#: text/chapter11.md:392 msgid "" "We are left with a type constructor. The final argument represents the " "return type, and we might instantiate it to `Number` for example:" @@ -6406,7 +6420,7 @@ msgstr "" "最後の引数は戻り値の型を表しており、例えばそれを`Number`にできます。" #. type: Fenced code block (text) -#: text/chapter11.md:394 +#: text/chapter11.md:393 #, no-wrap msgid "" "> :kind StateT String (Either String) Number\n" @@ -6416,41 +6430,40 @@ msgstr "" "Type\n" #. type: Plain text -#: text/chapter11.md:400 +#: text/chapter11.md:399 msgid "" -"Finally we are left with something of kind `Type`, which means we can try to " -"find values of this type." +"Finally, we are left with something of kind `Type`, which means we can try " +"to find values of this type." msgstr "" -"最後に、種 `Type`の何かが残りましたが、これはつまりこの型の値を探してみること" -"ができるということです。" +"最後に種`Type`の何かが残りました。\n" +"つまりこの型の値を探してみることができます。" #. type: Plain text -#: text/chapter11.md:402 +#: text/chapter11.md:401 msgid "" -"The monad we have constructed - `StateT String (Either String)` - represents " -"computations which can fail with an error, and which can use mutable state." +"The monad we have constructed – `StateT String (Either String)` – represents " +"computations that can fail with an error and use mutable state." msgstr "" -"構築したモナド `StateT String (Either String)`は、エラーで失敗する可能性があ" +"構築したモナド`StateT String (Either String)`は、エラーで失敗する可能性があ" "り、変更可能な状態を使える計算を表しています。" #. type: Plain text -#: text/chapter11.md:404 +#: text/chapter11.md:403 msgid "" "We can use the actions of the outer `StateT String` monad (`get`, `put`, and " -"`modify`) directly, but in order to use the effects of the wrapped monad " -"(`Either String`), we need to \"lift\" them over the monad transformer. The " -"`Control.Monad.Trans` module defines the `MonadTrans` type class, which " -"captures those type constructors which are monad transformers, as follows:" +"`modify`) directly, but to use the effects of the wrapped monad (`Either " +"String`), we need to \"lift\" them over the monad transformer. The `Control." +"Monad.Trans` module defines the `MonadTrans` type class, which captures " +"those type constructors which are monad transformers, as follows:" msgstr "" -"外側の `StateT String (Either String)`モナドのアクション(`get`、`put`、" -"`modify`)は直接使うことができますが、梱包されている内側のモナド (`Either " -"String`) の作用を使うためには、これらの関数をモナド変換子まで「持ち上げ」なく" -"てはいけません。\n" -"`Control.MonadTrans`モジュールでは、モナド変換子であるような型構築子を捉える" -"`MonadTrans`型クラスを次のように定義しています。" +"外側の`StateT String`モナドの動作(`get`、`put`、`modify`)は直接使えますが、" +"梱包されているモナド (`Either String`) の作用を使うためには、これらの関数をモ" +"ナド変換子まで「持ち上げ」る必要があります。\n" +"`Control.Monad.Trans`モジュールは`MonadTrans`型クラスを定義しています。\n" +"これはモナド変換子であるそうした型構築子を捕捉します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:405 +#: text/chapter11.md:404 #, no-wrap msgid "" "class MonadTrans t where\n" @@ -6460,36 +6473,37 @@ msgstr "" " lift :: forall m a. Monad m => m a -> t m a\n" #. type: Plain text -#: text/chapter11.md:411 +#: text/chapter11.md:410 msgid "" "This class contains a single member, `lift`, which takes computations in any " "underlying monad `m` and lifts them into the wrapped monad `t m`. In our " -"case, the type constructor `t` is `StateT String`, and `m` is the `Either " +"case, the type constructor `t` is `StateT String`, `m` is the `Either " "String` monad, so `lift` provides a way to lift computations of type `Either " "String a` to computations of type `StateT String (Either String) a`. This " "means that we can use the effects of `StateT String` and `Either String` " "side-by-side, as long as we use `lift` every time we use a computation of " "type `Either String a`." msgstr "" -"このクラスは、基礎となる任意のモナド `m`の計算をとり、それを梱包されたモナド " -"`t m`へと持ち上げる、 `lift`という1つの関数だけを持っています。\n" -"今回の場合、型構築子 `t`は `StateT String`で、 `m`は `Either String`モナドと" -"なり、 `lift`は型 `Either String a`の計算を、型 `State String (Either " -"String) a`の計算へと持ち上げる方法を提供することになります。\n" -"これは、型 `Either String a`の計算を使うときは、 `lift`を使えばいつでも作用 " -"`StateT String`と `Either String`を一緒に使うことができることを意味します。" +"このクラスは単一のメンバー`lift`を含みます。\n" +"これは通底する任意のモナド`m`の計算を取り、梱包されたモナド`t m`へと持ち上げ" +"るものです。\n" +"今回の場合、型構築子`t`は`StateT String`で、`m`は`Either String`モナドとなる" +"ので、`lift`は型`Either String a`の計算を、型`StateT String (Either String) " +"a`の計算へと持ち上げる方法を提供することになります。\n" +"つまり、型`Either String a`の計算を使う場合に毎回`lift`を使うのであれば、" +"`StateT String`と`Either String`の作用を使えます。" #. type: Plain text -#: text/chapter11.md:413 +#: text/chapter11.md:412 msgid "" -"For example, the following computation reads the underlying state, and then " +"For example, the following computation reads the underlying state and then " "throws an error if the state is the empty string:" msgstr "" -"例えば、次の計算は `StateT`モナド変換子で導入されている状態を読み込み、状態が" -"空の文字列である場合はエラーを投げます。" +"例えば、次の計算は通底する状態を読み、状態が空文字列であればエラーを投げま" +"す。" #. type: Fenced code block (haskell) -#: text/chapter11.md:414 +#: text/chapter11.md:413 #, no-wrap msgid "" "import Data.String (drop, take)\n" @@ -6515,22 +6529,23 @@ msgstr "" " pure (take 1 s)\n" #. type: Plain text -#: text/chapter11.md:428 +#: text/chapter11.md:427 msgid "" "If the state is not empty, the computation uses `put` to update the state to " -"`drop 1 s` (that is, `s` with the first character removed), and returns " -"`take 1 s` (that is, the first character of `s`)." +"`drop 1 s` (that is, `s` with the first character removed) and returns `take " +"1 s` (that is, the first character of `s`)." msgstr "" -"状態が空でなければ、この計算は `put`を使って状態を `drop 1 s`(最初の文字を取" -"り除いた `s`)へと更新し、 `take 1 s`(`s`の最初の文字)を返します。" +"状態が空でなければ、この計算は`put`を使って状態を`drop 1 s`(つまり`s`から最" +"初の文字を取り除いたもの)へと更新し、`take 1 s`(`s`の最初の文字)を返しま" +"す。" #. type: Plain text -#: text/chapter11.md:430 +#: text/chapter11.md:429 msgid "Let's try this in PSCi:" msgstr "それではPSCiでこれを試してみましょう。" #. type: Fenced code block (text) -#: text/chapter11.md:431 +#: text/chapter11.md:430 #, no-wrap msgid "" "> runStateT split \"test\"\n" @@ -6546,22 +6561,22 @@ msgstr "" "Left \"Empty string\"\n" #. type: Plain text -#: text/chapter11.md:440 +#: text/chapter11.md:439 msgid "" -"This is not very remarkable, since we could have implemented this without " +"This is not very remarkable since we could have implemented this without " "`StateT`. However, since we are working in a monad, we can use do notation " "or applicative combinators to build larger computations from smaller ones. " "For example, we can apply `split` twice to read the first two characters " "from a string:" msgstr "" -"これは `StateT`を使わなくても実装できるので、さほど驚くようなことはありませ" +"これは`StateT`を使わなくても実装できるので、さほど驚くようなことはありませ" "ん。\n" -"しかし、モナドとして扱っているので、do記法やアプリカティブコンビネータを使っ" -"て、小さな計算から大きな計算を構築していくことができます。\n" -"例えば、2回 `split`を適用すると、文字列から最初の2文字を読むことができます。" +"しかし、モナドの中で扱っているので、do記法やアプリカティブコンビネータを使っ" +"て、小さな計算から大きな計算を構築できます。\n" +"例えば、2回`split`を適用すると、文字列から最初の2文字を読めます。" #. type: Fenced code block (text) -#: text/chapter11.md:441 +#: text/chapter11.md:440 #, no-wrap msgid "" "> runStateT ((<>) <$> split <*> split) \"test\"\n" @@ -6571,40 +6586,38 @@ msgstr "" "(Right (Tuple \"te\" \"st\"))\n" #. type: Plain text -#: text/chapter11.md:447 +#: text/chapter11.md:446 msgid "" "We can use the `split` function with a handful of other actions to build a " "basic parsing library. In fact, this is the approach taken by the `parsing` " -"library. This is the power of monad transformers - we can create custom-" -"built monads for a variety of problems, choosing the side-effects that we " -"need, and keeping the expressiveness of do notation and applicative " -"combinators." +"library. This is the power of monad transformers – we can create custom-" +"built monads for various problems, choose the side-effects we need, and keep " +"the expressiveness of do notation and applicative combinators." msgstr "" -"他にもアクションを沢山用意すれば、 `split`関数を使って、基本的な構文解析ライ" -"ブラリを構築できます。これは実際に `parsing`ライブラリで採用されている手法で" -"す。これがモナド変換子の力なのです。必要な副作用を選択して、do記法とアプリカ" -"ティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作" -"成できるのです。" +"`split`関数とその他沢山の動作を使えば基本的な構文解析ライブラリを構築できま" +"す。\n" +"実際、これは`parsing`ライブラリで採用されている手法です。\n" +"これがモナド変換子の力なのです。\n" +"必要な副作用を選択し、do記法とアプリカティブコンビネータで表現力を維持しなが" +"ら、様々な問題のための特注のモナドを作成できるのです。" #. type: Title ## -#: text/chapter11.md:448 +#: text/chapter11.md:447 #, no-wrap msgid "The ExceptT Monad Transformer" msgstr "ExceptTモナド変換子" #. type: Plain text -#: text/chapter11.md:451 +#: text/chapter11.md:450 msgid "" "The `transformers` package also defines the `ExceptT e` monad transformer, " -"which is the transformer corresponding to the `Either e` monad. It provides " -"the following API:" +"corresponding to the `Either e` monad. It provides the following API:" msgstr "" -"`transformers`パッケージでは、 `Either e`モナドに対応する変換子である" -"`ExceptT e`モナド変換子も定義されています。\n" -"これは次のAPIを提供します。" +"`transformers`パッケージでは`ExceptT e`モナド変換子も定義されています。\n" +"これは`Either e`モナドに対応するもので、以下のAPIを提供します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:452 +#: text/chapter11.md:451 #, no-wrap msgid "" "class MonadError e m where\n" @@ -6624,30 +6637,29 @@ msgstr "" "runExceptT :: forall e m a. ExceptT e m a -> m (Either e a)\n" #. type: Plain text -#: text/chapter11.md:463 +#: text/chapter11.md:462 msgid "" -"The `MonadError` class captures those monads which support throwing and " -"catching of errors of some type `e`, and an instance is provided for the " -"`ExceptT e` monad transformer. The `throwError` action can be used to " -"indicate failure, just like `Left` in the `Either e` monad. The `catchError` " -"action allows us to continue after an error is thrown using `throwError`." +"The `MonadError` class captures those monads that support throwing and " +"catching errors of some type `e`, and an instance is provided for the " +"`ExceptT e` monad transformer. The `throwError` action can indicate failure, " +"like `Left` in the `Either e` monad. The `catchError` action allows us to " +"continue after an error is thrown using `throwError`." msgstr "" -"`MonadError`クラスは `e`型のエラーを投げたりキャッチに対応したりするモナドを" -"取得し、 `ExceptT e`モナド変換子のインスタンスが提供されます。\n" -"`Either e`モナドの `Left`と同じように、 `throwError`アクションは失敗を示すた" -"めに使われます。\n" -"`catchError`アクションを使うと、 `throwError`でエラーが投げられたあとでも処理" -"を継続できるようになります。" +"`MonadError`クラスは`e`型のエラーを投げたり捕えたりに対応するモナドを捕捉し、" +"`ExceptT e`モナド変換子のインスタンスが提供されます。\n" +"`Either e`モナドの`Left`と同じように、`throwError`動作では失敗を示せます。\n" +"`catchError`動作では`throwError`を使ってエラーが投げられた後に処理を継続でき" +"ます。" #. type: Plain text -#: text/chapter11.md:465 +#: text/chapter11.md:464 msgid "" "The `runExceptT` handler is used to run a computation of type `ExceptT e m " "a`." msgstr "`runExceptT`制御子を使うと、型 `ExceptT e m a`を計算できます。" #. type: Plain text -#: text/chapter11.md:467 +#: text/chapter11.md:466 msgid "" "This API is similar to that provided by the `exceptions` package and the " "`Exception` effect. However, there are some important differences:" @@ -6657,7 +6669,7 @@ msgstr "" "しかし、幾つかの重要な違いがあります。" #. type: Bullet: '- ' -#: text/chapter11.md:470 +#: text/chapter11.md:469 msgid "" "`Exception` uses actual JavaScript exceptions, whereas `ExceptT` models " "errors as a pure data structure." @@ -6666,7 +6678,7 @@ msgstr "" "数的データ型を使っています。" #. type: Bullet: '- ' -#: text/chapter11.md:470 +#: text/chapter11.md:469 msgid "" "The `Exception` effect only supports exceptions of one type, namely " "JavaScript's `Error` type, whereas `ExceptT` supports errors of any type. In " @@ -6677,18 +6689,18 @@ msgstr "" "`ExceptT`では新たなエラー型を自由に定義できます。" #. type: Plain text -#: text/chapter11.md:472 +#: text/chapter11.md:471 msgid "" "Let's try out `ExceptT` by using it to wrap the `Writer` monad. Again, we " "are free to use actions from the monad transformer `ExceptT e` directly, but " "computations in the `Writer` monad should be lifted using `lift`:" msgstr "" -"試しに `ExceptT`を使って `Writer`モナドを包んでみましょう。\n" -"ここでもモナド変換子 `ExceptT e`のアクションを直接使うことも自由にできます" -"が、`Writer`モナドの計算は `lift`を使って持ちあげるべきです。" +"試しに`ExceptT`を使って`Writer`モナドを包んでみましょう。\n" +"ここでもモナド変換子`ExceptT e`の動作を直接使うことも自由にできますが、" +"`Writer`モナドの計算は`lift`を使って持ち上げるべきです。" #. type: Fenced code block (haskell) -#: text/chapter11.md:473 +#: text/chapter11.md:472 #, no-wrap msgid "" "import Control.Monad.Except\n" @@ -6712,7 +6724,7 @@ msgstr "" " pure \"Return value\"\n" #. type: Plain text -#: text/chapter11.md:486 +#: text/chapter11.md:485 msgid "" "If we test this function in PSCi, we can see how the two effects of " "accumulating a log and throwing an error interact. First, we can run the " @@ -6727,7 +6739,7 @@ msgstr "" "それから、 `runWriter`で内側の`Writer`を計算します。" #. type: Fenced code block (text) -#: text/chapter11.md:487 +#: text/chapter11.md:486 #, no-wrap msgid "" "> runWriter $ runExceptT writerAndExceptT\n" @@ -6737,74 +6749,73 @@ msgstr "" "Tuple (Left \"Error!\") [\"Before the error\"]\n" #. type: Plain text -#: text/chapter11.md:493 +#: text/chapter11.md:492 msgid "" -"Note that only those log messages which were written before the error was " -"thrown actually get appended to the log." +"Note that only those log messages that were written before the error was " +"thrown get appended to the log." msgstr "" -"実際に追加されるログは、エラーが投げられる前に書かれたログメッセージだけであ" -"ることにも注目してください。" +"なお、エラーが投げられる前に書き出されるログ文言だけがログに追記されます。" #. type: Title ## -#: text/chapter11.md:494 +#: text/chapter11.md:493 #, no-wrap msgid "Monad Transformer Stacks" msgstr "モナド変換子スタック" #. type: Plain text -#: text/chapter11.md:497 +#: text/chapter11.md:496 msgid "" "As we have seen, monad transformers can be used to build new monads on top " "of existing monads. For some monad transformer `t1` and some monad `m`, the " -"application `t1 m` is also a monad. That means that we can apply a _second_ " -"monad transformer `t2` to the result `t1 m` to construct a third monad `t2 " -"(t1 m)`. In this way, we can construct a _stack_ of monad transformers, " -"which combine the side-effects provided by their constituent monads." +"application `t1 m` is also a monad. That means we can apply a _second_ monad " +"transformer `t2` to the result `t1 m` to construct a third monad `t2 (t1 " +"m)`. In this way, we can construct a _stack_ of monad transformers, which " +"combine the side-effects provided by their constituent monads." msgstr "" -"これまで見てきたように、モナド変換子を使うと既存のモナドを土台に新しいモナド" +"これまで見てきたように、モナド変換子を使って既存のモナドを土台に新しいモナド" "を構築できます。\n" -"任意のモナド変換子 `t1`と任意のモナド`m`について、その適用 `t1 m`もまたモナド" -"になります。\n" -"これは*2つめの*モナド変換子 `t2`を先ほどの結果 `t1 m`に適用すると、3つ目のモ" -"ナド `t2 (t1 m)`を作れることを意味しています。\n" -"このように、構成するモナドによって提供された副作用を組み合わせる、モナド変換" -"子の*スタック*を構築できます。" +"何かのモナド変換子`t1`とモナド`m`について、その適用`t1 m`もまたモナドになりま" +"す。\n" +"つまり、*2つめの*モナド変換子`t2`を結果`t1 m`に適用すると、3つ目のモナド`t2 " +"(t1 m)`を作れます。\n" +"このようにしてモナド変換子の*スタック*を構築できます。\n" +"これは構成されるモナドによって提供される副作用を組み合わせるものです。" #. type: Plain text -#: text/chapter11.md:499 +#: text/chapter11.md:498 msgid "" "In practice, the underlying monad `m` is either the `Effect` monad, if " "native side-effects are required, or the `Identity` monad, defined in the " "`Data.Identity` module. The `Identity` monad adds no new side-effects, so " "transforming the `Identity` monad only provides the effects of the monad " -"transformer. In fact, the `State`, `Reader` and `Writer` monads are " -"implemented by transforming the `Identity` monad with `StateT`, `ReaderT` " -"and `WriterT` respectively." +"transformer. The `State`, `Reader`, and `Writer` monads are implemented by " +"transforming the `Identity` monad with `StateT`, `ReaderT`, and `WriterT`, " +"respectively." msgstr "" -"実際には、基本となるモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、" -"さもなくば `Data.Identity`モジュールで定義されている`Identity`モナドになりま" +"実際には、通底するモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さ" +"もなくば`Data.Identity`モジュールで定義されている`Identity`モナドになりま" "す。\n" "`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換" "はモナド変換子の作用だけを提供します。\n" -"実際に、`State`モナドと`Reader`モナドと`Writer`モナドは、`Identity`モナドをそ" -"れぞれ`StateT`と`ReaderT`と`WriterT`で変換することによって実装されています。" +"`State`、`Reader`、`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`、" +"`ReaderT`、`WriterT`で変換することによって実装されています。" #. type: Plain text -#: text/chapter11.md:501 +#: text/chapter11.md:500 msgid "" "Let's see an example in which three side effects are combined. We will use " -"the `StateT`, `WriterT` and `ExceptT` effects, with the `Identity` monad on " +"the `StateT`, `WriterT`, and `ExceptT` effects, with the `Identity` monad on " "the bottom of the stack. This monad transformer stack will provide the side " "effects of mutable state, accumulating a log, and pure errors." msgstr "" -"それでは3つの副作用が組み合わされている例を見てみましょう。\n" -"`Identity`モナドをスタックの底にして、 `StateT`作用、 `WriterT`作用、" -"`ExceptT`作用を使います。\n" +"3つの副作用が組み合わっている例を見てみましょう。\n" +"`Identity`モナドをスタックの底にして、`StateT`、`WriterT`、`ExceptT`作用を使" +"います。\n" "このモナド変換子スタックは、可変状態、ログの蓄積、そして純粋なエラーの副作用" "を提供します。" #. type: Plain text -#: text/chapter11.md:503 +#: text/chapter11.md:502 msgid "" "We can use this monad transformer stack to reproduce our `split` action with " "the added feature of logging." @@ -6813,7 +6824,7 @@ msgstr "" "ンに作り変えられます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:504 +#: text/chapter11.md:503 #, no-wrap msgid "" "type Errors = Array String\n" @@ -6849,7 +6860,7 @@ msgstr "" " pure (take 1 s)\n" #. type: Plain text -#: text/chapter11.md:523 +#: text/chapter11.md:522 msgid "" "If we test this computation in PSCi, we see that the state is appended to " "the log for every invocation of `split`." @@ -6858,21 +6869,21 @@ msgstr "" "ることがわかります。" #. type: Plain text -#: text/chapter11.md:525 +#: text/chapter11.md:524 msgid "" "Note that we have to remove the side-effects in the order in which they " -"appear in the monad transformer stack: first we use `runStateT` to remove " +"appear in the monad transformer stack: first, we use `runStateT` to remove " "the `StateT` type constructor, then `runWriterT`, then `runExceptT`. " "Finally, we run the computation in the `Identity` monad by using `unwrap`." msgstr "" -"モナド変換子スタックに現れる順序に従って、副作用を取り除いていかなければなら" -"ないことに注意してください。\n" -"最初に `StateT`型構築子を取り除くために `runStateT`を使い、それから " -"`runtWriteT`を使い、その後`runExceptT`を使います。\n" -"最後に `unwrap`を使用して `Identity`モナドを演算します。" +"なお、モナド変換子スタックに現れる順序で副作用を取り除いていかなければなりま" +"せん。\n" +"最初に`StateT`型構築子を取り除くために`runStateT`を、それから`runtWriteT`、" +"`runExceptT`を使います。\n" +"最後に`unwrap`を使用して`Identity`モナド中で計算します。" #. type: Fenced code block (text) -#: text/chapter11.md:526 +#: text/chapter11.md:525 #, no-wrap msgid "" "> runParser p s = unwrap $ runExceptT $ runWriterT $ runStateT p s\n" @@ -6892,7 +6903,7 @@ msgstr "" "(Right (Tuple (Tuple \"te\" \"st\") [\"The state is test\", \"The state is est\"]))\n" #. type: Plain text -#: text/chapter11.md:537 +#: text/chapter11.md:536 msgid "" "However, if the parse is unsuccessful because the state is empty, then no " "log is printed at all:" @@ -6901,7 +6912,7 @@ msgstr "" "ん。" #. type: Fenced code block (text) -#: text/chapter11.md:538 +#: text/chapter11.md:537 #, no-wrap msgid "" "> runParser split \"\"\n" @@ -6911,42 +6922,42 @@ msgstr "" "(Left [\"Empty string\"])\n" #. type: Plain text -#: text/chapter11.md:544 +#: text/chapter11.md:543 msgid "" -"This is because of the way in which the side-effects provided by the " -"`ExceptT` monad transformer interact with the side-effects provided by the " -"`WriterT` monad transformer. We can address this by changing the order in " -"which the monad transformer stack is composed. If we move the `ExceptT` " -"transformer to the top of the stack, then the log will contain all messages " -"written up until the first error, as we saw earlier when we transformed " -"`Writer` with `ExceptT`." +"This is because of how the side-effects provided by the `ExceptT` monad " +"transformer interact with the side-effects provided by the `WriterT` monad " +"transformer. We can address this by changing the order in which the monad " +"transformer stack is composed. If we move the `ExceptT` transformer to the " +"top of the stack, then the log will contain all messages written up until " +"the first error, as we saw earlier when we transformed `Writer` with " +"`ExceptT`." msgstr "" -"これは、 `ExceptT`モナド変換子が提供する副作用が、 `WriterT`モナド変換子が提" -"供する副作用と干渉するためです。\n" -"これはモナド変換子スタックが構成されている順序を変更することで解決できま" +"これは、`ExceptT`モナド変換子が提供する副作用と`WriterT`モナド変換子が提供す" +"る副作用との関係によるものです。\n" +"これはモナド変換子スタックが構成されている順序を変更することで対処できま" "す。\n" -"スタックの最上部に `ExceptT`変換子を移動すると、先ほど `Writer`を `ExceptT`に" -"変換したときと同じように、最初のエラーまでに書かれた全てのメッセージが含まれ" -"るようになります。" +"スタックの最上部に`ExceptT`変換子を移動すると、先ほど`Writer`を`ExceptT`に変" +"換したときに見たように、最初のエラーまでに書かれた全ての文言がログに含まれる" +"ようになります。" #. type: Plain text -#: text/chapter11.md:546 +#: text/chapter11.md:545 msgid "" "One problem with this code is that we have to use the `lift` function " -"multiple times to lift computations over multiple monad transformers: for " +"multiple times to lift computations over multiple monad transformers; for " "example, the call to `throwError` has to be lifted twice, once over " "`WriterT` and a second time over `StateT`. This is fine for small monad " -"transformer stacks, but quickly becomes inconvenient." +"transformer stacks but quickly becomes inconvenient." msgstr "" -"このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、 " +"このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、" "`lift`関数を複数回使わなければならないということです。\n" -"例えば`throwError`の呼び出しは、1回目は `WriteT`へ、2回目は `StateT`へと、2回" -"持ちあげなければなりません。\n" -"小さなモナド変換子スタックならなんとかなりますが、そのうち不便だと感じるよう" -"になるでしょう。" +"例えば`throwError`の呼び出しは、1回目は`WriteT`へ、2回目は`StateT`へ、と2回持" +"ちあげなければなりません。\n" +"小さなモナド変換子スタックならなんとかなりますが、そのうちすぐに不便になるで" +"しょう。" #. type: Plain text -#: text/chapter11.md:548 +#: text/chapter11.md:547 msgid "" "Fortunately, as we will see, we can use the automatic code generation " "provided by type class inference to do most of this \"heavy lifting\" for us." @@ -6955,7 +6966,7 @@ msgstr "" "成を使うと、ほとんどの「重労働」を任せられます。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:553 +#: text/chapter11.md:552 msgid "" "(Easy) Use the `ExceptT` monad transformer over the `Identity` functor to " "write a function `safeDivide` which divides two numbers, throwing an error " @@ -6966,12 +6977,12 @@ msgstr "" "この関数は分母がゼロの場合に(文字列「Divide by zero!」の)エラーを投げます。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:553 +#: text/chapter11.md:552 msgid "(Medium) Write a parser" msgstr "(普通)次のような構文解析関数を書いてください。" #. type: Plain text -#: text/chapter11.md:557 +#: text/chapter11.md:556 #, no-wrap msgid "" " ```haskell\n" @@ -6983,19 +6994,19 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:559 +#: text/chapter11.md:558 #, no-wrap -msgid " which matches a string as a prefix of the current state, or fails with an error message.\n" -msgstr " これは現在の状態が接頭辞に適合するか、もしくはエラーメッセージとともに失敗します。\n" +msgid " which matches a string as a prefix of the current state or fails with an error message.\n" +msgstr " これは現在の状態が接頭辞に照合するか、もしくはエラー文言とともに失敗します。\n" #. type: Plain text -#: text/chapter11.md:561 +#: text/chapter11.md:560 #, no-wrap msgid " Your parser should work as follows:\n" msgstr " この構文解析器は次のように動作します。\n" #. type: Plain text -#: text/chapter11.md:566 +#: text/chapter11.md:565 #, no-wrap msgid "" " ```text\n" @@ -7009,18 +7020,19 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:569 +#: text/chapter11.md:568 #, no-wrap msgid "" " _Hint_: you can use the implementation of `split` as a starting point. You might find the `stripPrefix` function useful.\n" -" 1. (Difficult) Use the `ReaderT` and `WriterT` monad transformers to reimplement the document printing library which we wrote earlier using the `Reader` monad.\n" +" 1. (Difficult) Use the `ReaderT` and `WriterT` monad transformers to reimplement the document printing library, which we wrote earlier using the `Reader` monad.\n" msgstr "" -" *手掛かり*:出発点として`split`の実装を使うといいでしょう。\n" -" `stripPrefix`関数も役に立ちます。\n" -"1. (難しい)以前 `Reader`モナドを使用して書いた文書表示ライブラリを、`ReaderT`と `WriterT`モナド変換子を使用して再実装してください。\n" +" *手掛かり*:出発点として`split`の実装が使えます。\n" +" `stripPrefix`関数も役に立つかもしれません。\n" +"1. (難しい)文書表示ライブラリを、`ReaderT`と`WriterT`モナド変換子を使用して再実装してください。\n" +" 以前`Reader`モナドを使用して書いたものです。\n" #. type: Plain text -#: text/chapter11.md:571 +#: text/chapter11.md:570 #, no-wrap msgid " Instead of using `line` to emit strings and `cat` to concatenate strings, use the `Array String` monoid with the `WriterT` monad transformer, and `tell` to append a line to the result. Use the same names as in the original implementation but ending with an apostrophe (`'`).\n" msgstr "" @@ -7029,22 +7041,22 @@ msgstr "" # もしかして:アカリがやってきたぞっ #. type: Title ## -#: text/chapter11.md:572 +#: text/chapter11.md:571 #, no-wrap msgid "Type Classes to the Rescue!" msgstr "型クラスが助けに来たぞっ" #. type: Plain text -#: text/chapter11.md:575 +#: text/chapter11.md:574 msgid "" "When we looked at the `State` monad at the start of this chapter, I gave the " "following types for the actions of the `State` monad:" msgstr "" -"本章の最初で扱った `State`モナドを見てみると、 `State`モナドのアクションには" -"次のような型が与えられていました。" +"本章の最初で扱った `State`モナドを見てみると、 `State`モナドの動作には次のよ" +"うな型が与えられていました。" #. type: Fenced code block (haskell) -#: text/chapter11.md:576 +#: text/chapter11.md:575 #, no-wrap msgid "" "get :: forall s. State s s\n" @@ -7056,7 +7068,7 @@ msgstr "" "modify :: forall s. (s -> s) -> State s Unit\n" #. type: Plain text -#: text/chapter11.md:583 +#: text/chapter11.md:582 msgid "" "In reality, the types given in the `Control.Monad.State.Class` module are " "more general than this:" @@ -7065,7 +7077,7 @@ msgstr "" "もっと一般的です。" #. type: Fenced code block (haskell) -#: text/chapter11.md:584 +#: text/chapter11.md:583 #, no-wrap msgid "" "get :: forall m s. MonadState s m => m s\n" @@ -7077,7 +7089,7 @@ msgstr "" "modify :: forall m s. MonadState s m => (s -> s) -> m Unit\n" #. type: Plain text -#: text/chapter11.md:591 +#: text/chapter11.md:590 msgid "" "The `Control.Monad.State.Class` module defines the `MonadState` (multi-" "parameter) type class, which allows us to abstract over \"monads which " @@ -7093,89 +7105,88 @@ msgstr "" "ンスになっており、このクラスには他にも興味深いインスタンスが数多くあります。" #. type: Plain text -#: text/chapter11.md:593 +#: text/chapter11.md:592 msgid "" "In particular, there are instances of `MonadState` for the `WriterT`, " -"`ReaderT` and `ExceptT` monad transformers, provided in the `transformers` " -"package. Each of these monad transformers has an instance for `MonadState` " -"whenever the underlying `Monad` does. In practice, this means that as long " -"as `StateT` appears _somewhere_ in the monad transformer stack, and " -"everything above `StateT` is an instance of `MonadState`, then we are free " -"to use `get`, `put` and `modify` directly, without the need to use `lift`." +"`ReaderT`, and `ExceptT` monad transformers provided in the `transformers` " +"package. Each has an instance for `MonadState` whenever the underlying " +"`Monad` does. In practice, this means that as long as `StateT` appears " +"_somewhere_ in the monad transformer stack, and everything above `StateT` is " +"an instance of `MonadState`, then we are free to use `get`, `put`, and " +"`modify` directly without the need to use `lift`." msgstr "" -"特に、 `transformers`パッケージではモナド変換子 `WriterT`、 `ReaderT`、" -"`ExceptT`についての `MonadState`のインスタンスが提供されています。\n" -"通底する`Monad`が`MonadState`インスタンスを持っていれば常に、これらのモナド変" -"換子にもインスタンスがあります。\n" -"実践的には、 `StateT`がモナド変換子スタックの*どこか*に現れ、 `StateT`より上" -"の全てが `MonadState`のインスタンスであれば、 `get`、 `put`、 `modify`を直接" -"自由に使用できます。" +"特に、`transformers`パッケージではモナド変換子`WriterT`、`ReaderT`、`ExceptT`" +"についての`MonadState`のインスタンスがあります。\n" +"通底する`Monad`が`MonadState`インスタンスを持つなら常に、これらもインスタンス" +"を持ちます。\n" +"つまり実際には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より" +"上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく`get`や" +"`put`や`modify`を直接自由に使用できます。" #. type: Plain text -#: text/chapter11.md:595 +#: text/chapter11.md:594 msgid "" "Indeed, the same is true of the actions we covered for the `ReaderT`, " "`WriterT`, and `ExceptT` transformers. `transformers` defines a type class " -"for each of the major transformers, allowing us to abstract over monads " -"which support their operations." +"for each of the major transformers, allowing us to abstract over monads that " +"support their operations." msgstr "" -"当然ですが、これまで扱ってきた `ReaderT`、 `WriterT`、 `ExceptT`変換子につい" -"ても、同じことが成り立っています。`transformers`では主な変換子それぞれについ" -"ての型クラスが定義されています。これによりそれらの操作に対応するモナドの上に" -"抽象化できるのです。" +"当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子について" +"も、同じことが言えます。\n" +"`transformers`では主な各変換子について型クラスが定義されています。\n" +"これによりそれらの操作に対応するモナドの上に抽象化できるのです。" #. type: Plain text -#: text/chapter11.md:597 +#: text/chapter11.md:596 msgid "" "In the case of the `split` function above, the monad stack we constructed is " -"an instance of each of the `MonadState`, `MonadWriter` and `MonadError` type " -"classes. This means that we don't need to call `lift` at all! We can just " -"use the actions `get`, `put`, `tell` and `throwError` as if they were " +"an instance of each of the `MonadState`, `MonadWriter`, and `MonadError` " +"type classes. This means that we don't need to call `lift` at all! We can " +"just use the actions `get`, `put`, `tell`, and `throwError` as if they were " "defined on the monad stack itself:" msgstr "" -"上の `split`関数の場合、構築されたこのモナドスタックは型クラス`MonadState`、 " -"`MonadWriter`、 `MonadError`それぞれのインスタンスです。\n" -"これはつまり、`lift`は全く呼び出す必要がないのです。\n" -"まるでモナドスタック自体に定義されていたかのように、アクション `get`、" -"`put`、 `tell`、 `throwError`をそのまま使用できます。" +"上の`split`関数の場合、構築したモナドスタックは各型クラス`MonadState`、" +"`MonadWriter`、`MonadError`のインスタンスです。\n" +"つまり`lift`は全く呼び出す必要がないのです。\n" +"まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、" +"`tell`、`throwError`をそのまま使用できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:598 +#: text/chapter11.md:597 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Split.purs:split}}\n" msgstr "{{#include ../exercises/chapter11/src/Split.purs:split}}\n" #. type: Plain text -#: text/chapter11.md:603 +#: text/chapter11.md:602 msgid "" -"This computation really looks like we have extended our programming language " -"to support the three new side-effects of mutable state, logging and error " +"This computation looks like we have extended our programming language to " +"support the three new side-effects of mutable state, logging, and error " "handling. However, everything is still implemented using pure functions and " "immutable data under the hood." msgstr "" -"この計算はまるで、可変状態、ロギング、エラー処理という3つの副作用に対応した、" -"独自のプログラミング言語を拡張したかのようにみえます。\n" -"しかし、内部的には全てはあくまで純粋な関数と普通のデータを使って実装されてい" +"この計算は、独自のプログラミング言語を拡張し、可変状態、ロギング、エラー処理" +"という3つの新しい副作用に対応したように見えます。\n" +"しかし、内部的には全てはあくまで純粋な関数と不変のデータを使って実装されてい" "るのです。" #. type: Title ## -#: text/chapter11.md:604 +#: text/chapter11.md:603 #, no-wrap msgid "Alternatives" msgstr "代替" #. type: Plain text -#: text/chapter11.md:607 +#: text/chapter11.md:606 msgid "" "The `control` package defines a number of abstractions for working with " -"computations which can fail. One of these is the `Alternative` type class:" +"computations that can fail. One of these is the `Alternative` type class:" msgstr "" -"`control`パッケージでは失敗しうる計算を制御するための抽象化が幾つか定義されて" -"います。\n" -"その1つは `Alternative`型クラスです。" +"`control`パッケージでは失敗しうる計算を扱う抽象化が数多く定義されています。\n" +"その1つは`Alternative`型クラスです。" #. type: Fenced code block (haskell) -#: text/chapter11.md:608 +#: text/chapter11.md:607 #, no-wrap msgid "" "class Functor f <= Alt f where\n" @@ -7195,15 +7206,15 @@ msgstr "" "class (Applicative f, Plus f) <= Alternative f\n" #. type: Plain text -#: text/chapter11.md:619 +#: text/chapter11.md:618 #, no-wrap -msgid "`Alternative` provides two new combinators: the `empty` value, which provides a prototype for a failing computation, and the `alt` function (and its alias, `<|>`) which provides the ability to fall back to an _alternative_ computation in the case of an error.\n" +msgid "`Alternative` provides two new combinators: the `empty` value, which provides a prototype for a failing computation, and the `alt` function (and its alias, `<|>`), which provides the ability to fall back to an _alternative_ computation in the case of an error.\n" msgstr "" "`Alternative`は2つの新しいコンビネータを提供しています。\n" "1つは失敗しうる計算の雛形を提供する`empty`値で、もう1つはエラーが起きたときに*代替の*計算へ戻ってやり直す機能を提供する`alt`関数(そしてその別名`<|>`)です。\n" #. type: Plain text -#: text/chapter11.md:621 +#: text/chapter11.md:620 msgid "" "The `Data.Array` module provides two useful functions for working with type " "constructors in the `Alternative` type class:" @@ -7212,7 +7223,7 @@ msgstr "" "つの便利な関数を提供します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:622 +#: text/chapter11.md:621 #, no-wrap msgid "" "many :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a)\n" @@ -7222,23 +7233,23 @@ msgstr "" "some :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a)\n" #. type: Plain text -#: text/chapter11.md:628 +#: text/chapter11.md:627 msgid "There is also an equivalent `many` and `some` for `Data.List`" msgstr "`Data.List`にも等価な`many`と`some`があります。" #. type: Plain text -#: text/chapter11.md:630 +#: text/chapter11.md:629 msgid "" "The `many` combinator uses the `Alternative` type class to repeatedly run a " -"computation _zero-or-more_ times. The `some` combinator is similar, but " +"computation _zero-or-more_ times. The `some` combinator is similar but " "requires at least the first computation to succeed." msgstr "" -"`many`コンビネータは計算を _ゼロ回以上_ 繰り返し実行するために`Alternative`型" -"クラスを使用しています。 `some`コンビネータも似ていますが、成功するために少な" -"くとも1回の計算を必要とします。" +"`many`コンビネータは計算を*ゼロ回以上*繰り返し実行するために`Alternative`型ク" +"ラスを使います。\n" +"`some`コンビネータも似ていますが、最低1回は計算が成功する必要があります。" #. type: Plain text -#: text/chapter11.md:632 +#: text/chapter11.md:631 msgid "" "In the case of our `Parser` monad transformer stack, there is an instance of " "`Alternative` induced by the `ExceptT` component, which supports failure by " @@ -7255,7 +7266,7 @@ msgstr "" "ることを意味します。" #. type: Fenced code block (text) -#: text/chapter11.md:633 +#: text/chapter11.md:632 #, no-wrap msgid "" "> import Data.Array (many)\n" @@ -7279,7 +7290,7 @@ msgstr "" " ]))\n" #. type: Plain text -#: text/chapter11.md:646 +#: text/chapter11.md:645 msgid "" "Here, the input string `\"test\"` has been repeatedly split to return an " "array of four single-character strings, the leftover state is empty, and the " @@ -7291,13 +7302,13 @@ msgstr "" "す。" #. type: Title ## -#: text/chapter11.md:647 +#: text/chapter11.md:646 #, no-wrap msgid "Monad Comprehensions" msgstr "モナド内包表記" #. type: Plain text -#: text/chapter11.md:650 +#: text/chapter11.md:649 msgid "" "The `Control.MonadPlus` module defines a subclass of the `Alternative` type " "class, called `MonadPlus`. `MonadPlus` captures those type constructors " @@ -7309,70 +7320,70 @@ msgstr "" "す。" #. type: Fenced code block (haskell) -#: text/chapter11.md:651 +#: text/chapter11.md:650 #, no-wrap msgid "class (Monad m, Alternative m) <= MonadPlus m\n" msgstr "class (Monad m, Alternative m) <= MonadPlus m\n" #. type: Plain text -#: text/chapter11.md:656 +#: text/chapter11.md:655 msgid "In particular, our `Parser` monad is an instance of `MonadPlus`." msgstr "実際、`Parser`モナドは `MonadPlus`のインスタンスです。" #. type: Plain text -#: text/chapter11.md:658 +#: text/chapter11.md:657 msgid "" "When we covered array comprehensions earlier in the book, we introduced the " "`guard` function, which could be used to filter out unwanted results. In " -"fact, the `guard` function is more general, and can be used for any monad " +"fact, the `guard` function is more general and can be used for any monad, " "which is an instance of `MonadPlus`:" msgstr "" -"以前本書中で配列内包表記を扱ったとき、不要な結果を除いて絞り込むために使われ" -"る`guard`関数を導入しました。\n" -"実際には`guard`関数はもっと一般的で、 `MonadPlus`のインスタンスである全てのモ" -"ナドに対して使うことができます。" +"以前本書中で配列内包表記を押さえたとき、`guard`関数を導入しました。\n" +"これは欲しくない結果を取り除けるのに使えました。\n" +"実際には`guard`関数はもっと一般的で、`MonadPlus`のインスタンスである任意のモ" +"ナドに対して使えます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:659 +#: text/chapter11.md:658 #, no-wrap msgid "guard :: forall m. Alternative m => Boolean -> m Unit\n" msgstr "guard :: forall m. Alternative m => Boolean -> m Unit\n" #. type: Plain text -#: text/chapter11.md:664 +#: text/chapter11.md:663 #, no-wrap msgid "The `<|>` operator allows us to backtrack in case of failure. To see how this is useful, let's define a variant of the `split` combinator which only matches upper case characters:\n" msgstr "" "`<|>`演算子は失敗時にバックトラッキングできるようにします。\n" -"これがどのように役立つかを見るために、大文字だけに適合する `split`コンビネータの亜種を定義してみましょう。\n" +"これがどのように役立つかを見るために、大文字だけに照合する`split`コンビネータの亜種を定義してみましょう。\n" #. type: Fenced code block (haskell) -#: text/chapter11.md:665 +#: text/chapter11.md:664 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Split.purs:upper}}\n" msgstr "{{#include ../exercises/chapter11/src/Split.purs:upper}}\n" #. type: Plain text -#: text/chapter11.md:670 +#: text/chapter11.md:669 msgid "" "Here, we use a `guard` to fail if the string is not upper case. Note that " -"this code looks very similar to the array comprehensions we saw earlier - " +"this code looks very similar to the array comprehensions we saw earlier – " "using `MonadPlus` in this way, we sometimes refer to constructing _monad " "comprehensions_." msgstr "" -"ここで、文字列が大文字でない場合に失敗するよう `guard`を使用しています。この" -"コードは前に見た配列内包表記とよく似ていることに注目してください。このように" -"`MonadPlus`を使うことは、 _モナド内包表記_ (monad comprehensions) の構築と呼" -"ばれることがあります。" +"ここで、文字列が大文字でない場合に失敗するよう、`guard`を使用しています。\n" +"なお、このコードは前に見た配列内包表記とよく似ています。\n" +"このように`MonadPlus`を使うことは、*モナド内包表記*の構築と呼ばれることがあり" +"ます。" #. type: Title ## -#: text/chapter11.md:671 +#: text/chapter11.md:670 #, no-wrap msgid "Backtracking" msgstr "バックトラッキング" #. type: Plain text -#: text/chapter11.md:674 +#: text/chapter11.md:673 #, no-wrap msgid "We can use the `<|>` operator to backtrack to another alternative in case of failure. To demonstrate this, let's define one more parser, which matches lower case characters:\n" msgstr "" @@ -7380,36 +7391,36 @@ msgstr "" "これを確かめるために、小文字に一致するもう1つの構文解析器を定義してみましょう。\n" #. type: Fenced code block (haskell) -#: text/chapter11.md:675 +#: text/chapter11.md:674 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Split.purs:lower}}\n" msgstr "{{#include ../exercises/chapter11/src/Split.purs:lower}}\n" #. type: Plain text -#: text/chapter11.md:680 +#: text/chapter11.md:679 msgid "" "With this, we can define a parser which eagerly matches many upper case " "characters if the first character is upper case, or many lower case " "character if the first character is lower case:" msgstr "" -"これにより、まずもし最初の文字が大文字なら複数の大文字に適合し、さもなくばも" -"し最初の文字が小文字なら複数の小文字に適合する、という構文解析器を定義できま" +"これにより、まずもし最初の文字が大文字なら複数の大文字に照合し、さもなくばも" +"し最初の文字が小文字なら複数の小文字に照合する、という構文解析器を定義できま" "す。" #. type: Fenced code block (text) -#: text/chapter11.md:681 +#: text/chapter11.md:680 #, no-wrap msgid "> upperOrLower = some upper <|> some lower\n" msgstr "> upperOrLower = some upper <|> some lower\n" #. type: Plain text -#: text/chapter11.md:686 +#: text/chapter11.md:685 msgid "This parser will match characters until the case changes:" msgstr "" -"この構文解析器は、大文字と小文字が切り替わるまで、文字に適合し続けます。" +"この構文解析器は、大文字と小文字が切り替わるまで、文字に照合し続けます。" #. type: Fenced code block (text) -#: text/chapter11.md:687 +#: text/chapter11.md:686 #, no-wrap msgid "" "> runParser upperOrLower \"abcDEF\"\n" @@ -7427,14 +7438,14 @@ msgstr "" " ]))\n" #. type: Plain text -#: text/chapter11.md:697 +#: text/chapter11.md:696 msgid "" "We can even use `many` to fully split a string into its lower and upper case " "components:" msgstr "また、`many`を使うと文字列を小文字と大文字の要素に完全に分割できます。" #. type: Fenced code block (text) -#: text/chapter11.md:698 +#: text/chapter11.md:697 #, no-wrap msgid "" "> components = many upperOrLower\n" @@ -7466,57 +7477,57 @@ msgstr "" " ]))\n" #. type: Plain text -#: text/chapter11.md:715 +#: text/chapter11.md:714 msgid "" "Again, this illustrates the power of reusability that monad transformers " -"bring - we were able to write a backtracking parser in a declarative style " +"bring – we were able to write a backtracking parser in a declarative style " "with only a few lines of code, by reusing standard abstractions!" msgstr "" -"繰り返しになりますが、これはモナド変換子がもたらす再利用性の威力を示していま" +"繰り返しになりますが、これはモナド変換子が齎す再利用性の威力を示していま" "す。\n" "標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器" "を、ほんの数行のコードで書くことができました。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 msgid "" "(Easy) Remove the calls to the `lift` function from your implementation of " "the `string` parser. Verify that the new implementation type checks, and " -"convince yourself that it should." +"convince yourself it should." msgstr "" -"(簡単)`string`構文解析器の実装から `lift`関数の呼び出しを取り除いてくださ" +"(簡単)`string`構文解析器の実装から`lift`関数の呼び出しを取り除いてくださ" "い。\n" -"新しい実装の型が整合していることを確認し、なぜそのようになるのかをよく納得し" -"ておきましょう。" +"新しい実装の型検査が通ることを確認し、そうなることを納得するまで確かめましょ" +"う。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 msgid "" "(Medium) Use your `string` parser with the `some` combinator to write a " -"parser `asFollowedByBs` which recognizes strings consisting of several " -"copies of the string `\"a\"` followed by several copies of the string " -"`\"b\"`." +"parser `asFollowedByBs` that recognizes strings consisting of several copies " +"of the string `\"a\"` followed by several copies of the string `\"b\"`." msgstr "" -"(普通)`string`構文解析器と `many`コンビネータを使って、文字列`\"a\"`の連続" -"と、それに続く文字列 `\"b\"`の連続からなる文字列を認識する構文解析器" -"`asFollowedByBs`を書いてください。" +"(普通)`string`構文解析器と`some`コンビネータを使って構文解析器" +"`asFollowedByBs`を書いてください。\n" +"これは文字列`\"a\"`の連続と、それに続く文字列`\"b\"`の連続からなる文字列を認" +"識するものです。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 msgid "" -"(Medium) Use the `<|>` operator to write a parser `asOrBs` which recognizes " +"(Medium) Use the `<|>` operator to write a parser `asOrBs` that recognizes " "strings of the letters `a` or `b` in any order." msgstr "" -"(普通)`<|>`演算子を使って、文字 `a`と文字 `b`が任意の順序で現れるような文字" -"列を認識する構文解析器`asOrBs`を書いてください。" +"(普通)`<|>`演算子を使って構文解析器`asOrBs`を書いてください。\n" +"これは文字`a`と文字`b`が任意の順序で現れる文字列を認識します。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 msgid "(Difficult) The `Parser` monad might also be defined as follows:" msgstr "(難しい)`Parser`モナドを次のようにも定義できます。" #. type: Plain text -#: text/chapter11.md:726 +#: text/chapter11.md:725 #, no-wrap msgid "" " ```haskell\n" @@ -7528,35 +7539,34 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:728 +#: text/chapter11.md:727 #, no-wrap msgid " What effect does this change have on our parsing functions?\n" msgstr " このように変更すると、構文解析関数にどのような影響を与えるでしょうか。\n" #. type: Title ## -#: text/chapter11.md:729 +#: text/chapter11.md:728 #, no-wrap msgid "The RWS Monad" msgstr "RWSモナド" #. type: Plain text -#: text/chapter11.md:732 +#: text/chapter11.md:731 msgid "" "One particular combination of monad transformers is so common that it is " "provided as a single monad transformer in the `transformers` package. The " -"`Reader`, `Writer` and `State` monads are combined into the _reader-writer-" -"state_ monad, or more simply the `RWS` monad. This monad has a corresponding " -"monad transformer called the `RWST` monad transformer." +"`Reader`, `Writer`, and `State` monads are combined into the _reader-writer-" +"state_ or simply `RWS` monad. This monad has a corresponding monad " +"transformer called the `RWST` monad transformer." msgstr "" "モナド変換子のとある特定の組み合わせは頻出なので、`transformers`パッケージ内" "の単一のモナド変換子として提供されています。\n" -"`Reader`、 `Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わ" +"`Reader`、`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わ" "さり、より単純に`RWS`モナドともされます。\n" -"このモナドは `RWST`モナド変換子と呼ばれる、対応するモナド変換子を持っていま" -"す。" +"このモナドは`RWST`モナド変換子という名前の、対応するモナド変換子を持ちます。" #. type: Plain text -#: text/chapter11.md:734 +#: text/chapter11.md:733 msgid "" "We will use the `RWS` monad to model the game logic for our text adventure " "game." @@ -7565,7 +7575,7 @@ msgstr "" "ます。" #. type: Plain text -#: text/chapter11.md:736 +#: text/chapter11.md:735 msgid "" "The `RWS` monad is defined in terms of three type parameters (in addition to " "its return type):" @@ -7573,34 +7583,34 @@ msgstr "" "`RWS`モナドは(戻り値の型に加えて)3つの型変数を使って定義されています。" #. type: Fenced code block (haskell) -#: text/chapter11.md:737 +#: text/chapter11.md:736 #, no-wrap msgid "type RWS r w s = RWST r w s Identity\n" msgstr "type RWS r w s = RWST r w s Identity\n" #. type: Plain text -#: text/chapter11.md:742 +#: text/chapter11.md:741 msgid "" -"Notice that the `RWS` monad is defined in terms of its own monad " -"transformer, by setting the base monad to `Identity` which provides no side-" -"effects." +"Notice that the `RWS` monad is defined as its own monad transformer by " +"setting the base monad to `Identity`, which provides no side-effects." msgstr "" -"ここで、副作用を提供しない`Identity`を基底のモナドに設定することで、 `RWS`モ" -"ナドが独自のモナド変換子を用いて定義されています。" +"なお、`RWS`モナドは基底のモナドを`Identity`に設定することで独自のモナド変換子" +"として定義されています。\n" +"`Identity`は副作用を提供しないのでした。" #. type: Plain text -#: text/chapter11.md:744 +#: text/chapter11.md:743 msgid "" "The first type parameter, `r`, represents the global configuration type. The " -"second, `w`, represents the monoid which we will use to accumulate a log, " -"and the third, `s` is the type of our mutable state." +"second, `w`, represents the monoid, which we will use to accumulate a log, " +"and the third, `s`, is the type of our mutable state." msgstr "" -"第1型引数 `r`は大域的な設定の型を表します。\n" -"第2型引数 `w`はログを蓄積するために使用するモノイド、第3型引数 `s`は可変状態" -"の型を表しています。" +"最初の型引数`r`は大域的な構成の型を表します。\n" +"2つ目の`w`はログを蓄積するために使用するモノイドを表します。\n" +"3つ目の`s`は可変状態の型です。" #. type: Plain text -#: text/chapter11.md:746 +#: text/chapter11.md:745 msgid "" "In the case of our game, our global configuration is defined in a type " "called `GameEnvironment` in the `Data.GameEnvironment` module:" @@ -7609,25 +7619,25 @@ msgstr "" "`GameEnvironment`という名前の型で定義されています。" #. type: Fenced code block (haskell) -#: text/chapter11.md:747 +#: text/chapter11.md:746 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Data/GameEnvironment.purs:env}}\n" msgstr "{{#include ../exercises/chapter11/src/Data/GameEnvironment.purs:env}}\n" #. type: Plain text -#: text/chapter11.md:752 +#: text/chapter11.md:751 msgid "" -"It defines the player name, and a flag which indicates whether or not the " -"game is running in debug mode. These options will be set from the command " -"line when we come to run our monad transformer." +"It defines the player name and a flag that indicates whether or not the game " +"is running in debug mode. These options will be set from the command line " +"when we come to run our monad transformer." msgstr "" "プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義" "されています。\n" -"これらのオプションは、モナド変換子を実行するときにコマンドラインから設定され" -"ます。" +"モナド変換子を実行するとなると、これらのオプションがコマンドラインから設定さ" +"れます。" #. type: Plain text -#: text/chapter11.md:754 +#: text/chapter11.md:753 msgid "" "The mutable state is defined in a type called `GameState` in the `Data." "GameState` module:" @@ -7636,7 +7646,7 @@ msgstr "" "ます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:755 +#: text/chapter11.md:754 #, no-wrap msgid "" "{{#include ../exercises/chapter11/src/Data/GameState.purs:imports}}\n" @@ -7648,7 +7658,7 @@ msgstr "" "{{#include ../exercises/chapter11/src/Data/GameState.purs:GameState}}\n" #. type: Plain text -#: text/chapter11.md:762 +#: text/chapter11.md:761 msgid "" "The `Coords` data type represents points on a two-dimensional grid, and the " "`GameItem` data type is an enumeration of the items in the game:" @@ -7657,16 +7667,16 @@ msgstr "" "ムの列挙です。" #. type: Fenced code block (haskell) -#: text/chapter11.md:763 +#: text/chapter11.md:762 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Data/GameItem.purs:GameItem}}\n" msgstr "{{#include ../exercises/chapter11/src/Data/GameItem.purs:GameItem}}\n" #. type: Plain text -#: text/chapter11.md:768 +#: text/chapter11.md:767 msgid "" "The `GameState` type uses two new data structures: `Map` and `Set`, which " -"represent sorted maps and sorted sets respectively. The `items` property is " +"represent sorted maps and sorted sets, respectively. The `items` property is " "a mapping from coordinates of the game grid to sets of game items at that " "location. The `player` property stores the current coordinates of the " "player, and the `inventory` property stores a set of game items currently " @@ -7674,33 +7684,33 @@ msgid "" msgstr "" "`GameState`型は2つの新しいデータ構造を使っています。\n" "`Map`と`Set`はそれぞれ整列されたマップと整列された集合を表します。\n" -"`items`属性は、そのゲーム平面上の座標からゲームアイテムの集合への対応付けに" -"なっています。\n" -"`player`属性はプレイヤーの現在の座標を格納しており、 `inventory`属性は現在プ" -"レイヤーが保有するゲームアイテムの集合です。" +"`items`属性は、ゲーム平面上の座標からその位置にあるゲームアイテムの集合への対" +"応付けです。\n" +"`player`属性はプレイヤーの現在の座標を格納し、`inventory`属性は現在プレイヤー" +"が保有するゲームアイテムの集合を格納します。" #. type: Plain text -#: text/chapter11.md:770 +#: text/chapter11.md:769 msgid "" -"The `Map` and `Set` data structures are sorted by their keys, can be used " -"with any key type in the `Ord` type class. This means that the keys in our " -"data structures should be totally ordered." +"The `Map` and `Set` data structures are sorted by their keys, and can be " +"used with any key type in the `Ord` type class. This means that the keys in " +"our data structures should be totally ordered." msgstr "" -"`Map`と `Set`のデータ構造はキーによって整列され、 `Ord`型クラスの任意の型を" -"キーとして使用できます。これは今回のデータ構造のキーが完全に順序付けできるこ" -"とを意味します。" +"`Map`と`Set`のデータ構造はキーによって整列され、このキーには`Ord`型クラスの任" +"意の型を使えます。\n" +"つまりデータ構造中のキーは完全に順序付けされます。" #. type: Plain text -#: text/chapter11.md:772 +#: text/chapter11.md:771 msgid "" "We will see how the `Map` and `Set` structures are used as we write the " "actions for our game." msgstr "" -"ゲームのアクションを書く上で`Map`と `Set`構造をどのように使っていくのかを見て" -"いきます。" +"ゲームの動作を書く上で`Map`と`Set`構造をどのように使っていくのかを見ていきま" +"す。" #. type: Plain text -#: text/chapter11.md:774 +#: text/chapter11.md:773 msgid "" "For our log, we will use the `List String` monoid. We can define a type " "synonym for our `Game` monad, implemented using `RWS`:" @@ -7709,85 +7719,85 @@ msgstr "" "`Game`モナド用の型同義語を定義し、`RWS`を使って実装できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:775 +#: text/chapter11.md:774 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:Game}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:Game}}\n" #. type: Title ## -#: text/chapter11.md:779 +#: text/chapter11.md:778 #, no-wrap msgid "Implementing Game Logic" msgstr "ゲームロジックの実装" #. type: Plain text -#: text/chapter11.md:782 +#: text/chapter11.md:781 msgid "" -"Our game is going to be built from simple actions defined in the `Game` " -"monad, by reusing the actions from the `Reader`, `Writer` and `State` " -"monads. At the top level of our application, we will run the pure " -"computations in the `Game` monad, and use the `Effect` monad to turn the " -"results into observable side-effects, such as printing text to the console." +"Our game will be built from simple actions defined in the `Game` monad by " +"reusing the actions from the `Reader`, `Writer`, and `State` monads. At the " +"top level of our application, we will run the pure computations in the " +"`Game` monad and use the `Effect` monad to turn the results into observable " +"side-effects, such as printing text to the console." msgstr "" -"今回は`Reader`モナドと`Writer`モナドと`State`モナドのアクションを再利用し、" -"`Game`モナドで定義されている単純なアクションを組み合わせてゲームを構築してい" -"きます。\n" +"`Reader`、`Writer`、`State`モナドの動作を再利用することで、`Game`モナドで定義" +"されている単純な動作を組み合わせてゲームを構築していきます。\n" "このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モ" -"ナドはコンソールにテキストを出力するような観測可能な副作用へと結果を変換する" -"ために使っています。" +"ナドは結果からコンソールにテキストを出力するような観測可能な副作用へと変換す" +"るために使っています。" #. type: Plain text -#: text/chapter11.md:784 +#: text/chapter11.md:783 msgid "" "One of the simplest actions in our game is the `has` action. This action " "tests whether the player's inventory contains a particular game item. It is " "defined as follows:" msgstr "" -"このゲームで最も簡単なアクションの1つは `has`アクションです。このアクションは" -"プレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調べます。こ" -"れは次のように定義されます。" +"このゲームで最も簡単な動作の1つは `has`動作です。\n" +"この動作はプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調" +"べます。\n" +"これは次のように定義されます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:785 +#: text/chapter11.md:784 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:has}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:has}}\n" #. type: Plain text -#: text/chapter11.md:790 +#: text/chapter11.md:789 msgid "" "This function uses the `get` action defined in the `MonadState` type class " -"to read the current game state, and then uses the `member` function defined " +"to read the current game state and then uses the `member` function defined " "in `Data.Set` to test whether the specified `GameItem` appears in the `Set` " "of inventory items." msgstr "" -"この関数は、現在のゲームの状態を読み取るために `MonadState`型クラスで定義され" -"ている `get`アクションを使っています。\n" -"またそれから指定した`GameItem`が持ち物アイテムの`Set`に出現するかどうかを調べ" -"るために`Data.Set`で定義されている `member`関数を使っています。" +"この関数は、現在のゲームの状態を読み取るために`MonadState`型クラスで定義され" +"ている`get`動作を使っています。\n" +"それから指定した`GameItem`が持ち物のアイテムの`Set`に出現するかどうかを調べる" +"ために`Data.Set`で定義されている`member`関数を使っています。" #. type: Plain text -#: text/chapter11.md:792 +#: text/chapter11.md:791 msgid "" "Another action is the `pickUp` action. It adds a game item to the player's " "inventory if it appears in the current room. It uses actions from the " "`MonadWriter` and `MonadState` type classes. First of all, it reads the " "current game state:" msgstr "" -"他にも `pickUp`アクションがあります。\n" +"他にも`pickUp`動作があります。\n" "現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加" "します。\n" -"これには`MonadWriter`と `MonadState`型クラスのアクションを使っています。\n" +"これには`MonadWriter`と`MonadState`型クラスの動作を使っています。\n" "一番最初に現在のゲームの状態を読み取ります。" #. type: Fenced code block (haskell) -#: text/chapter11.md:793 +#: text/chapter11.md:792 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_start}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_start}}\n" #. type: Plain text -#: text/chapter11.md:798 +#: text/chapter11.md:797 msgid "" "Next, `pickUp` looks up the set of items in the current room. It does this " "by using the `lookup` function defined in `Data.Map`:" @@ -7796,25 +7806,25 @@ msgstr "" "これは`Data.Map`で定義された `lookup`関数を使って行います。" #. type: Fenced code block (haskell) -#: text/chapter11.md:799 +#: text/chapter11.md:798 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_case}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_case}}\n" #. type: Plain text -#: text/chapter11.md:804 +#: text/chapter11.md:803 msgid "" "The `lookup` function returns an optional result indicated by the `Maybe` " "type constructor. If the key does not appear in the map, the `lookup` " -"function returns `Nothing`, otherwise it returns the corresponding value in " +"function returns `Nothing`; otherwise, it returns the corresponding value in " "the `Just` constructor." msgstr "" -"`lookup`関数は `Maybe`型構築子で示されたオプショナルな結果を返します。\n" -"`lookup`関数は、キーがマップにない場合は `Nothing`を返し、それ以外の場合は " -"`Just`構築子で対応する値を返します。" +"`lookup`関数は`Maybe`型構築子で示される省略可能な結果を返します。\n" +"`lookup`関数は、キーがマップにない場合は`Nothing`を返します。\n" +"それ以外の場合は`Just`構築子で対応する値を返します。" #. type: Plain text -#: text/chapter11.md:806 +#: text/chapter11.md:805 msgid "" "We are interested in the case where the corresponding item set contains the " "specified game item. Again we can test this using the `member` function:" @@ -7824,72 +7834,72 @@ msgstr "" "ここでも`member`関数を使うとこれを調べることができます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:807 +#: text/chapter11.md:806 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}}\n" #. type: Plain text -#: text/chapter11.md:812 +#: text/chapter11.md:811 msgid "" -"In this case, we can use `put` to update the game state, and `tell` to add a " +"In this case, we can use `put` to update the game state and `tell` to add a " "message to the log:" msgstr "" -"この場合、 `put`を使ってゲームの状態を更新し、 `tell`を使ってログにメッセージ" -"を追加できます。" +"この場合、`put`を使ってゲームの状態を更新し、`tell`を使ってログに文言を追加で" +"きます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:813 +#: text/chapter11.md:812 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_body}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_body}}\n" #. type: Plain text -#: text/chapter11.md:818 +#: text/chapter11.md:817 msgid "" -"Note that there is no need to `lift` either of the two computations here, " +"Note that there is no need to `lift` either of the two computations here " "because there are appropriate instances for both `MonadState` and " "`MonadWriter` for our `Game` monad transformer stack." msgstr "" "ここで2つの計算のどちらも`lift`が必要ないことに注意してください。\n" -"なぜなら`MonadState`と `MonadWriter`の両方について `Game`モナド変換子スタック" -"用の適切なインスタンスが存在するからです。" +"なぜなら`MonadState`と`MonadWriter`の両方について`Game`モナド変換子スタック用" +"の適切なインスタンスが存在するからです。" #. type: Plain text -#: text/chapter11.md:820 +#: text/chapter11.md:819 msgid "" "The argument to `put` uses a record update to modify the game state's " -"`items` and `inventory` fields. We use the `update` function from `Data.Map` " -"which modifies a value at a particular key. In this case, we modify the set " -"of items at the player's current location, using the `delete` function to " -"remove the specified item from the set. `inventory` is also updated, using " -"`insert` to add the new item to the player's inventory set." +"`items` and `inventory` fields. We use the `update` function from `Data." +"Map`, which modifies a value at a particular key. In this case, we modify " +"the set of items at the player's current location, using the `delete` " +"function to remove the specified item from the set. `inventory` is also " +"updated, using `insert` to add the new item to the player's inventory set." msgstr "" -"`put`への引数では、レコード更新を使ってゲームの状態の `items`と`inventory`" +"`put`への引数では、レコード更新を使ってゲームの状態の`items`及び`inventory`" "フィールドを変更しています。\n" -"また、特定のキーの値を変更する`Data.Map`の `update`関数を使っています。\n" -"このとき、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`" -"関数を使って指定したアイテムを集合から取り除いています。\n" -"`insert`を使って新しいアイテムをプレイヤーの持ち物集合に加えるときにも、" +"また、特定のキーの値を変更する`Data.Map`の`update`関数を使っています。\n" +"今回の場合、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、" +"`delete`関数を使って指定したアイテムを集合から取り除いています。\n" +"`insert`を使って新しいアイテムをプレイヤーの持ち物の集合に加えるときにも、" "`inventory`は更新されます。" #. type: Plain text -#: text/chapter11.md:822 +#: text/chapter11.md:821 msgid "" -"Finally, the `pickUp` function handles the remaining cases, by notifying the " +"Finally, the `pickUp` function handles the remaining cases by notifying the " "user using `tell`:" msgstr "" -"最後に、`pickUp`関数は `tell`を使ってユーザに次のように通知することにより、残" -"りの場合を処理します。" +"最後に、`pickUp`関数は`tell`を使ってユーザに通知することにより、残りの場合を" +"処理します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:823 +#: text/chapter11.md:822 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:pickup_err}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_err}}\n" #. type: Plain text -#: text/chapter11.md:828 +#: text/chapter11.md:827 msgid "" "As an example of using the `Reader` monad, we can look at the code for the " "`debug` command. This command allows the user to inspect the game state at " @@ -7900,62 +7910,62 @@ msgstr "" "時にゲームの状態を調べることができます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:829 +#: text/chapter11.md:828 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:debug}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:debug}}\n" #. type: Plain text -#: text/chapter11.md:834 +#: text/chapter11.md:833 msgid "" "Here, we use the `ask` action to read the game configuration. Again, note " "that we don't need to `lift` any computation, and we can use actions defined " -"in the `MonadState`, `MonadReader` and `MonadWriter` type classes in the " +"in the `MonadState`, `MonadReader`, and `MonadWriter` type classes in the " "same do notation block." msgstr "" -"ここでは、ゲームの設定を読み込むために `ask`アクションを使用しています。\n" -"繰り返しますが、どの計算でも`lift`は必要がなく、同じdo記法ブロック内で" -"`MonadState`、 `MonadReader`、 `MonadWriter`型クラスで定義されているアクショ" -"ンを使うことができることに注意してください。" +"ここでは、ゲームの構成を読み込むために`ask`動作を使用しています。\n" +"繰り返しますが、どの計算でも`lift`する必要がなく、同じdo記法ブロック内で" +"`MonadState`、`MonadReader`、`MonadWriter`型クラスで定義されている動作を使え" +"る点に注意してください。" #. type: Plain text -#: text/chapter11.md:836 +#: text/chapter11.md:835 msgid "" -"If the `debugMode` flag is set, then the `tell` action is used to write the " -"state to the log. Otherwise, an error message is added." +"If the `debugMode` flag is set, the `tell` action is used to write the state " +"to the log. Otherwise, an error message is added." msgstr "" -"`debugMode`フラグが設定されている場合、 `tell`アクションを使うとログに状態が" -"追加されます。\n" -"そうでなければ、エラーメッセージが追加されます。" +"`debugMode`フラグが設定されている場合、`tell`動作を使うとログに状態が書き込ま" +"れます。\n" +"そうでなければ、エラー文言が追加されます。" #. type: Plain text -#: text/chapter11.md:838 +#: text/chapter11.md:837 msgid "" "The remainder of the `Game` module defines a set of similar actions, each " -"using only the actions defined by the `MonadState`, `MonadReader` and " +"using only the actions defined by the `MonadState`, `MonadReader`, and " "`MonadWriter` type classes." msgstr "" -"`Game.purs`モジュールの残りの部分では、`MonadState`型クラスと`MonadReader`型" -"クラスと`MonadWriter`型クラスでそれぞれ定義されたアクションだけを使い、同様の" -"アクションが定義されています。" +"`Game`モジュールの残りの部分では同様の動作の集合が定義されています。\n" +"各動作は`MonadState`、`MonadReader`、`MonadWriter`型クラスにより定義された動" +"作のみを使っています。" #. type: Title ## -#: text/chapter11.md:839 +#: text/chapter11.md:838 #, no-wrap msgid "Running the Computation" msgstr "計算の実行" #. type: Plain text -#: text/chapter11.md:842 +#: text/chapter11.md:841 msgid "" "Since our game logic runs in the `RWS` monad, it is necessary to run the " -"computation in order to respond to the user's commands." +"computation to respond to the user's commands." msgstr "" -"このゲームロジックは `RWS`モナドで動くため、ユーザのコマンドに応答するために" -"は計算する必要があります。" +"このゲームロジックは`RWS`モナドで動くため、ユーザのコマンドに応答するために計" +"算する必要があります。" #. type: Plain text -#: text/chapter11.md:844 +#: text/chapter11.md:843 msgid "" "The front-end of our game is built using two packages: `optparse`, which " "provides applicative command line parsing, and `node-readline`, which wraps " @@ -7968,7 +7978,7 @@ msgstr "" "ジュールを梱包する `node-readline`パッケージです。" #. type: Plain text -#: text/chapter11.md:846 +#: text/chapter11.md:845 msgid "" "The interface to our game logic is provided by the function `game` in the " "`Game` module:" @@ -7977,22 +7987,22 @@ msgstr "" "て提供されます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:847 +#: text/chapter11.md:846 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Game.purs:game_sig}}\n" msgstr "{{#include ../exercises/chapter11/src/Game.purs:game_sig}}\n" #. type: Plain text -#: text/chapter11.md:852 +#: text/chapter11.md:851 msgid "" "To run this computation, we pass a list of words entered by the user as an " -"array of strings, and run the resulting `RWS` computation using `runRWS`:" +"array of strings and run the resulting `RWS` computation using `runRWS`:" msgstr "" "これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してか" -"ら、 `runRWS`を使って `RWS`の計算結果を実行します。" +"ら、`runRWS`を使って結果の`RWS`を計算します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:853 +#: text/chapter11.md:852 #, no-wrap msgid "" "data RWSResult state result writer = RWSResult state result writer\n" @@ -8004,20 +8014,20 @@ msgstr "" "runRWS :: forall r w s a. RWS r w s a -> r -> s -> RWSResult s a w\n" #. type: Plain text -#: text/chapter11.md:860 +#: text/chapter11.md:859 msgid "" -"`runRWS` looks like a combination of `runReader`, `runWriter` and " +"`runRWS` looks like a combination of `runReader`, `runWriter`, and " "`runState`. It takes a global configuration and an initial state as an " -"argument, and returns a data structure containing the log, the result and " +"argument and returns a data structure containing the log, the result, and " "the final state." msgstr "" -"`runRWS`は `runReader`、 `runWriter`、 `runState`を組み合わせたように見えま" +"`runRWS`は`runReader`、`runWriter`、`runState`を組み合わせたように見えま" "す。\n" -"これは、引数として大域的な設定及び初期状態をとり、ログ、結果、最的な終状態を" -"含むデータ構造を返します。" +"引数として大域的な構成及び初期状態を取り、ログ、結果、最終的な状態を含むデー" +"タ構造を返します。" #. type: Plain text -#: text/chapter11.md:862 +#: text/chapter11.md:861 msgid "" "The front-end of our application is defined by a function `runGame`, with " "the following type signature:" @@ -8026,13 +8036,13 @@ msgstr "" "よって定義されます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:863 +#: text/chapter11.md:862 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_sig}}\n" msgstr "{{#include ../exercises/chapter11/src/Main.purs:runGame_sig}}\n" #. type: Plain text -#: text/chapter11.md:868 +#: text/chapter11.md:867 msgid "" "This function interacts with the user via the console (using the `node-" "readline` and `console` packages). `runGame` takes the game configuration as " @@ -8043,18 +8053,18 @@ msgstr "" "`runGame`は関数の引数としてのゲームの設定を取ります。" #. type: Plain text -#: text/chapter11.md:870 +#: text/chapter11.md:869 msgid "" "The `node-readline` package provides the `LineHandler` type, which " -"represents actions in the `Effect` monad which handle user input from the " +"represents actions in the `Effect` monad, which handle user input from the " "terminal. Here is the corresponding API:" msgstr "" "`node-readline`パッケージでは`LineHandler`型が提供されています。\n" -"これは端末からのユーザ入力を扱う `Effect`モナドのアクションを表します。\n" +"これは端末からのユーザ入力を扱う`Effect`モナドの動作を表します。\n" "対応するAPIは次の通りです。" #. type: Fenced code block (haskell) -#: text/chapter11.md:871 +#: text/chapter11.md:870 #, no-wrap msgid "" "type LineHandler a = String -> Effect a\n" @@ -8074,18 +8084,18 @@ msgstr "" " -> Effect Unit\n" #. type: Plain text -#: text/chapter11.md:882 +#: text/chapter11.md:881 msgid "" -"The `Interface` type represents a handle for the console, and is passed as " -"an argument to the functions which interact with it. An `Interface` can be " +"The `Interface` type represents a handle for the console and is passed as an " +"argument to the functions which interact with it. An `Interface` can be " "created using the `createConsoleInterface` function:" msgstr "" -"`Interface`型はコンソールの制御対象を表しており、コンソールとやり取りする関数" -"への引数として渡されます。\n" -"`createConsoleInterface`関数を使用すると `Interface`を作成できます。" +"`Interface`型はコンソールの制御子を表しており、コンソールとやり取りする関数へ" +"の引数として渡されます。\n" +"`createConsoleInterface`関数を使用すると`Interface`を作成できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:883 +#: text/chapter11.md:882 #, no-wrap msgid "" "{{#include ../exercises/chapter11/src/Main.purs:import_RL}}\n" @@ -8097,7 +8107,7 @@ msgstr "" "{{#include ../exercises/chapter11/src/Main.purs:runGame_interface}}\n" #. type: Plain text -#: text/chapter11.md:890 +#: text/chapter11.md:889 msgid "" "The first step is to set the prompt at the console. We pass the `interface` " "handle, and provide the prompt string and indentation level:" @@ -8106,13 +8116,13 @@ msgstr "" "`interface`制御対象を渡し、プロンプト文字列と字下げレベルを与えます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:891 +#: text/chapter11.md:890 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_prompt}}\n" msgstr "{{#include ../exercises/chapter11/src/Main.purs:runGame_prompt}}\n" #. type: Plain text -#: text/chapter11.md:896 +#: text/chapter11.md:895 msgid "" "In our case, we are interested in implementing the line handler function. " "Our line handler is defined using a helper function in a `let` declaration, " @@ -8122,13 +8132,13 @@ msgstr "" "ここでの行制御は`let`宣言内の補助関数を使って次のように定義されています。" #. type: Fenced code block (haskell) -#: text/chapter11.md:897 +#: text/chapter11.md:896 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_lineHandler}}\n" msgstr "{{#include ../exercises/chapter11/src/Main.purs:runGame_lineHandler}}\n" #. type: Plain text -#: text/chapter11.md:902 +#: text/chapter11.md:901 msgid "" "The `let` binding is closed over both the game configuration, named `env`, " "and the console handle, named `interface`." @@ -8137,7 +8147,7 @@ msgstr "" "対象を包み込んでいます。" #. type: Plain text -#: text/chapter11.md:904 +#: text/chapter11.md:903 msgid "" "Our handler takes an additional first argument, the game state. This is " "required since we need to pass the game state to `runRWS` to run the game's " @@ -8148,20 +8158,20 @@ msgstr "" "ので、これは必要となっています。" #. type: Plain text -#: text/chapter11.md:906 +#: text/chapter11.md:905 msgid "" "The first thing this action does is to break the user input into words using " "the `split` function from the `Data.String` module. It then uses `runRWS` to " "run the `game` action (in the `RWS` monad), passing the game environment and " "current game state." msgstr "" -"このアクションが最初に行うことは、 `Data.String`モジュールの `split`関数を使" -"用して、ユーザーの入力を単語に分割することです。\n" +"この動作が最初に行うことは、`Data.String`モジュールの `split`関数を使用して、" +"ユーザーの入力を単語に分割することです。\n" "それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`" -"モナドで)`game`アクションを実行しています。" +"モナドで)`game`動作を実行しています。" #. type: Plain text -#: text/chapter11.md:908 +#: text/chapter11.md:907 msgid "" "Having run the game logic, which is a pure computation, we need to print any " "log messages to the screen and show the user a prompt for the next command. " @@ -8170,30 +8180,30 @@ msgid "" "update the line handler function to use the updated game state, and the " "prompt is displayed again using the `prompt` action." msgstr "" -"純粋な計算であるゲームロジックを実行するには、画面に全てのログメッセージを出" -"力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。\n" -"`for_`アクションが(`List String`型の)ログを走査し、コンソールにその内容を出" -"力するために使われています。\n" +"純粋な計算であるゲームロジックを実行するには、画面に全てのログ文言を出力し" +"て、ユーザに次のコマンドのためのプロンプトを表示する必要があります。\n" +"`for_`動作が(`List String`型の)ログを走査し、コンソールにその内容を出力する" +"ために使われています。\n" "最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新" -"し、`prompt`アクションを使ってプロンプトを再び表示しています。" +"し、`prompt`動作を使ってプロンプトを再び表示しています。" #. type: Plain text -#: text/chapter11.md:910 +#: text/chapter11.md:909 msgid "" "The `runGame` function finally attaches the initial line handler to the " -"console interface, and displays the initial prompt:" +"console interface and displays the initial prompt:" msgstr "" "`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付け" -"て、最初のプロンプトを表示します。" +"て、初期プロンプトを表示します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:911 +#: text/chapter11.md:910 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:runGame_attach_handler}}\n" msgstr "{{#include ../exercises/chapter11/src/Main.purs:runGame_attach_handler}}\n" #. type: Bullet: ' 1. ' -#: text/chapter11.md:919 +#: text/chapter11.md:918 msgid "" "(Medium) Implement a new command `cheat`, which moves all game items from " "the game grid into the user's inventory. Create a function `cheat :: Game " @@ -8205,33 +8215,34 @@ msgstr "" "ください。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:919 +#: text/chapter11.md:918 msgid "" "(Difficult) The `Writer` component of the `RWS` monad is currently used for " "two types of messages: error messages and informational messages. Because of " "this, several parts of the code use case statements to handle error cases." msgstr "" -"(難しい)`RWS`モナドの ` Writer`コンポーネントは、エラーメッセージと情報メッ" -"セージの2つの種類のメッセージのために使われています。\n" +"(難しい)`RWS`モナドの ` Writer`コンポーネントは、エラー文言とお知らせ文言の" +"2つの種類の文言のために使われています。\n" "このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用して" "います。" #. type: Plain text -#: text/chapter11.md:921 +#: text/chapter11.md:920 #, no-wrap -msgid " Refactor the code to use the `ExceptT` monad transformer to handle the error messages, and `RWS` to handle informational messages. _Note:_ There are no tests for this exercise.\n" +msgid " Refactor the code to use the `ExceptT` monad transformer to handle the error messages and `RWS` to handle informational messages. _Note:_ There are no tests for this exercise.\n" msgstr "" -" エラーメッセージを扱うのに `ExceptT`モナド変換子を使うようにし、情報メッセージを扱うのに`RWS`を使うようにするよう、コードをリファクタリングしてください。\n" -" *補足*:この演習にはテストはありません。\n" +" コードをリファクタリングしてください。\n" +" エラー文言を扱うのに`ExceptT`モナド変換子を使い、お知らせ文言を扱うのに`RWS`を使います。\n" +" *補足*:この演習にはテストがありません。\n" #. type: Title ## -#: text/chapter11.md:922 +#: text/chapter11.md:921 #, no-wrap msgid "Handling Command Line Options" msgstr "コマンドラインオプションの扱い" #. type: Plain text -#: text/chapter11.md:925 +#: text/chapter11.md:924 msgid "" "The final piece of the application is responsible for parsing command line " "options and creating the `GameEnvironment` configuration record. For this, " @@ -8242,7 +8253,7 @@ msgstr "" "このためには`optparse`パッケージを使用します。" #. type: Plain text -#: text/chapter11.md:927 +#: text/chapter11.md:926 msgid "" "`optparse` is an example of _applicative command line option parsing_. " "Recall that an applicative functor allows us to lift functions of arbitrary " @@ -8265,13 +8276,13 @@ msgstr "" # TODO: 原文でもUnicodeの矢印になっています。 #. type: Fenced code block (haskell) -#: text/chapter11.md:928 +#: text/chapter11.md:927 #, no-wrap msgid "customExecParser :: forall a. ParserPrefs → ParserInfo a → Effect a\n" msgstr "customExecParser :: forall a. ParserPrefs → ParserInfo a → Effect a\n" #. type: Plain text -#: text/chapter11.md:933 +#: text/chapter11.md:932 msgid "" "This is best illustrated by example. The application's `main` function is " "defined using `customExecParser` as follows:" @@ -8281,13 +8292,13 @@ msgstr "" "れています。" #. type: Fenced code block (haskell) -#: text/chapter11.md:934 +#: text/chapter11.md:933 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:main}}\n" msgstr "{{#include ../exercises/chapter11/src/Main.purs:main}}\n" #. type: Plain text -#: text/chapter11.md:939 +#: text/chapter11.md:938 msgid "" "The first argument is used to configure the `optparse` library. In our case, " "we simply configure it to show the help message when the application is run " @@ -8298,16 +8309,16 @@ msgstr "" "最初の引数は`optparse`ライブラリを設定するために使用されます。\n" "今回の場合、アプリケーションが引数なしで走らされたときは、(「missing " "argument」エラーを表示する代わりに)`OP.prefs OP.showHelpOnEmpty`を使って使用" -"方法のメッセージを表示するように設定していますが、`Options.Applicative." -"Builder`モジュールには他にも幾つかの選択肢を提供しています。" +"方法の文言を表示するように設定していますが、`Options.Applicative.Builder`モ" +"ジュールには他にも幾つかの選択肢を提供しています。" #. type: Plain text -#: text/chapter11.md:941 +#: text/chapter11.md:940 msgid "The second argument is the complete description of our parser program:" msgstr "2つ目の引数は解析プログラムの完全な説明です。" #. type: Fenced code block (haskell) -#: text/chapter11.md:942 +#: text/chapter11.md:941 #, no-wrap msgid "" "{{#include ../exercises/chapter11/src/Main.purs:argParser}}\n" @@ -8319,73 +8330,73 @@ msgstr "" "{{#include ../exercises/chapter11/src/Main.purs:parserOptions}}\n" #. type: Plain text -#: text/chapter11.md:949 +#: text/chapter11.md:948 #, no-wrap -msgid "Here `OP.info` combines a `Parser` with a set of options for how the help message is formatted. `env <**> OP.helper` takes any command line argument `Parser` named `env` and adds a `--help` option to it automatically. Options for the help message are of type `InfoMod`, which is a monoid, so we can use the `fold` function to add several options together.\n" +msgid "Here `OP.info` combines a `Parser` with a set of options for how the help message is formatted. `env <**> OP.helper` takes any command line argument `Parser` named `env` and automatically adds a `--help` option. Options for the help message are of type `InfoMod`, which is a monoid, so we can use the `fold` function to add several options together.\n" msgstr "" -"ここで`OP.info`は使用方法のメッセージの書式方法のオプションの集合と共に`Parser`を結合します。\n" +"ここで`OP.info`は、`Parser`をヘルプ文言の書式方法のためのオプションの集合と組み合わせます。\n" "`env <**> OP.helper`は`env`と名付けられた任意のコマンドライン引数`Parser`を取り、自動的に`--help`オプションを加えます。\n" -"使用方法のメッセージ用のオプションは型が`InfoMod`であり、これはモノイドなので`fold`関数を使って複数のオプションを一緒に追加できます。\n" +"ヘルプ文言用のオプションは型が`InfoMod`であり、これはモノイドなので、`fold`関数を使って複数のオプションを一緒に追加できます。\n" #. type: Plain text -#: text/chapter11.md:951 +#: text/chapter11.md:950 msgid "" "The interesting part of our parser is constructing the `GameEnvironment`:" msgstr "解析器の面白い部分は`GameEnvironment`の構築にあります。" #. type: Fenced code block (haskell) -#: text/chapter11.md:952 +#: text/chapter11.md:951 #, no-wrap msgid "{{#include ../exercises/chapter11/src/Main.purs:env}}\n" msgstr "{{#include ../exercises/chapter11/src/Main.purs:env}}\n" #. type: Plain text -#: text/chapter11.md:957 +#: text/chapter11.md:956 #, no-wrap -msgid "`player` and `debug` are both `Parser`s, so we can use our applicative operators `<$>` and `<*>` to lift our `gameEnvironment` function, which has the type `PlayerName -> Boolean -> GameEnvironment` over `Parser`. `OP.strOption` constructs a command line option that expects a string value, and is configured via a collection of `Mod`s folded together. `OP.flag` works similarly, but doesn't expect an associated value. `optparse` offers extensive [documentation](https://pursuit.purescript.org/packages/purescript-optparse) on different modifiers available to build various command line parsers.\n" +msgid "`player` and `debug` are both `Parser`s, so we can use our applicative operators `<$>` and `<*>` to lift our `gameEnvironment` function, which has the type `PlayerName -> Boolean -> GameEnvironment` over `Parser`. `OP.strOption` constructs a command line option that expects a string value and is configured via a collection of `Mod`s folded together. `OP.flag` works similarly but doesn't expect an associated value. `optparse` offers extensive [documentation](https://pursuit.purescript.org/packages/purescript-optparse) on different modifiers available to build various command line parsers.\n" msgstr "" -"`player`と`debug`は両方とも`Parser`なので、アプリカティブ演算子`<$>`と`<*>`を使って`gameEnvironment`関数を持ち上げることができます。\n" +"`player`と`debug`は両方とも`Parser`なので、アプリカティブ演算子`<$>`と`<*>`を使って`gameEnvironment`関数を持ち上げられます。\n" "この関数は`Parser`上で型`PlayerName -> Boolean -> GameEnvironment`を持ちます。\n" -"`OP.strOption`は文字列値を期待するコマンドラインオプションを構築し、一緒に畳み込まれた`Mod`の集まりを介して設定されています。\n" +"`OP.strOption`は文字列値を期待するコマンドラインオプションを構築し、一緒に畳み込まれた`Mod`の集まりを介して構成されています。\n" "`OP.flag`は似たような動作をしますが、関連付けられた値は期待しません。\n" -"`optparse`は多種多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。\n" +"`optparse`は多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。\n" #. type: Plain text -#: text/chapter11.md:959 +#: text/chapter11.md:958 #, no-wrap -msgid "Notice how we were able to use the notation afforded by the applicative operators to give a compact, declarative specification of our command line interface. In addition, it is simple to add new command line arguments, simply by adding a new function argument to `runGame`, and then using `<*>` to lift `runGame` over an additional argument in the definition of `env`.\n" +msgid "Notice how we used the notation afforded by the applicative operators to give a compact, declarative specification of our command line interface. In addition, it is simple to add new command line arguments by adding a new function argument to `runGame` and then using `<*>` to lift `runGame` over an additional argument in the definition of `env`.\n" msgstr "" -"アプリカティブ演算子による記法を使うことで、コマンドラインインターフェイスに対して簡潔で宣言的な仕様を与えることが可能になったことに注目です。\n" -"また、`runGame`に新しい関数引数を追加し、`env`の定義中で`<*>`を使って追加の引数まで `runGame`を持ち上げるだけで、簡単に新しいコマンドライン引数を追加できます。\n" +"アプリカティブ演算子により齎される記法を使うことで、コマンドラインインターフェイスの簡潔で宣言的な仕様を与えられた点に注目です。\n" +"加えて、新しいコマンドライン引数を追加するのは単純で、`runGame`に新しい関数引数を追加し、`env`の定義中で`<*>`を使って追加の引数まで`runGame`を持ち上げるだけでできます。\n" #. type: Bullet: ' 1. ' -#: text/chapter11.md:963 +#: text/chapter11.md:962 msgid "" "(Medium) Add a new Boolean-valued property `cheatMode` to the " "`GameEnvironment` record. Add a new command line flag `-c` to the `optparse` " -"configuration which enables cheat mode. The `cheat` command from the " -"previous exercise should be disallowed if cheat mode is not enabled." +"configuration, enabling cheat mode. The `cheat` command from the previous " +"exercise should be disallowed if cheat mode is not enabled." msgstr "" "(普通)`GameEnvironment`レコードに新しい真偽値のプロパティ`cheatMode`を追加" "してください。\n" -"また、 `optparse`設定に、チートモードを有効にする新しいコマンドラインフラグ " +"また、`optparse`の構成に、チートモードを有効にする新しいコマンドラインフラグ" "`-c`を追加してください。\n" -"チートモードが有効になっていない場合、 `cheat`コマンドは禁止されなければなり" -"ません。" +"チートモードが有効になっていない場合、前の演習の`cheat`コマンドは禁止されま" +"す。" #. type: Plain text -#: text/chapter11.md:967 +#: text/chapter11.md:966 msgid "" "This chapter was a practical demonstration of the techniques we've learned " -"so far, using monad transformers to build a pure specification of our game, " +"so far, using monad transformers to build a pure specification of our game " "and the `Effect` monad to build a front-end using the console." msgstr "" "この章ではこれまで学んできた技術を実践的に実演しました。\n" "モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロント" -"エンドを構築するための `Effect`モナドがそれです。" +"エンドを構築するための`Effect`モナドがそれです。" #. type: Plain text -#: text/chapter11.md:969 +#: text/chapter11.md:968 msgid "" "Because we separated our implementation from the user interface, it would be " "possible to create other front-ends for our game. For example, we could use " @@ -8398,33 +8409,33 @@ msgstr "" "ようなことができるでしょう。" #. type: Plain text -#: text/chapter11.md:971 +#: text/chapter11.md:970 msgid "" "We have seen how monad transformers allow us to write safe code in an " -"imperative style, where effects are tracked by the type system. In addition, " -"type classes provide a powerful way to abstract over the actions provided by " -"a monad, enabling code reuse. We were able to use standard abstractions like " -"`Alternative` and `MonadPlus` to build useful monads by combining standard " -"monad transformers." -msgstr "" -"モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見" -"てきました。\n" +"imperative style, where the type system tracks effects. In addition, type " +"classes provide a powerful way to abstract over the actions provided by a " +"monad, enabling code reuse. We used standard abstractions like `Alternative` " +"and `MonadPlus` to build useful monads by combining standard monad " +"transformers." +msgstr "" +"モナド変換子によって命令型のスタイルで安全なコードを書けることが分かりまし" +"た。\n" "このスタイルでは型システムによって作用が追跡されています。\n" -"また、型クラスはモナドが提供するアクションへと抽象化する強力な方法を提供しま" -"す。\n" -"このモナドのお陰でコードの再利用が可能になりました。\n" +"加えて、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供し、これ" +"によりコードの再利用が可能になりました。\n" "標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のよ" "うな標準的な抽象化を使用して、役に立つモナドを構築できました。" #. type: Plain text -#: text/chapter11.md:972 +#: text/chapter11.md:971 msgid "" -"Monad transformers are an excellent demonstration of the sort of expressive " -"code that can be written by relying on advanced type system features such as " -"higher-kinded polymorphism and multi-parameter type classes." +"Monad transformers are an excellent demonstration of expressive code that " +"can be written by relying on advanced type system features such as higher-" +"kinded polymorphism and multi-parameter type classes." msgstr "" -"モナド変換子は、高階多相や多変数型クラスなどの高度な型システムの機能を利用す" -"ることによって記述でき、表現力の高いコードの優れた実演となっています。" +"モナド変換子は表現力の高いコードの優れた実演となっています。\n" +"これは高階多相や多変数型クラスなどの高度な型システムの機能を利用することに" +"よって記述できるものです。" #. type: Title # #: text/chapter12.md:1 @@ -8464,11 +8475,11 @@ msgid "" "modifying the Spago build command to run the appropriate file's `main` " "method at each point." msgstr "" -"この章のソースコードは、それぞれに `main`メソッドが定義されているモジュールの" -"集合へと分割されています。\n" -"この章のそれぞれの節の内容は個別のファイルで実装されており、それぞれの時点で" -"の適切なファイルの`main`メソッドを実行できるように、Spagoビルドコマンドを変更" -"することで`Main`モジュールを合わせられるようになっています。" +"この章の各ソースコードは、`main`メソッドが定義されているモジュールの集合へと" +"分割されています。\n" +"この章の各節の内容は個別のファイルで実装されており、各時点での適切なファイル" +"の`main`メソッドを実行できるように、Spagoビルドコマンドを変更することで、" +"`Main`モジュールを合わせられるようになっています。" #. type: Plain text #: text/chapter12.md:17 @@ -8476,11 +8487,12 @@ msgid "" "The HTML file `html/index.html` contains a single `canvas` element which " "will be used in each example, and a `script` element to load the compiled " "PureScript code. To test the code for each section, open the HTML file in " -"your browser. Because most exercises target the browser, there are no unit " -"tests for this chapter." +"your browser. Because most exercises target the browser, this chapter has no " +"unit tests." msgstr "" -"HTMLファイル `html/index.html`には、各例で使用される単一の `canvas`要素、及び" -"コンパイルされたPureScriptコードを読み込む `script`要素が含まれています。\n" +"HTMLファイル`html/index.html`には、各例で使用される単一の`canvas`要素、及びコ" +"ンパイルされたPureScriptコードを読み込む`script`要素が含まれています。\n" +"各節のコードを試すにはブラウザでHTMLファイルを開きます。\n" "ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありませ" "ん。" @@ -8500,28 +8512,26 @@ msgid "" "with the Canvas API." msgstr "" "`Example/Rectangle.purs`ファイルには簡単な導入例が含まれています。\n" -"この例ではcanvasの中心に青い四角形を1つ描画します。\n" +"この例ではキャンバスの中心に青い四角形を1つ描画します。\n" "このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas APIを扱うた" -"めの`Effect`モナドのアクションを含む`Graphics.Canvas`モジュールをインポートし" -"ます。" +"めの`Effect`モナドの動作を含む`Graphics.Canvas`モジュールをインポートします。" #. type: Plain text #: text/chapter12.md:23 msgid "" "The `main` action starts, like in the other modules, by using the " -"`getCanvasElementById` action to get a reference to the canvas object, and " +"`getCanvasElementById` action to get a reference to the canvas object and " "the `getContext2D` action to access the 2D rendering context for the canvas:" msgstr "" -"他のモジュールでも同様ですが、 `main`アクションは最初に`getCanvasElementById`" -"アクションを使ってcanvasオブジェクトへの参照を取得します。\n" -"また、 `getContext2D`アクションを使ってキャンバスの2D描画コンテキストを参照し" -"ます。" +"他のモジュールでも同様ですが、`main`動作は最初に`getCanvasElementById`動作を" +"使ってキャンバスオブジェクトへの参照を取得し、`getContext2D`動作を使ってキャ" +"ンバスの2D描画文脈にアクセスします。" #. type: Plain text #: text/chapter12.md:25 msgid "" "The `void` function takes a functor and replaces its value with `Unit`. In " -"the example it is used to make `main` conform with its signature." +"the example, it is used to make `main` conform with its signature." msgstr "" "`void`関数は関手を取り値を`Unit`で置き換えます。\n" "例では`main`がシグネチャに沿うようにするために使われています。" @@ -8545,14 +8555,14 @@ msgstr "" "これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと" "照合するためです。\n" "ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子" -"と照合させ、適切なエラーメッセージを提供したほうがよいでしょう。" +"と照合させ、適切なエラー文言を提供したほうがよいでしょう。" #. type: Plain text #: text/chapter12.md:33 msgid "" "The types of these actions can be found using PSCi or by looking at the " "documentation:" -msgstr "これらのアクションの型はPSCiを使うかドキュメントを見ると確認できます。" +msgstr "これらの動作の型はPSCiを使うかドキュメントを見ると確認できます。" #. type: Fenced code block (haskell) #: text/chapter12.md:34 @@ -8581,12 +8591,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:43 msgid "" -"The graphics context `ctx` manages the state of the canvas, and provides " +"The graphics context `ctx` manages the state of the canvas and provides " "methods to render primitive shapes, set styles and colors, and apply " "transformations." msgstr "" -"グラフィックスコンテキスト`ctx`はcanvasの状態を管理し、原始的な図形を描画した" -"り、スタイルや色を設定したり、座標変換を適用するためのメソッドを提供します。" +"グラフィックス文脈`ctx`はキャンバスの状態を管理し、原始的な図形を描画したり、" +"スタイルや色を設定したり、座標変換を適用したりするための手段を提供します。" #. type: Plain text #: text/chapter12.md:45 @@ -8595,8 +8605,8 @@ msgid "" "action. The longer hex notation of `#0000FF` may also be used for blue, but " "shorthand notation is easier for simple colors:" msgstr "" -"話を進めると、`setFillStyle`アクションを使うことで塗り潰しスタイルを濃い青に" -"設定できます。\n" +"話を進めると、`setFillStyle`動作を使うことで塗り潰しスタイルを濃い青に設定で" +"きます。\n" "より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がよ" "り簡単です。" @@ -8612,9 +8622,9 @@ msgid "" "Note that the `setFillStyle` action takes the graphics context as an " "argument. This is a common pattern in the `Graphics.Canvas` module." msgstr "" -"`setFillStyle`アクションがグラフィックスコンテキストを引数として取っているこ" -"とに注意してください。\n" -"これは `Graphics.Canvas`ではよくあるパターンです。" +"`setFillStyle`動作がグラフィックス文脈を引数として取っていることに注意してく" +"ださい。\n" +"これは`Graphics.Canvas`ではよくあるパターンです。" #. type: Plain text #: text/chapter12.md:53 @@ -8622,7 +8632,7 @@ msgid "" "Finally, we use the `fillPath` action to fill the rectangle. `fillPath` has " "the following type:" msgstr "" -"最後に、 `fillPath`アクションを使用して矩形を塗り潰しています。\n" +"最後に、`fillPath`動作を使用して矩形を塗り潰しています。\n" "`fillPath`は次のような型を持っています。" #. type: Fenced code block (haskell) @@ -8634,16 +8644,16 @@ msgstr "fillPath :: forall a. Context2D -> Effect a -> Effect a\n" #. type: Plain text #: text/chapter12.md:59 msgid "" -"`fillPath` takes a graphics context and another action which builds the path " +"`fillPath` takes a graphics context and another action that builds the path " "to render. To build a path, we can use the `rect` action. `rect` takes a " -"graphics context, and a record which provides the position and size of the " +"graphics context and a record that provides the position and size of the " "rectangle:" msgstr "" -"`fillPath`はグラフィックスコンテキストと描画するパスを構築する別のアクション" -"を引数にとります。\n" -"`rect`アクションを使うとパスを構築できます。\n" -"`rect`はグラフィックスコンテキストと矩形の位置及びサイズを格納するレコードを" -"引数にとります。" +"`fillPath`はグラフィックスの文脈と描画するパスを構築する他の動作を引数に取り" +"ます。\n" +"`rect`動作を使うとパスを構築できます。\n" +"`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを取りま" +"す。" #. type: Fenced code block (haskell) #: text/chapter12.md:60 @@ -8672,8 +8682,8 @@ msgid "" "Now, open the `html/index.html` file and verify that this code renders a " "blue rectangle in the center of the canvas." msgstr "" -"それでは `html/index.html`ファイルを開き、このコードによってcanvasの中央に青" -"い四角形が描画されていることを確認してみましょう。" +"それでは `html/index.html`ファイルを開き、このコードによってキャンバスの中央" +"に青い四角形が描画されていることを確認してみましょう。" #. type: Title ## #: text/chapter12.md:72 @@ -8685,18 +8695,19 @@ msgstr "行多相を利用する" #: text/chapter12.md:75 msgid "" "There are other ways to render paths. The `arc` function renders an arc " -"segment, and the `moveTo`, `lineTo` and `closePath` functions can be used to " -"render piecewise-linear paths." +"segment, and the `moveTo`, `lineTo`, and `closePath` functions can render " +"piecewise-linear paths." msgstr "" -"パスを描画する方法は他にもあります。 `arc`関数は円弧を描画します。\n" -"`moveTo`関数、 `lineTo`関数、 `closePath`関数は断片的な線分のパスを描画するの" -"に使えます。" +"パスを描画する方法は他にもあります。\n" +"`arc`関数は円弧を描画します。\n" +"`moveTo`関数、`lineTo`関数、`closePath`関数は断片的な線分のパスを描画できま" +"す。" #. type: Plain text #: text/chapter12.md:77 msgid "" -"The `Shapes.purs` file renders three shapes: a rectangle, an arc segment and " -"a triangle." +"The `Shapes.purs` file renders three shapes: a rectangle, an arc segment, " +"and a triangle." msgstr "" "`Shapes.purs`ファイルでは長方形と円弧と三角形の、3つの図形を描画しています。" @@ -8732,10 +8743,11 @@ msgstr "" #: text/chapter12.md:90 msgid "" "The `x` and `y` properties represent the location of the top-left corner, " -"while the `w` and `h` properties represent the width and height respectively." +"while the `w` and `h` properties represent the width and height, " +"respectively." msgstr "" -"`x`と `y`プロパティは左上隅の位置を表しており、 `w`と `h`のプロパティはそれぞ" -"れ幅と高さを表しています。" +"`x`と`y`プロパティは左上隅の位置を表しており、`w`と`h`のプロパティはそれぞれ" +"幅と高さを表しています。" #. type: Plain text #: text/chapter12.md:92 @@ -8771,24 +8783,24 @@ msgstr "" #: text/chapter12.md:104 msgid "" "Here, the `x` and `y` properties represent the center point, `r` is the " -"radius, and `start` and `end` represent the endpoints of the arc in radians." +"radius, `start` and `end` represent the endpoints of the arc in radians." msgstr "" -"ここで、 `x`と `y`プロパティは弧の中心、 `r`は半径、 `start`と `end`は弧の両" -"端の角度を弧度法で表しています。" +"ここで、`x`と`y`プロパティは弧の中心、`r`は半径、`start`と`end`は弧の両端の角" +"度を弧度法で表しています。" #. type: Plain text #: text/chapter12.md:106 msgid "" "For example, this code fills an arc segment centered at `(300, 300)` with " "radius `50`. The arc completes 2/3rds of a rotation. Note that the unit " -"circle is flipped vertically, since the y-axis increases towards the bottom " +"circle is flipped vertically since the y-axis increases towards the bottom " "of the canvas:" msgstr "" "例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰しま" "す。\n" "弧は1回転のうち2/3ラジアン分あります。\n" "単位円が上下逆様になっている点に注意してください。\n" -"これはy軸がcanvasの下向きに伸びるためです。" +"これはy軸がキャンバスの下向きに伸びるためです。" #. type: Fenced code block (haskell) #: text/chapter12.md:107 @@ -8815,23 +8827,22 @@ msgstr "" msgid "" "Notice that both the `Rectangle` and `Arc` record types contain `x` and `y` " "properties of type `Number`. In both cases, this pair represents a point. " -"This means that we can write row-polymorphic functions which can act on " -"either type of record." +"This means we can write row-polymorphic functions acting on either type of " +"record." msgstr "" -"`Number`型の `x`と `y`というプロパティが `Rectangle`レコード型と`Arc`レコード" -"型の両方に含まれていますね。\n" +"`Rectangle`レコード型と`Arc`レコード型の両方共、`Number`型の`x`と`y`というプ" +"ロパティを含んでいますね。\n" "どちらの場合でもこの組は点を表しています。\n" -"これは、何れのレコード型にも適用できる、行多相な関数を書くことができることを" -"意味します。" +"つまり、何れのレコード型にも作用する行多相な関数を書けます。" #. type: Plain text #: text/chapter12.md:120 msgid "" -"For example, the `Shapes` module defines a `translate` function which " +"For example, the `Shapes` module defines a `translate` function that " "translates a shape by modifying its `x` and `y` properties:" msgstr "" -"例えば`Shapes`モジュールでは `x`と `y`のプロパティを変更し図形を並行移動する " -"`translate`関数を定義されています。" +"例えば`Shapes`モジュールでは`x`と`y`のプロパティを変更し図形を並行移動する" +"`translate`関数が定義されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:121 @@ -8872,10 +8883,10 @@ msgstr "" #: text/chapter12.md:130 msgid "" "The `translate` function can be used with both the `Rectangle` and `Arc` " -"records, as can be seen in the `Shapes` example." +"records, as seen in the `Shapes` example." msgstr "" -"`Shapes`の例からわかるように、 `translate`関数は `Rectangle`レコードと`Arc`レ" -"コード双方に対して使うことができます。" +"`Shapes`の例からわかるように、`translate`関数は`Rectangle`レコードと`Arc`レ" +"コード双方に対して使えます。" #. type: Plain text #: text/chapter12.md:132 @@ -8941,33 +8952,32 @@ msgid "" "and open `html/index.html` again to see the result. You should see the three " "different types of shapes rendered to the canvas." msgstr "" -"そしてもう一度 `html/index.html`を開き、結果を確認してください。canvas\n" -"に3つの異なる図形が描画されるはずです。" +"そしてもう一度`html/index.html`を開き、結果を確認してください。\n" +"キャンバスに3つの異なる図形が描画されるはずです。" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 msgid "" "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " -"each of the examples so far." +"each example so far." msgstr "" -"(簡単)これまでの例のそれぞれについて、 `strokePath`関数や`setStrokeStyle`関" -"数を使ってみましょう。" +"(簡単)これまでの各例について、`strokePath`関数や`setStrokeStyle`関数を使っ" +"てみましょう。" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 msgid "" -"(Easy) The `fillPath` and `strokePath` functions can be used to render " -"complex paths with a common style by using a do notation block inside the " -"function argument. Try changing the `Rectangle` example to render two " -"rectangles side-by-side using the same call to `fillPath`. Try rendering a " -"sector of a circle by using a combination of a piecewise-linear path and an " -"arc segment." +"(Easy) The `fillPath` and `strokePath` functions can render complex paths " +"with a common style using a do notation block inside the function argument. " +"Try changing the `Rectangle` example to render two rectangles side-by-side " +"using the same call to `fillPath`. Try rendering a sector of a circle by " +"using a combination of a piecewise-linear path and an arc segment." msgstr "" -"(簡単)関数の引数の内部のdo記法ブロックにより、`fillPath`関数と`strokePath`" -"関数を使って共通のスタイルを持つ複雑なパスを描画できます。\n" -"同じ `fillPath`呼び出しで隣り合った2つの矩形を描画するように、`Rectangle`の" -"コード例を変更してみてください。\n" -"線分と円弧を組み合わせて、扇形を描画してみてください。" +"(簡単)関数の引数の内部でdo記法ブロックを使うと、`fillPath`関数と" +"`strokePath`関数は共通のスタイルを持つ複雑なパスを描画できます。\n" +"同じ`fillPath`呼び出しを使って隣り合う2つの矩形を描画するように、`Rectangle`" +"の例を変更してみてください。\n" +"線分と円弧の組み合わせを使って、扇形を描画してみてください。" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 @@ -9033,11 +9043,11 @@ msgstr "" #. type: Plain text #: text/chapter12.md:179 #, no-wrap -msgid " which takes a `Number` between `0` and `1` as its argument and returns a `Point`, write an action which plots `f` by using your `renderPath` function. Your action should approximate the path by sampling `f` at a finite set of points.\n" +msgid " which takes a `Number` between `0` and `1` as its argument and returns a `Point`, write an action that plots `f` by using your `renderPath` function. Your action should approximate the path by sampling `f` at a finite set of points.\n" msgstr "" -" この関数は引数として `1`から `0`の間の `Number`をとり、 `Point`を返します。\n" -" `renderPath`関数を利用して関数 `f`のグラフを描くアクションを書いてください。\n" -" そのアクションでは有限個の点を `f`からサンプリングすることによって近似しなければなりません。\n" +" この関数は引数として`1`から`0`の間の`Number`を取り、`Point`を返します。\n" +" `renderPath`関数を使い、関数`f`のグラフを描く動作を書いてください。\n" +" その動作では有限個の点で`f`を標本化することによって近似しなければなりません。\n" #. type: Plain text #: text/chapter12.md:181 @@ -9054,24 +9064,24 @@ msgstr "無作為に円を描く" #. type: Plain text #: text/chapter12.md:185 msgid "" -"The `Example/Random.purs` file contains an example which uses the `Effect` " -"monad to interleave two different types of side-effect: random number " -"generation, and canvas manipulation. The example renders one hundred " -"randomly generated circles onto the canvas." +"The `Example/Random.purs` file contains an example that uses the `Effect` " +"monad to interleave two types of side-effect: random number generation and " +"canvas manipulation. The example renders one hundred randomly generated " +"circles onto the canvas." msgstr "" -"`Example/Random.purs`ファイルには2種類の異なる副作用が混在した`Effect`モナド" -"を使う例が含まれています。\n" -"1つは乱数生成で、もう1つはcanvasの操作です。\n" +"`Example/Random.purs`ファイルには、`Effect`モナドを使って2種類の副作用を綴じ" +"合わせる例が含まれています。\n" +"1つの副作用は乱数生成で、もう1つはキャンバスの操作です。\n" "この例では無作為に生成された円をキャンバスに100個描画します。" #. type: Plain text #: text/chapter12.md:187 msgid "" -"The `main` action obtains a reference to the graphics context as before, and " +"The `main` action obtains a reference to the graphics context as before and " "then sets the stroke and fill styles:" msgstr "" -"`main`アクションではこれまでのようにグラフィックスコンテキストへの参照を取得" -"し、ストロークと塗り潰しスタイルを設定します。" +"`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗" +"り潰しのスタイルを設定します。" #. type: Fenced code block (haskell) #: text/chapter12.md:188 @@ -9085,8 +9095,8 @@ msgid "" "Next, the code uses the `for_` function to loop over the integers between " "`0` and `100`:" msgstr "" -"次のコードでは `for_`アクションを使って `0`から `100`までの整数について反復し" -"ています。" +"次のコードでは`for_`動作を使って`0`から`100`までの整数について反復していま" +"す。" #. type: Fenced code block (haskell) #: text/chapter12.md:194 @@ -9099,12 +9109,11 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:for}}\n" msgid "" "On each iteration, the do notation block starts by generating three random " "numbers distributed between `0` and `1`. These numbers represent the `x` and " -"`y` coordinates, and the radius of a circle:" +"`y` coordinates and the radius of a circle:" msgstr "" -"それぞれの繰り返しでのdo記法ブロックは、`0`と`1`の間に分布する3つの乱数を生成" -"することから始まります。\n" -"これらの数は `0`から `1`の間に無作為に分布しており、それぞれ `x`座標、 `y`座" -"標、半径 `r`を表しています。" +"各繰り返しで、do記法ブロックは`0`と`1`の間に分布する3つの乱数を生成することか" +"ら始まります。\n" +"これらの数はそれぞれ`x`座標、`y`座標、半径`r`を表しています。" #. type: Fenced code block (haskell) #: text/chapter12.md:200 @@ -9118,8 +9127,8 @@ msgid "" "Next, for each circle, the code creates an `Arc` based on these parameters " "and finally fills and strokes the arc with the current styles:" msgstr "" -"次のコードではそれぞれの円について、これらの変数に基づいて `Arc`を作成し、最" -"後に現在のスタイルに従って円弧を塗り潰し線描きします。" +"次のコードでは各円について、これらの変数に基づいて`Arc`を作成し、最後に現在の" +"スタイルに従って円弧を塗り潰し線描きします。" #. type: Fenced code block (haskell) #: text/chapter12.md:206 @@ -9156,12 +9165,11 @@ msgstr "座標変換" #: text/chapter12.md:221 msgid "" "There is more to the canvas than just rendering simple shapes. Every canvas " -"maintains a transformation which is used to transform shapes before " +"maintains a transformation that is used to transform shapes before " "rendering. Shapes can be translated, rotated, scaled, and skewed." msgstr "" "キャンバスは簡単な図形を描画するだけのものではありません。\n" -"キャンバスは変換行列を扱うことができ、描画の前に形状を変形してから図形を描画" -"できます。\n" +"キャンバスは座標変換を管理しており、描画の前に図形を変形するのに使えます。\n" "図形は平行移動、回転、拡大縮小、及び斜めに変形できます。" #. type: Plain text @@ -9213,17 +9221,17 @@ msgid "" "The `translate` action performs a translation whose components are specified " "by the properties of the `TranslateTransform` record." msgstr "" -"`translate`アクションは`TranslateTransform`レコードのプロパティで指定した大き" -"さだけ平行移動します。" +"`translate`動作は`TranslateTransform`レコードのプロパティで指定した大きさだけ" +"平行移動します。" #. type: Plain text #: text/chapter12.md:245 msgid "" -"The `rotate` action performs a rotation around the origin, through some " -"number of radians specified by the first argument." +"The `rotate` action rotates around the origin through some number of radians " +"specified by the first argument." msgstr "" -"`rotate`アクションは最初の引数で指定されたラジアンの値に応じて、原点を中心と" -"して回転します。" +"`rotate`動作は最初の引数で指定されたラジアンの数値に応じて、原点を中心として" +"回転します。" #. type: Plain text #: text/chapter12.md:247 @@ -9232,9 +9240,8 @@ msgid "" "`ScaleTransform` record specifies the scale factors along the `x` and `y` " "axes." msgstr "" -"`scale`アクションは原点を中心として拡大縮小します。\n" -"`ScaleTransform`レコードは `X`軸と `y`軸に沿った拡大率を指定するのに使いま" -"す。" +"`scale`動作は原点を中心として拡大縮小します。\n" +"`ScaleTransform`レコードは`x`軸と`y`軸に沿った拡大率を指定するのに使います。" #. type: Plain text #: text/chapter12.md:249 @@ -9242,8 +9249,8 @@ msgid "" "Finally, `transform` is the most general action of the four here. It " "performs an affine transformation specified by a matrix." msgstr "" -"最後の `transform`はこの4つのうちで最も一般化されたアクションです。\n" -"このアクションでは行列に従ってアフィン変換します。" +"最後の `transform`はこの4つのうちで最も一般化された動作です。\n" +"この動作では行列に従ってアフィン変換します。" #. type: Plain text #: text/chapter12.md:251 @@ -9251,8 +9258,8 @@ msgid "" "Any shapes rendered after these actions have been invoked will automatically " "have the appropriate transformation applied." msgstr "" -"これらのアクションが呼び出された後に描画される図形は、自動的に適切な座標変換" -"が適用されます。" +"これらの動作が呼び出された後に描画される図形は、自動的に適切な座標変換が適用" +"されます。" #. type: Plain text #: text/chapter12.md:253 @@ -9262,8 +9269,8 @@ msgid "" "if multiple transformations applied after one another, then their effects " "are actually applied in reverse:" msgstr "" -"実際には、これらの関数のそれぞれの作用は、コンテキストの現在の変換行列に対し" -"て変換行列を*右から乗算*していきます。\n" +"実際には、これらの関数の各作用は、文脈の現在の変換行列に対して変換行列を*右か" +"ら乗算*していきます。\n" "つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されてい" "きます。" @@ -9291,23 +9298,23 @@ msgid "" "The effect of this sequence of actions is that the scene is rotated, then " "scaled, and finally translated." msgstr "" -"この一連のアクションの作用では、まずシーンが回転され、それから拡大縮小され、" -"最後に平行移動されます。" +"この一連の動作の作用では、まずシーンが回転され、それから拡大縮小され、最後に" +"平行移動されます。" #. type: Title ## #: text/chapter12.md:265 #, no-wrap msgid "Preserving the Context" -msgstr "コンテキストの保存" +msgstr "文脈の保存" #. type: Plain text #: text/chapter12.md:268 msgid "" "A common use case is to render some subset of the scene using a " -"transformation, and then to reset the transformation afterwards." +"transformation and then reset the transformation." msgstr "" -"変換を適用してシーンの一部を描画し、それからその変換を元に戻す、という使い方" -"はよくあります。" +"座標変換を使ってシーンの一部を描画し、それからその変換を元に戻す、という使い" +"方はよくあります。" #. type: Plain text #: text/chapter12.md:270 @@ -9347,9 +9354,9 @@ msgid "" "current transformation and any styles) onto the stack, and the `restore` " "action pops the top state from the stack and restores it." msgstr "" -"`save`アクションは現在のコンテキストの状態(現在の変換行列や描画スタイル)を" -"スタックにプッシュし、 `restore`アクションはスタックの一番上の状態をポップ" -"し、コンテキストの状態を復元します。" +"`save`動作は現在の文脈の状態(現在の変換行列や描画スタイル)をスタックにプッ" +"シュし、`restore`動作はスタックの一番上の状態をポップし、文脈の状態を復元しま" +"す。" #. type: Plain text #: text/chapter12.md:284 @@ -9357,13 +9364,13 @@ msgid "" "This allows us to save the current state, apply some styles and " "transformations, render some primitives, and finally restore the original " "transformation and state. For example, the following function performs some " -"canvas action, but applies a rotation before doing so, and restores the " +"canvas action but applies a rotation before doing so and restores the " "transformation afterwards:" msgstr "" -"これらのアクションにより、現在の状態を保存し、いろいろなスタイルや変換を適用" -"してから原始的な図形を描画し、最後に元の変換と状態を復元できます。\n" -"例えば、次の関数は回転を適用してから幾つかのキャンバスアクションを実行し、そ" -"のあとに変換を復元します。" +"これらの動作により、現在の状態を保存し、いろいろなスタイルや変換を適用してか" +"ら原始的な図形を描画し、最後に元の変換と状態を復元できます。\n" +"例えば次の関数は幾つかのキャンバス動作を実行しますが、その前に回転を適用し、" +"その後に変換を復元します。" #. type: Fenced code block (haskell) #: text/chapter12.md:285 @@ -9389,8 +9396,8 @@ msgid "" "performs some canvas action while preserving the original context state:" msgstr "" "こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元" -"のコンテキスト状態を保存しつつ幾つかのキャンバスアクションを実行する " -"`withContext`関数が提供されています。" +"の文脈状態を保存しつつ幾つかのキャンバス動作を実行する`withContext`関数が提供" +"されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:295 @@ -9447,10 +9454,10 @@ msgstr "" #: text/chapter12.md:316 msgid "" "The `Effect.Ref` module provides a type constructor for global mutable " -"references, and an associated effect:" +"references and an associated effect:" msgstr "" -"`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及び関連" -"する作用を提供します。" +"`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及びそれ" +"に紐付く作用を提供します。" #. type: Fenced code block (text) #: text/chapter12.md:317 @@ -9480,20 +9487,19 @@ msgstr "" #. type: Plain text #: text/chapter12.md:327 msgid "" -"The `Example/Refs.purs` file contains an example which uses a `Ref` to track " +"The `Example/Refs.purs` file contains an example that uses a `Ref` to track " "mouse clicks on the `canvas` element." msgstr "" "`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに " -"`Ref`作用を使用する例が含まれています。" +"`Ref`を使う例が含まれます。" #. type: Plain text #: text/chapter12.md:329 msgid "" -"The code starts by creating a new reference containing the value `0`, by " +"The code starts by creating a new reference containing the value `0` by " "using the `new` action:" msgstr "" -"このコードでは最初に`new`アクションを使って値`0`を含む新しい参照を作成してい" -"ます。" +"このコードでは最初に`new`動作を使って値`0`を含む新しい参照を作成しています。" #. type: Fenced code block (haskell) #: text/chapter12.md:330 @@ -9507,8 +9513,8 @@ msgid "" "Inside the click event handler, the `modify` action is used to update the " "click count, and the updated value is returned." msgstr "" -"クリックイベント制御子の内部では、 `modify`アクションを使用してクリック数を更" -"新し、更新された値が返されています。" +"クリックイベント制御子の内部では、`modify`動作を使用してクリック数を更新し、" +"更新された値が返されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:336 @@ -9532,19 +9538,19 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}}\n" #. type: Plain text #: text/chapter12.md:347 msgid "" -"This action uses `withContext` to preserve the original transformation, and " +"This action uses `withContext` to preserve the original transformation and " "then applies the following sequence of transformations (remember that " "transformations are applied bottom-to-top):" msgstr "" -"このアクションでは元の変換を保存するために `withContext`を使用しており、それ" -"から一連の変換を適用しています(変換が下から上に適用されることを思い出してく" -"ださい)。" +"この動作では元の変換を保存するために`withContext`を使用しており、それから一連" +"の変換を適用しています(変換が下から上に適用されることを思い出してくださ" +"い)。" #. type: Bullet: '- ' #: text/chapter12.md:352 msgid "" -"The rectangle is translated through `(-100, -100)` so that its center lies " -"at the origin." +"The rectangle is translated through `(-100, -100)`, so its center lies at " +"the origin." msgstr "矩形が`(-100, -100)`だけ平行移動し、中心が原点に来ます。" #. type: Bullet: '- ' @@ -9562,9 +9568,9 @@ msgstr "矩形が原点を中心に`10`の倍数分の角度で回転します #. type: Bullet: '- ' #: text/chapter12.md:352 msgid "" -"The rectangle is translated through `(300, 300)` so that it center lies at " -"the center of the canvas." -msgstr "矩形が`(300, 300)`だけ平行移動し、中心がcanvasの中心に来ます。" +"The rectangle is translated through `(300, 300)`, so its center lies at the " +"center of the canvas." +msgstr "矩形が`(300, 300)`だけ平行移動し、中心がキャンバスの中心に来ます。" #. type: Plain text #: text/chapter12.md:354 @@ -9590,32 +9596,33 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 msgid "" -"(Easy) Write a higher-order function which strokes and fills a path " -"simultaneously. Rewrite the `Random.purs` example using your function." +"(Easy) Write a higher-order function that simultaneously strokes and fills a " +"path. Rewrite the `Random.purs` example using your function." msgstr "" "(簡単)パスの線描と塗り潰しを同時に行う高階関数を書いてください。\n" -"その関数を使用して `Random.purs`例を書き直してください。" +"その関数を使用して`Random.purs`の例を書き直してください。" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 msgid "" -"(Medium) Use `Random` and `Dom` to create an application which renders a " -"circle with random position, color and radius to the canvas when the mouse " +"(Medium) Use `Random` and `Dom` to create an application that renders a " +"circle with random position, color, and radius to the canvas when the mouse " "is clicked." msgstr "" -"(普通)`Random`作用と `Dom`作用を使用して、マウスがクリックされたときに、" -"キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してく" -"ださい。" +"(普通)`Random`作用と`Dom`作用を使用して、マウスがクリックされたときに、キャ" +"ンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してくださ" +"い。" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 msgid "" -"(Medium) Write a function which transforms the scene by rotating it around a " +"(Medium) Write a function that transforms the scene by rotating it around a " "point with specified coordinates. _Hint_: use a translation to first " "translate the scene to the origin." msgstr "" -"(普通)指定された座標を中心としてシーンを回転させる関数を書いてください。\n" -"*手掛かり*:最初にシーンを原点まで平行移動しましょう。" +"(普通)指定された座標の点を中心として回転させることでシーンを変換する関数を" +"書いてください。\n" +"*手掛かり*:変換を使い、最初にシーンを原点まで平行移動しましょう。" #. type: Title ## #: text/chapter12.md:367 @@ -9638,14 +9645,14 @@ msgid "" "An L-system is defined by an _alphabet_, an initial sequence of letters from " "the alphabet, and a set of _production rules_. Each production rule takes a " "letter of the alphabet and returns a sequence of replacement letters. This " -"process is iterated some number of times starting with the initial sequence " +"process is iterated some number of times, starting with the initial sequence " "of letters." msgstr "" -"L-Systemは*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生" -"成規則*の集合で定義されています。\n" -"各生成規則は、アルファベットの文字をとり、それを置き換える文字の配列を返しま" +"1つのL-Systemは*アルファベット*、つまりアルファベット由来の文字の初期の並び" +"と、*生成規則*の集合で定義されます。\n" +"各生成規則は、アルファベットの文字を取り、それを置き換える文字の並びを返しま" "す。\n" -"この処理は文字の初期配列から始まり、複数回繰り返されます。" +"この処理は文字の初期の並びから始まり、複数回繰り返されます。" #. type: Plain text #: text/chapter12.md:374 @@ -9654,19 +9661,19 @@ msgid "" "perform on the canvas, the L-system can be rendered by following the " "instructions in order." msgstr "" -"もしアルファベットの各文字がcanvas上で実行される命令と対応付けられていれば、" -"その指示に順番に従うことでL-Systemを描画できます。" +"もしアルファベットの各文字がキャンバス上で実行される命令と対応付けられていれ" +"ば、その指示に順番に従うことでL-Systemを描画できます。" #. type: Plain text #: text/chapter12.md:376 msgid "" "For example, suppose the alphabet consists of the letters `L` (turn left), " -"`R` (turn right) and `F` (move forward). We might define the following " +"`R` (turn right), and `F` (move forward). We might define the following " "production rules:" msgstr "" -"例えばアルファベットが文字 `L`(左回転)、 `R`(右回転)、 `F`(前進)で構成" -"されているとします。\n" -"また、次のような生成規則を定義します。" +"例えばアルファベットが文字`L`(左回転)、`R`(右回転)、`F`(前進)で構成され" +"ているとします。\n" +"次のような生成規則を定義できます。" #. type: Fenced code block (text) #: text/chapter12.md:377 @@ -9704,11 +9711,11 @@ msgstr "" #: text/chapter12.md:392 msgid "" "and so on. Plotting a piecewise-linear path corresponding to this set of " -"instruction approximates a curve called the _Koch curve_. Increasing the " -"number of iterations increases the resolution of the curve." +"instructions approximates the _Koch curve_. Increasing the number of " +"iterations increases the resolution of the curve." msgstr "" -"この命令群に対応する線分パスをプロットすると、*コッホ曲線*と呼ばれる曲線に近" -"似されます。\n" +"というように続きます。\n" +"この命令群に対応する線分パスをプロットすると、*コッホ曲線*に近似されます。\n" "反復回数を増やすと、曲線の解像度が増していきます。" #. type: Plain text @@ -9780,17 +9787,16 @@ msgstr "これはまさに上記の仕様をそのまま書き写したもので #. type: Plain text #: text/chapter12.md:420 msgid "" -"Now we can implement a function `lsystem` which will take a specification in " -"this form, and render it to the canvas. What type should `lsystem` have? " +"Now we can implement a function `lsystem` that will take a specification in " +"this form and render it to the canvas. What type should `lsystem` have? " "Well, it needs to take values like `initial` and `productions` as arguments, " -"as well as a function which can render a letter of the alphabet to the " -"canvas." +"as well as a function that can render a letter of the alphabet to the canvas." msgstr "" -"これで、この形式の仕様を受け取りcanvasに描画する関数 `lsystem`を実装できま" -"す。\n" +"これで、この形式の仕様を受け取ってキャンバスに描画する関数`lsystem`を実装でき" +"ます。\n" "`lsystem`はどのような型を持っているべきでしょうか。\n" -"この関数は初期状態 `initial`や生成規則 `productions`のような値だけでなく、ア" -"ルファベットの文字をcanvasに描画する関数を引数に取る必要があります。" +"`initial`や`productions`のような値だけでなく、アルファベットの文字をキャンバ" +"スに描画できる関数を引数に取る必要があります。" #. type: Plain text #: text/chapter12.md:422 @@ -9823,15 +9829,15 @@ msgstr "最初の2つの引数の型は、値 `initial`と `productions`に対 #. type: Plain text #: text/chapter12.md:434 msgid "" -"The third argument represents a function which takes a letter of the " -"alphabet and _interprets_ it by performing some actions on the canvas. In " -"our example, this would mean turning left in the case of the letter `L`, " -"turning right in the case of the letter `R`, and moving forward in the case " -"of a letter `F`." +"The third argument represents a function that takes a letter of the alphabet " +"and _interprets_ it by performing some actions on the canvas. In our " +"example, this would mean turning left in the case of the letter `L`, turning " +"right in the case of the letter `R`, and moving forward in the case of a " +"letter `F`." msgstr "" -"3番目の引数は、アルファベットの文字を取り、canvas上の幾つかのアクションを実行" -"することによって*解釈*する関数を表します。\n" -"この例では、文字`L`は左回転、文字 `R`で右回転、文字 `F`は前進を意味します。" +"3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行す" +"ることによって*解釈*する関数を表します。\n" +"この例では、文字`L`は左回転、文字`R`で右回転、文字`F`は前進を意味します。" #. type: Plain text #: text/chapter12.md:436 @@ -9873,20 +9879,20 @@ msgstr "" #. type: Plain text #: text/chapter12.md:448 msgid "" -"The second observation is that, in order to implement instructions like " -"\"turn left\" and \"turn right\", we will need to maintain some state, " -"namely the direction in which the path is moving at any time. We need to " -"modify our function to pass the state through the computation. Again, the " -"`lsystem` function should work for any type of state, so we will represent " -"it using the type variable `s`." +"The second observation is that, to implement instructions like \"turn left\" " +"and \"turn right\", we will need to maintain some state, namely the " +"direction in which the path is moving at any time. We need to modify our " +"function to pass the state through the computation. Again, the `lsystem` " +"function should work for any type of state, so we will represent it using " +"the type variable `s`." msgstr "" "次に気付くこととしては、「左回転」と「右回転」のような命令を実装するために" "は、幾つかの状態を管理する必要があります。\n" -"具体的に言えば、その時点でパスが向いている方向を状態として持たなければなりま" +"具体的に言えば、その時点でパスが動いている方向を状態として持たなければなりま" "せん。\n" -"計算を通じて状態を関数に渡すように変更する必要があります。\n" -"ここでも `lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数 `s`" -"を使用してそれを表しています。" +"計算を通じて状態を渡すように関数を変更する必要があります。\n" +"ここでも`lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数`s`を" +"使用してそれを表しています。" #. type: Plain text #: text/chapter12.md:450 @@ -10017,19 +10023,19 @@ msgstr "" #: text/chapter12.md:494 msgid "" "The `go` function works by recursion on its second argument. There are two " -"cases: when `n` is zero, and when `n` is non-zero." +"cases: when `n` is zero and `n` is non-zero." msgstr "" -"`go`関数は第2引数に応じて再帰することで動作します。\n" -"場合分けは2つであり、`n`がゼロであるときと `n`がゼロでないときです。" +"`go`関数は第2引数について再帰することで動作します。\n" +"場合分けは2つであり、`n`がゼロであるときと`n`がゼロでないときです。" #. type: Plain text #: text/chapter12.md:496 #, no-wrap -msgid "In the first case, the recursion is complete, and we simply need to interpret the current sentence according to the interpretation function. We have a sentence of type `Array a`, a state of type `s`, and a function of type `s -> a -> Effect s`. This sounds like a job for the `foldM` function which we defined earlier, and which is available from the `control` package:\n" +msgid "In the first case, the recursion is complete, and we need to interpret the current sentence according to the interpretation function. We have a sentence of type `Array a`, a state of type `s`, and a function of type `s -> a -> Effect s`. This sounds like a job for the `foldM` function which we defined earlier, and which is available from the `control` package:\n" msgstr "" "1つ目の場合は再帰は完了し、解釈関数に応じて現在の文を解釈します。\n" -"型`Array a`の文、型 `s`の状態、型 `s -> a -> Effect s`の関数があります。\n" -"以前定義した `foldM`でやったことみたいです。\n" +"型`Array a`の文、型`s`の状態、型`s -> a -> Effect s`の関数があります。\n" +"以前定義した`foldM`の出番のようです。\n" "この関数は`control`パッケージで手に入ります。\n" #. type: Fenced code block (haskell) @@ -10058,12 +10064,12 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_ #. type: Plain text #: text/chapter12.md:508 msgid "" -"That's it! Note how the use of higher order functions like `foldM` and " +"That's it! Note how using higher-order functions like `foldM` and " "`concatMap` allowed us to communicate our ideas concisely." msgstr "" "これだけです。\n" -"`foldM`や `concatMap`のような高階関数を使うと、このようにアイデアを簡潔に表現" -"できるのです。" +"`foldM`や`concatMap`のような高階関数を使うと、アイデアを簡潔に表現できるので" +"す。" #. type: Plain text #: text/chapter12.md:510 @@ -10075,8 +10081,8 @@ msgid "" msgstr "" "しかし、話はこれで終わりではありません。\n" "ここで与えた型は、実際はまだ特殊化されすぎています。\n" -"この定義ではcanvasの操作が実装のどこにも使われていないことに注目してくださ" -"い。\n" +"この定義ではキャンバスの操作が実装のどこにも使われていないことに注目してくだ" +"さい。\n" "それに、全く`Effecta`モナドの構造を利用していません。\n" "実際には、この関数は*どんな*モナド`m`についても動作します。" @@ -10100,12 +10106,12 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_anno} msgid "" "We can understand this type as saying that our interpretation function is " "free to have any side-effects at all, captured by the monad `m`. It might " -"render to the canvas, or print information to the console, or support " -"failure or multiple return values. The reader is encouraged to try writing L-" -"systems which use these various types of side-effect." +"render to the canvas, print information to the console, or support failure " +"or multiple return values. The reader is encouraged to try writing L-systems " +"that use these various types of side-effect." msgstr "" -"この型で書かれていることは、この解釈関数はモナド `m`が持つ任意の副作用を完全" -"に自由に持つことができる、ということだと理解できます。\n" +"この型で書かれていることは、この解釈関数はモナド`m`が持つ任意の副作用を完全に" +"自由に持つことができる、ということだと理解できます。\n" "キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれません" "し、失敗や複数の戻り値に対応しているかもしれません。\n" "こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めし" @@ -10115,18 +10121,17 @@ msgstr "" #: text/chapter12.md:520 msgid "" "This function is a good example of the power of separating data from " -"implementation. The advantage of this approach is that we gain the freedom " -"to interpret our data in multiple different ways. We might even factor " -"`lsystem` into two smaller functions: the first would build the sentence " -"using repeated application of `concatMap`, and the second would interpret " -"the sentence using `foldM`. This is also left as an exercise for the reader." +"implementation. The advantage of this approach is that we can interpret our " +"data in multiple ways. We might even factor `lsystem` into two smaller " +"functions: the first would build the sentence using repeated application of " +"`concatMap`, and the second would interpret the sentence using `foldM`. This " +"is also left as an exercise for the reader." msgstr "" "この関数は実装からデータを分離することの威力を示す良い例となっています。\n" -"この手法の利点は、複数の異なる方法でデータを解釈する自由が得られることで" -"す。\n" -"`lsystem`は2つの小さな関数へと分解さえできるかもしれません。\n" -"1つ目は `concatMap`の適用の繰り返しを使って文を構築するもので、2つ目は " -"`foldM`を使って文を解釈するものです。\n" +"この手法の利点は、複数の異なる方法でデータを解釈できることです。\n" +"さらに`lsystem`を2つの小さな関数へと分解できます。\n" +"1つ目は`concatMap`の適用の繰り返しを使って文を構築するもの、2つ目は`foldM`を" +"使って文を解釈するものです。\n" "これは読者の演習として残しておきます。" #. type: Plain text @@ -10167,11 +10172,10 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} #: text/chapter12.md:534 msgid "" "To interpret the letter `F` (move forward), we can calculate the new " -"position of the path, render a line segment, and update the state, as " -"follows:" +"position of the path, render a line segment, and update the state as follows:" msgstr "" -"文字 `F`(前進)を解釈するには、パスの新しい位置を計算し、線分を描画し、状態" -"を次のように更新します。" +"文字`F`(前進)を解釈するには、次のようにパスの新しい位置を計算し、線分を描画" +"し、状態を更新します。" #. type: Fenced code block (haskell) #: text/chapter12.md:535 @@ -10188,17 +10192,16 @@ msgid "" "`State` type, but this would be inappropriate because it is not a changing " "part of the state of the system." msgstr "" -"なおこの章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`関" -"数は `main`関数内で `let`束縛を使用して定義されています。\n" -"`State`型がコンテキストを持つように変更できるでしょうが、それはこのシステムの" -"状態の変化する部分ではないので不適切でしょう。" +"なお、この章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`" +"関数は `main`関数内で `let`束縛を使用して定義されています。\n" +"`State`型が文脈を持つように変更できるでしょうが、それはこのシステムの状態の変" +"化する部分ではないので不適切でしょう。" #. type: Plain text #: text/chapter12.md:542 msgid "To render this L-system, we can simply use the `strokePath` action:" msgstr "" -"このL-Systemを描画するには、次のような `strokePath`アクションを使用するだけで" -"す。" +"このL-Systemを描画するには、次のような`strokePath`動作を使用するだけです。" #. type: Fenced code block (haskell) #: text/chapter12.md:543 @@ -10241,7 +10244,7 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 msgid "" -"(Easy) Try changing the various numerical constants in the code, to " +"(Easy) Try changing the various numerical constants in the code to " "understand their effect on the rendered system." msgstr "" "(簡単)描画システムへの影響を理解するために、コード中の様々な数値の定数を変" @@ -10261,13 +10264,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 msgid "" -"(Medium) Add a drop shadow to the filled shape, by using the " -"`setShadowOffsetX`, `setShadowOffsetY`, `setShadowBlur` and `setShadowColor` " -"actions. _Hint_: use PSCi to find the types of these functions." +"(Medium) Add a drop shadow to the filled shape using the `setShadowOffsetX`, " +"`setShadowOffsetY`, `setShadowBlur`, and `setShadowColor` actions. _Hint_: " +"use PSCi to find the types of these functions." msgstr "" -"(普通)`setShadowOffsetX`アクション、 `setShadowOffsetY`アクション、" -"`setShadowBlur`アクション、 `setShadowColor`アクションを使い、塗りつぶされた" -"図形にドロップシャドウを追加してください。\n" +"(普通)`setShadowOffsetX`、`setShadowOffsetY`、`setShadowBlur`、" +"`setShadowColor`動作を使い、塗りつぶされた図形にドロップシャドウを追加してく" +"ださい。\n" "*手掛かり*:PSCiを使って、これらの関数の型を調べてみましょう。" #. type: Bullet: ' 1. ' @@ -10306,10 +10309,11 @@ msgstr "" #, no-wrap msgid "" " How can this new information be used in the production rules to create interesting shapes?\n" -" 1. (Difficult) An L-system is given by an alphabet with four letters: `L` (turn left through 60 degrees), `R` (turn right through 60 degrees), `F` (move forward) and `M` (also move forward).\n" +" 1. (Difficult) An L-system is given by an alphabet with four letters: `L` (turn left through 60 degrees), `R` (turn right through 60 degrees), `F` (move forward), and `M` (also move forward).\n" msgstr "" -" 生成規則でこの新しい情報を使うと、どんな面白い図形を作ることができるでしょうか。\n" -"1. (難しい)`L`(60度左回転)、 `R`(60度右回転)、`F`(前進)、 `M`(これも前進)という4つの文字からなるアルファベットでL-Systemが与えられたとします。\n" +" この新しい情報を生成規則でどう使うと、面白い図形を作ることができるでしょうか。\n" +"1. (難しい)4つの文字からなるアルファベットでL-Systemが与えられたとします。\n" +" それぞれ`L`(60度左回転)、`R`(60度右回転)、`F`(前進)、`M`(これも前進)です。\n" #. type: Plain text #: text/chapter12.md:573 @@ -10344,7 +10348,7 @@ msgstr "" #. type: Plain text #: text/chapter12.md:584 #, no-wrap -msgid " Render this L-system. _Note_: you will need to decrease the number of iterations of the production rules, since the size of the final sentence grows exponentially with the number of iterations.\n" +msgid " Render this L-system. _Note_: you will need to decrease the number of iterations of the production rules since the size of the final sentence grows exponentially with the number of iterations.\n" msgstr "" " このL-Systemを描画してください。\n" " *補足*:最後の文のサイズは反復回数に従って指数関数的に増大するので、生成規則の繰り返しの回数を削減する必要があります。\n" @@ -10382,14 +10386,13 @@ msgstr "" msgid "" "In this chapter, we learned how to use the HTML5 Canvas API from PureScript " "by using the `canvas` library. We also saw a practical demonstration of many " -"of the techniques we have learned already: maps and folds, records and row " +"techniques we have learned already: maps and folds, records and row " "polymorphism, and the `Effect` monad for handling side-effects." msgstr "" -"この章では、 `canvas`ライブラリを使用することにより、PureScriptからHTML5 " +"この章では、`canvas`ライブラリを使用することにより、PureScriptからHTML5 " "Canvas APIを使う方法について学びました。\n" -"また、これまで学んできた手法の多くを利用した実用的な例について見ました。\n" -"マップや畳み込み、レコードと行多相、副作用を扱うための `Effect`モナドなどで" -"す。" +"また、これまで学んできた多くの手法からなる実用的な実演を見ました。\n" +"マップや畳み込み、レコードと行多相、副作用を扱うための`Effect`モナドです。" #. type: Plain text #: text/chapter12.md:599 @@ -10427,11 +10430,11 @@ msgstr "" #: text/chapter12.md:611 msgid "" "This approach is taken in the `drawing` package, and it brings the " -"flexibility of being able to manipulate the scene as data in various ways " -"before rendering." +"flexibility of manipulating the scene as data in various ways before " +"rendering." msgstr "" -"この手法は `drawing`パッケージでも採用されており、描画前にさまざまな方法で" -"データとしてシーンを操作できる柔軟性をもたらしています。" +"この手法は`drawing`パッケージで取られており、描画前に様々な方法でシーンをデー" +"タとして操作できる柔軟性を齎しています。" #. type: Plain text #: text/chapter12.md:612 @@ -10440,7 +10443,7 @@ msgid "" "\"Signal\" recipes in the [cookbook](https://github.com/JordanMartinez/" "purescript-cookbook/blob/master/README.md#recipes)." msgstr "" -"canvasに描画されるゲームの例については[cookbook](https://github.com/" +"キャンバスに描画されるゲームの例については[cookbook](https://github.com/" "JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の" "「Behavior」と「Signal」のレシピを見てください。" @@ -10526,7 +10529,7 @@ msgstr "merge :: Array Int -> Array Int -> Array Int\n" #. type: Plain text #: text/chapter13.md:24 msgid "" -"`merge` takes two sorted arrays of integers, and merges their elements so " +"`merge` takes two sorted arrays of integers and merges their elements so " "that the result is also sorted. For example:" msgstr "" "`merge`は2つの整列された整数の配列を取って、結果が整列されるように要素を統合" @@ -10551,14 +10554,13 @@ msgstr "" #: text/chapter13.md:33 msgid "" "In a typical test suite, we might test `merge` by generating a few small " -"test cases like this by hand, and asserting that the results were equal to " +"test cases like this by hand and asserting that the results were equal to " "the appropriate values. However, everything we need to know about the " "`merge` function can be summarized by this property:" msgstr "" "典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成" "し、結果が正しい値と等しいことを確認することでテストを実施します。\n" -"しかし、 `merge`関数について知る必要があるものは全て、この性質に要約できま" -"す。" +"しかし、`merge`関数について知る必要があるものは全て、この性質に要約できます。" #. type: Bullet: '- ' #: text/chapter13.md:35 @@ -10572,9 +10574,9 @@ msgstr "" #. type: Plain text #: text/chapter13.md:37 msgid "" -"`quickcheck` allows us to test this property directly, by generating random " -"test cases. We simply state the properties that we want our code to have, as " -"functions. In this case, we have a single property:" +"`quickcheck` allows us to test this property directly by generating random " +"test cases. We state the properties we want our code to have as functions. " +"In this case, we have a single property:" msgstr "" "`quickcheck`では、無作為なテスト項目を生成することで、直接この性質をテストで" "きます。\n" @@ -10597,16 +10599,15 @@ msgstr "" #: text/chapter13.md:45 msgid "" "When we run this code, `quickcheck` will attempt to disprove the properties " -"we claimed, by generating random inputs `xs` and `ys`, and passing them to " -"our functions. If our function returns `false` for any inputs, the property " -"will be incorrect, and the library will raise an error. Fortunately, the " -"library is unable to disprove our properties after generating 100 random " -"test cases:" -msgstr "" -"このコードを実行すると、 `quickcheck`は無作為な入力 `xs`と `ys`を生成してこの" -"関数に渡すことで、主張しようとしている性質を反証しようとします。\n" -"何らかの入力に対して関数が `false`を返した場合、性質は正しくないことが示さ" -"れ、ライブラリはエラーを発生させます。\n" +"we claimed by generating random inputs `xs` and `ys` and passing them to our " +"functions. If our function returns `false` for any inputs, the property will " +"be incorrect, and the library will raise an error. Fortunately, the library " +"is unable to disprove our properties after generating 100 random test cases:" +msgstr "" +"このコードを実行すると、`quickcheck`は無作為な入力`xs`と`ys`を生成してこの関" +"数に渡すことで、主張した性質を反証しようとします。\n" +"何らかの入力に対して関数が`false`を返した場合、性質は正しくなく、ライブラリは" +"エラーを発生させます。\n" "幸いなことに、次のように100個の無作為なテスト項目を生成しても、ライブラリはこ" "の性質を反証できません。" @@ -10657,21 +10658,21 @@ msgid "" "As we can see, this error message is not very helpful, but it can be " "improved with a little work." msgstr "" -"見ての通りこのエラーメッセージではあまり役に立ちませんが、少し工夫するだけで" -"改良できます。" +"見ての通りこのエラー文言ではあまり役に立ちませんが、少し工夫するだけで改良で" +"きます。" #. type: Title ## #: text/chapter13.md:65 #, no-wrap msgid "Improving Error Messages" -msgstr "エラーメッセージの改善" +msgstr "エラー文言の改善" #. type: Plain text #: text/chapter13.md:68 #, no-wrap msgid "To provide error messages along with our failed test cases, `quickcheck` provides the `` operator. Simply separate the property definition from the error message using ``, as follows:\n" msgstr "" -"テスト項目が失敗した時に同時にエラーメッセージを提供する上で、`quickcheck`は``演算子を提供しています。\n" +"テスト項目が失敗した時に同時にエラー文言を提供する上で、`quickcheck`は``演算子を提供しています。\n" "次のように性質の定義とエラー文言を``で区切って書くだけです。\n" #. type: Fenced code block (haskell) @@ -10699,7 +10700,7 @@ msgid "" "error message after the first failed test case:" msgstr "" "このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗" -"したときに改良されたエラーメッセージが表示されます。" +"したときに改良されたエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter13.md:80 @@ -10729,11 +10730,10 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter13.md:94 msgid "" -"(Easy) Write a property which asserts that merging an array with the empty " -"array does not modify the original array. _Note_: This new property is " -"redundant, since this situation is already covered by our existing property. " -"We're just trying to give you readers a simple way to practice using " -"quickCheck." +"(Easy) Write a property that asserts that merging an array with an empty one " +"does not modify the original array. _Note_: This new property is redundant " +"since this situation is already covered by our existing property. We're just " +"trying to give readers a simple way to practice using quickCheck." msgstr "" "(簡単)配列に空の配列を統合しても元の配列は変更されないことを確かめる性質を" "書いてください。\n" @@ -10748,8 +10748,7 @@ msgid "" "(Easy) Add an appropriate error message to the remaining property for " "`merge`." msgstr "" -"(簡単)`merge`の残りの性質に対して、適切なエラーメッセージを追加してくださ" -"い。" +"(簡単)`merge`の残りの性質に対して、適切なエラー文言を追加してください。" #. type: Title ## #: text/chapter13.md:95 @@ -10781,7 +10780,7 @@ msgid "" "see the following error message:" msgstr "" "`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエ" -"ラーメッセージが表示されます。" +"ラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter13.md:105 @@ -10805,12 +10804,12 @@ msgstr "" #: text/chapter13.md:115 msgid "" "This error message indicates that the compiler could not generate random " -"test cases, because it did not know what type of elements we wanted our " +"test cases because it did not know what type of elements we wanted our " "arrays to have. In these sorts of cases, we can use type annotations to " "force the compiler to infer a particular type, such as `Array Int`:" msgstr "" -"このエラーメッセージは、配列に持たせたい要素の型が何なのかわからないので、コ" -"ンパイラが無作為なテスト項目を生成できなかったということを示しています。\n" +"このエラー文言は、配列に持たせたい要素の型が何なのかわからないので、コンパイ" +"ラが無作為なテスト項目を生成できなかったということを示しています。\n" "このような場合、型註釈を使ってコンパイラが特定の型を推論するように強制できま" "す。\n" "例えば`Array Int`などです。" @@ -10828,13 +10827,13 @@ msgstr "" #. type: Plain text #: text/chapter13.md:122 msgid "" -"We can alternatively use a helper function to specify type, which may result " -"in cleaner code. For example, if we define a function `ints` as a synonym " -"for the identity function:" +"We can alternatively use a helper function to specify the type, which may " +"result in cleaner code. For example, if we define a function `ints` as a " +"synonym for the identity function:" msgstr "" "代替案として型を指定する補助関数を使うこともできます。\n" "こうするとより見通しのよいコードになることがあります。\n" -"例えば同値関数の同義な関数`ints`を定義したとしましょう。" +"例えば同値関数の同義語として関数`ints`を定義したとしましょう。" #. type: Fenced code block (haskell) #: text/chapter13.md:123 @@ -10868,20 +10867,20 @@ msgstr "" #. type: Plain text #: text/chapter13.md:136 msgid "" -"Here, `xs` and `ys` both have type `Array Int`, since the `ints` function " -"has been used to disambiguate the unknown type." +"Here, `xs` and `ys` have type `Array Int` since the `ints` function has been " +"used to disambiguate the unknown type." msgstr "" -"ここで、 `ints`関数が不明な型を解消するために使われているため、 `xs`と `ys`は" -"どちらも型 `Array Int`を持っています。" +"ここで、`ints`関数が不明な型の曖昧さを解消するために使われているため、`xs`と" +"`ys`は型`Array Int`を持っています。" #. type: Bullet: ' 1. ' #: text/chapter13.md:141 msgid "" -"(Easy) Write a function `bools` which forces the types of `xs` and `ys` to " -"be `Array Boolean`, and add additional properties which test `mergePoly` at " -"that type." +"(Easy) Write a function `bools` that forces the types of `xs` and `ys` to be " +"`Array Boolean`, and add additional properties that test `mergePoly` at that " +"type." msgstr "" -"(簡単)`xs`と `ys`の型を `Array Boolean`に強制する関数 `bools`を書き、 " +"(簡単)`xs`と`ys`の型を`Array Boolean`に強制する関数`bools`を書き、" "`mergePoly`をその型でテストする性質を追加してください。" #. type: Bullet: ' 1. ' @@ -10893,7 +10892,7 @@ msgid "" "any polymorphic type arguments to either `Int` or `Boolean`." msgstr "" "(普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエ" -"ラーメッセージを含めてQuickCheckの性質を書いてください。\n" +"ラー文言を含めてQuickCheckの性質を書いてください。\n" "その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定し" "なければいけません。" @@ -10906,11 +10905,11 @@ msgstr "任意のデータの生成" #. type: Plain text #: text/chapter13.md:145 msgid "" -"Now we will see how the `quickcheck` library is able to randomly generate " -"test cases for our properties." +"Now we will see how the `quickcheck` library can randomly generate test " +"cases for our properties." msgstr "" -"`quickcheck`ライブラリを使って性質に対するテスト項目を無作為に生成する方法に" -"ついて説明します。" +"それでは`quickcheck`ライブラリが性質に対するテスト項目をどのように無作為に生" +"成できているのかを見ていきます。" #. type: Plain text #: text/chapter13.md:147 @@ -10961,14 +10960,14 @@ msgstr "" #: text/chapter13.md:158 msgid "" "For example, we can use the `Arbitrary` instance for the `Int` type, " -"provided in the `quickcheck` library, to create a distribution on the 256 " +"provided in the `quickcheck` library, to create a distribution on the 256-" "byte values, using the `Functor` instance for `Gen` to map a function from " "integers to bytes over arbitrary integer values:" msgstr "" -"例えば、 `quickcheck`ライブラリで提供されている `Int`型用の `Arbitrary`インス" -"タンスを使い、256個のバイト値上の分布を作ることができます。\n" -"これには`Gen`用に`Functor`インスタンスを使って整数から任意の整数値のバイトま" -"でマップします。" +"例えば、`quickcheck`ライブラリで提供されている`Int`型用の`Arbitrary`インスタ" +"ンスを使い、256個のバイト値上の分布を作れます。\n" +"これには`Gen`用の`Functor`インスタンスを使い、整数からバイトへの関数を任意の" +"整数値に写します。" #. type: Fenced code block (haskell) #: text/chapter13.md:159 @@ -10998,10 +10997,10 @@ msgid "" "function over the `arbitrary` action. The type of the inner `arbitrary` " "action is inferred as `Gen Int`." msgstr "" -"ここでは、0から255までの間の整数値であるような型 `Byte`を定義しています。\n" -"`Arbitrary`インスタンスは `map`演算子を使って、 `intToByte`関数を `arbitrary`" -"アクションまで持ち上げています。\n" -"`arbitrary`アクション内部の型は `Gen Int`と推論されます。" +"ここでは、0から255までの間の整数値であるような型`Byte`を定義しています。\n" +"`Arbitrary`インスタンスは`map`演算子を使って、`intToByte`関数を`arbitrary`動" +"作まで持ち上げています。\n" +"`arbitrary`動作内部の型は`Gen Int`と推論されます。" #. type: Plain text #: text/chapter13.md:172 @@ -11023,12 +11022,12 @@ msgstr "" msgid "" "In this test, we generated arbitrary arrays `xs` and `ys`, but had to sort " "them, since `merge` expects sorted input. On the other hand, we could create " -"a newtype representing sorted arrays, and write an `Arbitrary` instance " -"which generates sorted data:" +"a newtype representing sorted arrays and write an `Arbitrary` instance that " +"generates sorted data:" msgstr "" -"このテストでは、任意の配列 `xs`と `ys`を生成しますが、 `merge`は整列済みの入" -"力を期待しているので、 `xs`と `ys`を整列しておかなければなりません。\n" -"一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する " +"このテストでは、任意の配列`xs`と`ys`を生成しますが、`merge`は整列済みの入力を" +"期待しているので、これらを整列しておかなければなりません。\n" +"一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する" "`Arbitrary`インスタンスを書くこともできます。" #. type: Fenced code block (haskell) @@ -11070,17 +11069,17 @@ msgstr "" #: text/chapter13.md:198 msgid "" "This may look like a small change, but the types of `xs` and `ys` have " -"changed to `Sorted Int`, instead of just `Array Int`. This communicates our " -"_intent_ in a clearer way - the `mergePoly` function takes sorted input. " +"changed to `Sorted Int` instead of just `Array Int`. This communicates our " +"_intent_ in a clearer way – the `mergePoly` function takes sorted input. " "Ideally, the type of the `mergePoly` function itself would be updated to use " "the `Sorted` type constructor." msgstr "" -"これは些細な変更に見えるかもしれませんが、 `xs`と `ys`の型はただの `Array " -"Int`から `Sorted Int`へと変更されています。\n" -"これにより、 `mergePoly`関数は整列済みの入力を取る、という*意図*を、わかりや" -"すく示すことができます。\n" -"理想的には、 `mergePoly`関数自体の型が `Sorted`型構築子を使うようにするといい" -"でしょう。" +"これは些細な変更に見えるかもしれませんが、`xs`と`ys`の型はただの`Array Int`か" +"ら`Sorted Int`へと変更されています。\n" +"これにより、`mergePoly`関数は整列済みの入力を取る、という*意図*をわかりやすく" +"示すことができます。\n" +"理想的には、`mergePoly`関数自体の型が`Sorted`型構築子を使うようにするといいで" +"しょう。" #. type: Plain text #: text/chapter13.md:200 @@ -11125,12 +11124,11 @@ msgstr "" #. type: Plain text #: text/chapter13.md:217 msgid "" -"The `insert` function is used to insert a new element into a sorted tree, " -"and the `member` function can be used to query a tree for a particular " -"value. For example:" +"The `insert` function inserts a new element into a sorted tree, and the " +"`member` function can query a tree for a particular value. For example:" msgstr "" -"`insert`関数は新しい要素を整列済みの二分木に挿入するのに使われ、 `member`関数" -"は特定の値の有無を木に問い合わせるのに使われます。\n" +"`insert`関数は新しい要素を整列済みの木に挿入し、`member`関数は特定の値につい" +"て木に問い合わせます。\n" "例えば次のようになります。" #. type: Fenced code block (text) @@ -11156,14 +11154,11 @@ msgstr "" #. type: Plain text #: text/chapter13.md:229 msgid "" -"The `toArray` and `fromArray` functions can be used to convert sorted trees " -"to and from arrays. We can use `fromArray` to write an `Arbitrary` instance " -"for trees:" +"The `toArray` and `fromArray` functions can convert sorted trees to and from " +"arrays. We can use `fromArray` to write an `Arbitrary` instance for trees:" msgstr "" -"`toArray`関数と `fromArray`関数は、整列された木と整列された配列を相互に変換す" -"るために使われます。\n" -"`fromArray`を使うと、木についての `Arbitrary`インスタンスを書くことができま" -"す。" +"`toArray`関数と`fromArray`関数は、整列された木と配列を相互に変換できます。\n" +"`fromArray`を使うと、木についての`Arbitrary`インスタンスを書けます。" #. type: Fenced code block (haskell) #: text/chapter13.md:230 @@ -11178,14 +11173,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:236 msgid "" -"We can now use `Tree a` as the type of an argument to our test properties, " +"We can now use `Tree a` as the type of an argument to our test properties " "whenever there is an `Arbitrary` instance available for the type `a`. For " "example, we can test that the `member` test always returns `true` after " "inserting a value:" msgstr "" -"型 `a`についての`Arbitary`インスタンスが使えるなら、テストする性質の引数の型" -"として `Tree a`を使うことができます。例えば、 `member`テストは値を挿入した後" -"は常に `true`を返すことをテストできます。" +"型`a`用に使える`Arbitary`インスタンスがあるなら、テストする性質の引数の型とし" +"て`Tree a`を使えます。\n" +"例えば、`member`による木の確認については、値を挿入した後は常に`true`を返すこ" +"とをテストできます。" #. type: Fenced code block (haskell) #: text/chapter13.md:237 @@ -11222,11 +11218,11 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter13.md:248 msgid "" -"(Difficult) Write a property which asserts that a value inserted into a tree " +"(Difficult) Write a property that asserts that a value inserted into a tree " "is still a member of that tree after arbitrarily many more insertions." msgstr "" -"(難しい)木に挿入された値は、どれだけ挿入があった後でも、その木の構成要素で" -"あることを主張する性質を書いてください。" +"(難しい)木に挿入された値は、どれだけ沢山の挿入があった後でも、その木の構成" +"要素であることを主張する性質を書いてください。" #. type: Title ## #: text/chapter13.md:249 @@ -11237,26 +11233,26 @@ msgstr "高階関数のテスト" #. type: Plain text #: text/chapter13.md:252 msgid "" -"The `Merge` module defines another generalization of the `merge` function - " -"the `mergeWith` function takes an additional function as an argument which " -"is used to determine the order in which elements should be merged. That is, " -"`mergeWith` is a higher-order function." +"The `Merge` module defines another generalization of the `merge` function – " +"the `mergeWith` function takes an additional function as an argument to " +"determine the order in which elements should be merged. That is, `mergeWith` " +"is a higher-order function." msgstr "" -"`Merge`モジュールは `merge`関数の別の一般化も定義しています。\n" -"`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を決定するの" -"に使われます。\n" -"つまり `mergeWith`は高階関数です。" +"`Merge`モジュールは`merge`関数の別の一般化も定義しています。\n" +"`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を判定しま" +"す。\n" +"つまり`mergeWith`は高階関数です。" #. type: Plain text #: text/chapter13.md:254 msgid "" -"For example, we can pass the `length` function as the first argument, to " -"merge two arrays which are already in length-increasing order. The result " -"should also be in length-increasing order:" +"For example, we can pass the `length` function as the first argument to " +"merge two arrays already in length-increasing order. The result should also " +"be in length-increasing order:" msgstr "" "例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列" "を統合できます。\n" -"このとき、結果も長さの昇順になっていなければなりません。" +"その結果もまた長さの昇順になっているでしょう。" #. type: Fenced code block (haskell) #: text/chapter13.md:255 @@ -11282,20 +11278,20 @@ msgstr "" #: text/chapter13.md:266 msgid "" "How might we test such a function? Ideally, we would like to generate values " -"for all three arguments, including the first argument which is a function." +"for all three arguments, including the first argument, which is a function." msgstr "" "このような関数をテストするにはどうしたらいいでしょうか。\n" -"理想的には、関数である最初の引数を含めた、3つの引数全てについて、値を生成した" -"いと思うでしょう。" +"理想的には、関数である最初の引数を含めた3つの引数全てについて、値を生成したい" +"ところです。" #. type: Plain text #: text/chapter13.md:268 msgid "" -"There is a second type class which allows us to create randomly-generated " +"There is a second type class that allows us to create randomly-generated " "functions. It is called `Coarbitrary`, and it is defined as follows:" msgstr "" -"関数を無作為に生成できるようにする、もう1つの型クラスがあります。\n" -"この型クラスは `Coarbitrary`と呼ばれており、次のように定義されています。" +"無作為に生成された関数を作れるようにする、2つ目の型クラスがあります。\n" +"`Coarbitrary`という名前で次のように定義されています。" #. type: Fenced code block (haskell) #: text/chapter13.md:269 @@ -11310,24 +11306,26 @@ msgstr "" #. type: Plain text #: text/chapter13.md:275 msgid "" -"The `coarbitrary` function takes a function argument of type `t`, and a " -"random generator for a function result of type `r`, and uses the function " +"The `coarbitrary` function takes a function argument of type `t` and a " +"random generator for a function result of type `r`. It uses the function " "argument to _perturb_ the random generator. That is, it uses the function " "argument to modify the random output of the random generator for the result." msgstr "" -"`coarbitrary`関数は、型 `t`と、関数の結果の型 `r`についての乱数生成器を関数の" -"引数としてとり、乱数生成器を _かき乱す_ のにこの引数を使います。つまり関数の" -"引数を使って、乱数生成器の無作為な出力を変更しているのです。" +"`coarbitrary`関数は、型`t`の関数の引数と、型`r`の関数の結果の乱数生成器を取り" +"ます。\n" +"この関数引数を使って乱数生成器を*かき乱し*ます。\n" +"つまり、関数の引数を使って乱数生成器の無作為な出力を変更し、結果としているの" +"です。" #. type: Plain text #: text/chapter13.md:277 msgid "" -"In addition, there is a type class instance which gives us `Arbitrary` " +"In addition, there is a type class instance that gives us `Arbitrary` " "functions if the function domain is `Coarbitrary` and the function codomain " "is `Arbitrary`:" msgstr "" -"また、もし関数の定義域が `Coarbitrary`で、値域が `Arbitrary`なら、`Arbitrary`" -"の関数を与える型クラスインスタンスが存在します。" +"また、もし関数の定義域が`Coarbitrary`で値域が`Arbitrary`なら、`Arbitrary`の関" +"数を与える型クラスインスタンスが存在します。" #. type: Fenced code block (haskell) #: text/chapter13.md:278 @@ -11338,31 +11336,30 @@ msgstr "instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b)\n" #. type: Plain text #: text/chapter13.md:283 msgid "" -"In practice, this means that we can write properties which take functions as " -"arguments. In the case of the `mergeWith` function, we can generate the " -"first argument randomly, modifying our tests to take account of the new " -"argument." +"In practice, we can write properties that take functions as arguments. In " +"the case of the `mergeWith` function, we can generate the first argument " +"randomly, modifying our tests to take account of the new argument." msgstr "" -"実は、これが意味しているのは、引数として関数を取るような性質を記述できるとい" -"うことです。 `mergeWith`関数の場合では、新しい引数を考慮するようにテストを修" -"正すると、最初の引数を無作為に生成できます。" +"実際のところ、引数として関数を取るような性質を記述できます。\n" +"`mergeWith`関数の場合では、新しい引数を考慮するようにテストを修正すると、最初" +"の引数を無作為に生成できます。" #. type: Plain text #: text/chapter13.md:285 msgid "" -"We cannot guarantee that the result will be sorted - we do not even " -"necessarily have an `Ord` instance - but we can expect that the result be " +"We cannot guarantee that the result will be sorted – we do not even " +"necessarily have an `Ord` instance – but we can expect that the result be " "sorted with respect to the function `f` that we pass in as an argument. In " -"addition, we need the two input arrays to be sorted with respect to `f`, so " -"we use the `sortBy` function to sort `xs` and `ys` based on comparison after " +"addition, we need the two input arrays to be sorted concerning `f`, so we " +"use the `sortBy` function to sort `xs` and `ys` based on comparison after " "the function `f` has been applied:" msgstr "" "結果が整列されていることは保証できません。\n" -"必ずしも`Ord`インスタンスを持っているとさえ限らないのです。\n" -"しかし、引数として渡す関数 `f`に従って結果が整列されていることは期待されま" +"`Ord`インスタンスを持っているとさえ限らないのです。\n" +"しかし、引数として渡す関数`f`に従って結果が整列されていることは期待されま" "す。\n" -"更に、2つの入力配列が `f`に従って整列されている必要がありますので、`sortBy`関" -"数を使って関数 `f`が適用されたあとの比較に基づいて `xs`と`ys`を整列します。" +"更に、2つの入力配列が`f`に従って整列されている必要がありますので、`sortBy`関" +"数を使って関数`f`が適用されたあとの比較に基づいて`xs`と`ys`を整列します。" #. type: Fenced code block (haskell) #: text/chapter13.md:286 @@ -11426,14 +11423,13 @@ msgstr "instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b)\n" #. type: Plain text #: text/chapter13.md:315 msgid "" -"This means that we are not limited to just values and functions - we can " +"This means that we are not limited to just values and functions – we can " "also randomly generate _higher-order functions_, or functions whose " "arguments are higher-order functions, and so on." msgstr "" -"これは値の生成が単純な関数だけに限定されるものではないことを意味していま" -"す。\n" -"つまり*高階関数*や、引数が高階関数であるような関数もまた、無作為に生成できる" -"のです。" +"つまり値や関数だけに制限されません。\n" +"*高階関数*や、引数が高階関数であるような関数やその他諸々もまた、無作為に生成" +"できるのです。" #. type: Title ## #: text/chapter13.md:316 @@ -11473,13 +11469,13 @@ msgstr "instance Coarbitrary a => Coarbitrary (Tree a) where\n" #. type: Plain text #: text/chapter13.md:327 msgid "" -"We have to write a function which perturbs a random generator given a value " -"of type `Tree a`. If the input value is a `Leaf`, then we will just return " -"the generator unchanged:" +"We have to write a function that perturbs a random generator given a value " +"of type `Tree a`. If the input value is a `Leaf`, then we will return the " +"generator unchanged:" msgstr "" -"型 `Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があ" +"型`Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があ" "ります。\n" -"入力値が `Leaf`であれば、そのままにしておく生成器を返します。" +"入力値が`Leaf`であれば、そのままにしておく生成器を返します。" #. type: Fenced code block (haskell) #: text/chapter13.md:328 @@ -11515,14 +11511,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:342 msgid "" -"Now we are free to write properties whose arguments include functions taking " -"trees as arguments. For example, the `Tree` module defines a function " -"`anywhere`, which tests if a predicate holds on any subtree of its argument:" +"Now we can write properties whose arguments include functions taking trees " +"as arguments. For example, the `Tree` module defines a function `anywhere`, " +"which tests if a predicate holds on any subtree of its argument:" msgstr "" "これで、木を引数にとるような関数を引数に含む性質を自由に書くことができるよう" "になりました。\n" -"例えば`Tree`モジュールでは`anywhere`が定義されており、これは述語が引数のどん" -"な部分木についても成り立っているかを調べる関数です。" +"例えば`Tree`モジュールでは関数`anywhere`が定義されています。\n" +"これは述語が引数のどんな部分木についても満たされるかを調べます。" #. type: Fenced code block (haskell) #: text/chapter13.md:343 @@ -11533,11 +11529,11 @@ msgstr "anywhere :: forall a. (Tree a -> Boolean) -> Tree a -> Boolean\n" #. type: Plain text #: text/chapter13.md:348 msgid "" -"Now we are able to generate the predicate function randomly. For example, we " -"expect the `anywhere` function to _respect disjunction_:" +"Now we can generate the predicate function randomly. For example, we expect " +"the `anywhere` function to _respect disjunction_:" msgstr "" -"これで、この述語関数`anywhere`を無作為に生成できるようになりました。\n" -"例えば、 `anywhere`関数は*ある命題のもとで不変*であることが期待されます。" +"今となっては述語関数を無作為に生成できます。\n" +"例えば、`anywhere`関数は*選言の法則を満たす*ことが期待されます。" #. type: Fenced code block (haskell) #: text/chapter13.md:349 @@ -11582,15 +11578,14 @@ msgid "" "For the purposes of testing, we usually include calls to the `quickCheck` " "function in the `main` action of our test suite. However, there is a variant " "of the `quickCheck` function, called `quickCheckPure` which does not use " -"side-effects. Instead, it is a pure function which takes a random seed as an " -"input, and returns an array of test results." +"side-effects. Instead, it is a pure function that takes a random seed as an " +"input and returns an array of test results." msgstr "" -"通常、テストの目的ではテストスイートの `main`アクションに`quickCheck`関数の呼" -"び出しが含まれています。\n" -"しかし、副作用を使わない`quickCheckPure`と呼ばれる `quickCheck`関数の亜種もあ" -"ります。\n" -"`quickCheckPure`は、入力として乱数の種をとり、テスト結果の配列を返す純粋な関" -"数です。" +"通常、テストの目的ではテストスイートの`main`動作に`quickCheck`関数の呼び出し" +"が含まれています。\n" +"しかし`quickCheck`関数には亜種があり、`quickCheckPure`という名前です。\n" +"副作用を使わない代わりに、入力として乱数の種を取ってテスト結果の配列を返す純" +"粋な関数です。" #. type: Plain text #: text/chapter13.md:367 @@ -11639,7 +11634,7 @@ msgid "" "see an array of `Success` data constructors printed to the console." msgstr "" "`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を" -"とります。\n" +"取ります。\n" "もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出" "力されます。" @@ -11647,8 +11642,8 @@ msgstr "" #: text/chapter13.md:386 msgid "" "`quickCheckPure` might be useful in other situations, such as generating " -"random input data for performance benchmarks, or generating sample form data " -"for web applications." +"random input data for performance benchmarks or sample form data for web " +"applications." msgstr "" "`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションの" "フォームデータ例を無作為に生成するというような状況で便利かもしれません。" @@ -11699,14 +11694,14 @@ msgstr "" #, no-wrap msgid "" " _Hint_: Use the `oneOf` function defined in `Test.QuickCheck.Gen` to define your `Arbitrary` instance.\n" -" 1. (Medium) Use `all` to simplify the result of the `quickCheckPure` function - your new function should have type `List Result -> Boolean` and should return `true` if every test passes and `false` otherwise.\n" +" 1. (Medium) Use `all` to simplify the result of the `quickCheckPure` function – your new function should have the type `List Result -> Boolean` and should return `true` if every test passes and `false` otherwise.\n" " 1. (Medium) As another approach to simplifying the result of `quickCheckPure`, try writing a function `squashResults :: List Result -> Result`. Consider using the `First` monoid from `Data.Maybe.First` with the `foldMap` function to preserve the first error in case of failure.\n" msgstr "" -" *手掛かり*:`Test.QuickCheck.Gen`で定義された `oneOf`関数を使って `Arbitrary`インスタンスを定義してください。\n" -" 1. (普通)`all`を使って `quickCheckPure`関数の結果を単純化してください。\n" +" *手掛かり*:`Test.QuickCheck.Gen`で定義された`oneOf`関数を使って`Arbitrary`インスタンスを定義してください。\n" +" 1. (普通)`all`を使って`quickCheckPure`関数の結果を単純化してください。\n" " この新しい関数は型`List Result -> Boolean`を持ち、全てのテストが通れば`true`を、そうでなければ`false`を返します。\n" " 2. (普通)`quickCheckPure`の結果を単純にする別の手法として、関数`squashResults :: List Result -> Result`を書いてみてください。\n" -" `Data.Maybe.First`の`First`モノイドと共に`foldMap`関数を使うことで、失敗した場合の最初のエラーを保存することを検討してください。\n" +" `Data.Maybe.First`の`First`モノイドと共に`foldMap`関数を使うことで、失敗した場合の最初のエラーを保持することを検討してください。\n" #. type: Plain text #: text/chapter13.md:404 @@ -11727,22 +11722,21 @@ msgstr "`spago test`を使ってQuickCheckのテストを自動化する方法 #. type: Bullet: '- ' #: text/chapter13.md:408 msgid "" -"We saw how to write properties as functions, and how to use the `` " +"We saw how to write properties as functions and how to use the `` " "operator to improve error messages." msgstr "" -"性質を関数として書く方法とエラーメッセージを改良する ``演算子の使い方を説" -"明しました。" +"性質を関数として書く方法とエラー文言を改良する``演算子の使い方を説明しまし" +"た。" #. type: Bullet: '- ' #: text/chapter13.md:408 msgid "" "We saw how the `Arbitrary` and `Coarbitrary` type classes enable generation " -"of boilerplate testing code, and how they allow us to test higher-order " +"of boilerplate testing code and how they allow us to test higher-order " "properties." msgstr "" -"`Arbitrary`と `Coarbitrary`型クラスによって、如何にして定型的なテストコードの" -"自動生成を可能にし、またどうすれば高階な性質関数が可能になるかを見てきまし" -"た。" +"`Arbitrary`と`Coarbitrary`型クラスによって定型的なテストコードの自動生成を可" +"能にする方法や、高階な性質のテストを可能にする方法を見ました。" #. type: Bullet: '- ' #: text/chapter13.md:408 @@ -11771,14 +11765,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:8 msgid "" -"A domain-specific language is a language which is well-suited to development " +"A domain-specific language is a language that is well-suited to development " "in a particular problem domain. Its syntax and functions are chosen to " -"maximize readability of code used to express ideas in that domain. We have " -"already seen a number of examples of domain-specific languages in this book:" +"maximize the readability of code used to express ideas in that domain. We " +"have already seen several examples of domain-specific languages in this book:" msgstr "" "領域特化言語とは、特定の問題領域での開発に適した言語のことです。\n" -"領域特化言語の構文及び機能は、その領域内の考え方を表現するコードの読みやすさ" -"を最大限に発揮すべく選択されます。\n" +"構文及び機能は、その領域内の考え方を表現するに使われるコードの読みやすさを最" +"大化すべく選択されます。\n" "本書の中では、既に領域特化言語の例を幾つか見てきています。" #. type: Bullet: '- ' @@ -11788,54 +11782,53 @@ msgid "" "constitute a domain-specific language for the domain of _text adventure game " "development_." msgstr "" -"第11章で開発された `Game`モナドと関連するアクションは、 _テキストアドベン" -"チャーゲーム開発_ という領域に対しての領域特化言語を構成しています。" +"第11章で開発された`Game`モナドと関連する動作は、*テキストアドベンチャーゲーム" +"開発*という領域に対しての領域特化言語を構成しています。" #. type: Bullet: '- ' #: text/chapter14.md:11 msgid "" -"The `quickcheck` package, covered in chapter 13, is a domain-specific " +"The `quickcheck` package, covered in Chapter 13, is a domain-specific " "language for the domain of _generative testing_. Its combinators enable a " "particularly expressive notation for test properties." msgstr "" -"第13章で扱った `quickcheck`パッケージは、 _生成的テスティング_ の領域の領域特" -"化言語です。このコンビネータはテストの性質に対して特に表現力の高い記法を可能" -"にします。" +"第13章で扱った`quickcheck`パッケージは、*生成的テスティング*の領域に向けた領" +"域特化言語です。\n" +"このコンビネータはテストの性質に対して特に表現力の高い記法を可能にします。" #. type: Plain text #: text/chapter14.md:13 msgid "" -"This chapter will take a more structured approach to some of standard " -"techniques in the implementation of domain-specific languages. It is by no " -"means a complete exposition of the subject, but should provide you with " -"enough knowledge to build some practical DSLs for your own tasks." +"This chapter will take a more structured approach to some standard " +"techniques in implementing domain-specific languages. It is by no means a " +"complete exposition of the subject, but should provide you with enough " +"knowledge to build some practical DSLs for your own tasks." msgstr "" -"この章では、領域特化言語の実装において、幾つかの標準的な技法による構造的な手" -"法に迫ります。\n" -"これがこの話題の完全な説明だということでは決してありませんが、自分の目的に合" -"う具体的なDSLを構築するのには充分な知識をもたらすことでしょう。" +"この章では、領域特化言語の実装において、幾つかの標準的な技法にについて構造的" +"な手法を取ります。\n" +"この話題の完全な解説では決してありませんが、目的に合う実践的なDSLを構築するの" +"に充分な知識は得られるでしょう。" #. type: Plain text #: text/chapter14.md:15 msgid "" "Our running example will be a domain-specific language for creating HTML " -"documents. Our aim will be to develop a type-safe language for describing " +"documents. We will aim to develop a type-safe language for describing " "correct HTML documents, and we will work by improving a naive implementation " "in small steps." msgstr "" -"この章で実行している例は、HTML文書を作成するための領域特化言語です。\n" +"ここでの実行例はHTML文書を作成するための領域特化言語です。\n" "正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装" "を徐々に改善しつつ進めていきます。" #. type: Plain text #: text/chapter14.md:19 msgid "" -"The project accompanying this chapter adds one new dependency - the `free` " -"library, which defines the _free monad_, one of the tools which we will be " -"using." +"The project accompanying this chapter adds one new dependency – the `free` " +"library, which defines the _free monad_, one of the tools we will use." msgstr "" -"この章で使うプロジェクトには新しい依存性が1つ追加されます。これから使う道具の" -"1つである*Freeモナド*が定義されている `free`ライブラリです。" +"この章に付随するプロジェクトには新しい依存性が1つ追加されます。\n" +"これから使う道具の1つである*Freeモナド*が定義されている`free`ライブラリです。" #. type: Plain text #: text/chapter14.md:21 @@ -11845,7 +11838,7 @@ msgstr "このプロジェクトをPSCiを使って試していきます。" #. type: Title ## #: text/chapter14.md:22 #, no-wrap -msgid "A HTML Data Type" +msgid "An HTML Data Type" msgstr "HTMLデータ型" #. type: Plain text @@ -11895,14 +11888,14 @@ msgstr "" #: text/chapter14.md:44 msgid "" "The `Element` type represents HTML elements. Each element consists of an " -"element name, an array of attribute pairs and some content. The content " +"element name, an array of attribute pairs, and some content. The content " "property uses the `Maybe` type to indicate that an element might be open " "(containing other elements and text) or closed." msgstr "" -"`Element`型はHTMLの要素を表しています。\n" -"各要素は要素名、属性の対の配列と、要素の内容で構成されています。\n" -"contentプロパティは、`Maybe`タイプを適切に使って、要素が開いている(他の要素" -"やテキストを含む)か閉じているかを示しています。" +"`Element`型はHTMLの要素を表します。\n" +"各要素は要素名、属性の対の配列と、内容で構成されます。\n" +"内容のプロパティには`Maybe`型を適切に使い、要素が開いている(他の要素やテキス" +"トを含む)か閉じているかを示します。" #. type: Plain text #: text/chapter14.md:46 @@ -11988,10 +11981,10 @@ msgstr "現状のライブラリには幾つもの問題があります。" #. type: Bullet: '- ' #: text/chapter14.md:87 msgid "" -"Creating HTML documents is difficult - every new element requires at least " +"Creating HTML documents is difficult – every new element requires at least " "one record and one data constructor." msgstr "" -"HTML文書の作成に手がかかります。\n" +"HTML文書の作成に手が掛かります。\n" "全ての新しい要素に少なくとも1つのレコードと1つのデータ構築子が必要です。" #. type: Bullet: '- ' @@ -12035,15 +12028,15 @@ msgstr "スマート構築子" msgid "" "The first technique we will apply is simple but can be very effective. " "Instead of exposing the representation of the data to the module's users, we " -"can use the module exports list to hide the `Element`, `Content` and " +"can use the module exports list to hide the `Element`, `Content`, and " "`Attribute` data constructors, and only export so-called _smart " -"constructors_, which construct data which is known to be correct." +"constructors_, which construct data known to be correct." msgstr "" -"最初に導入する手法は方法こそ単純なものですが、とても効果的です。\n" +"最初に導入する手法は単純ですがとても効果的です。\n" "モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリ" -"ストを使ってデータ構築子 `Element`、 `Content`、 `Attribute`を隠蔽し、正しい" -"ことが明らかなデータだけ構築する、いわゆる*スマート構築子*だけをエクスポート" -"します。" +"ストを使ってデータ構築子`Element`、`Content`、`Attribute`を隠蔽します。\n" +"そして正しいことが分かっているデータを構築する、いわゆる*スマート構築子*だけ" +"をエクスポートします。" #. type: Plain text #: text/chapter14.md:95 @@ -12075,10 +12068,11 @@ msgstr "" #: text/chapter14.md:106 msgid "" "Next, we create smart constructors for those HTML elements we want our users " -"to be able to create, by applying the `element` function:" +"to be able to create by applying the `element` function:" msgstr "" -"次に、欲しいHTML要素を利用者が作れるように、スマート構築子を作成します。\n" -"これには`element`関数を適用します。" +"次にHTML要素のためのスマート構築子を作成します。\n" +"この要素は利用者が`element`関数を適用して作成できるようになってほしいもので" +"す。" #. type: Fenced code block (haskell) #: text/chapter14.md:107 @@ -12161,24 +12155,24 @@ msgstr "型クラス。クラス名により指定されます。" #. type: Bullet: '- ' #: text/chapter14.md:139 msgid "" -"A type constructor and any associated data constructors, indicated by the " +"A type constructor and any associated data constructors indicated by the " "name of the type followed by a parenthesized list of exported data " "constructors." msgstr "" -"型構築子と関連するデータ構築子。型名とそれに続くエクスポートされるデータ構築" -"子の括弧で囲まれたリストで指定されます。" +"型構築子とそれに紐付くデータ構築子。\n" +"型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定さ" +"れます。" #. type: Plain text #: text/chapter14.md:141 msgid "" "Here, we export the `Element` _type_, but we do not export its data " -"constructors. If we did, the user would be able to construct invalid HTML " -"elements." +"constructors. If we did, the user could construct invalid HTML elements." msgstr "" -"ここでは、 `Element`の*型*をエクスポートしていますが、データ構築子はエクス" -"ポートしていません。\n" -"もしデータ構築子をエクスポートすると、モジュールの使用者が不正なHTML要素を構" -"築できてしまいます。" +"ここでは、`Element`の*型*をエクスポートしていますが、データ構築子はエクスポー" +"トしていません。\n" +"もしデータ構築子をエクスポートすると、使用者が不正なHTML要素を構築できてしま" +"います。" #. type: Plain text #: text/chapter14.md:143 @@ -12202,8 +12196,8 @@ msgid "" "It is impossible to represent HTML elements with invalid names (of course, " "we are restricted to the set of element names provided by the library)." msgstr "" -"不正な名前を持つHTML要素は表現できません(もちろん、ライブラリが提供する要素" -"名に制限されています)。" +"不正な名前を持つHTML要素は表現できません(勿論ライブラリが提供する要素名に制" +"限されています)。" #. type: Bullet: '- ' #: text/chapter14.md:148 @@ -12214,12 +12208,12 @@ msgstr "閉じた要素は構築するときに内容を含められません。 #: text/chapter14.md:150 msgid "" "We can apply this technique to the `Content` type very easily. We simply " -"remove the data constructors for the `Content` type from the exports list, " +"remove the data constructors for the `Content` type from the exports list " "and provide the following smart constructors:" msgstr "" "`Content`型にとても簡単にこの手法を適用できます。\n" -"単にエクスポートリストから `Content`型のデータ構築子を取り除き、次のスマート" -"構築子を提供します。" +"単にエクスポートリストから`Content`型のデータ構築子を取り除き、次のスマート構" +"築子を提供します。" #. type: Fenced code block (haskell) #: text/chapter14.md:151 @@ -12271,12 +12265,12 @@ msgstr "" #: text/chapter14.md:172 msgid "" "This representation suffers from the same problem as the original `Element` " -"type - it is possible to represent attributes which do not exist or whose " +"type – it is possible to represent attributes that do not exist or whose " "names were entered incorrectly. To solve this problem, we can create a " -"newtype which represents attribute names:" +"newtype that represents attribute names:" msgstr "" -"この定義では元の `Element`型と同じ問題に直面しています。\n" -"存在しなかったり、名前が間違っているような属性を表現できます。\n" +"この定義では元の`Element`型と同じ問題に直面しています。\n" +"存在しなかったり、名前が間違って入力された属性を表現できます。\n" "この問題を解決するために、属性名を表すnewtypeを作成します。" #. type: Fenced code block (haskell) @@ -12449,15 +12443,15 @@ msgstr "" msgid "" "Note, however, that no changes had to be made to the `render` function, " "because the underlying data representation never changed. This is one of the " -"benefits of the smart constructors approach - it allows us to separate the " -"internal data representation for a module from the representation which is " -"perceived by users of its external API." +"benefits of the smart constructors approach – it allows us to separate the " +"internal data representation for a module from the representation perceived " +"by users of its external API." msgstr "" -"しかし、基盤をなすデータ表現は変更されなかったので、 `render`関数を変更する必" -"要はなかったことにも注目してください。\n" +"しかし、基盤をなすデータ表現は全く変更されなかったので、`render`関数を変更す" +"る必要はなかったことにも注目してください。\n" "これはスマート構築子による手法の利点のひとつです。\n" -"外部APIの使用者によって認識される表現からモジュールの内部データ表現を分離でき" -"るのです。" +"外部APIの使用者によって認識される表現から、モジュールの内部データ表現を分離で" +"きるのです。" #. type: Bullet: ' 1. ' #: text/chapter14.md:253 @@ -12471,11 +12465,11 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:253 msgid "" -"(Medium) Some HTML attributes such as `checked` and `disabled` do not " -"require values, and may be rendered as _empty attributes_:" +"(Medium) Some HTML attributes, such as `checked` and `disabled`, do not " +"require values and may be rendered as _empty attributes_:" msgstr "" -"(普通)`checked`と `disabled`など、値を要求しないHTML属性がありますが、これ" -"らは次のような _空の属性_ として表示されるかもしれません。" +"(普通)`checked`や`disabled`といったHTML属性は値を要求せず、*空の属性*として" +"書き出せます。" #. type: Plain text #: text/chapter14.md:257 @@ -12744,26 +12738,26 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:356 msgid "" -"(Easy) Create a data type which represents either pixel or percentage " -"lengths. Write an instance of `IsValue` for your type. Modify the `width` " -"and `height` attributes to use your new type." +"(Easy) Create a data type representing either pixel or percentage lengths. " +"Write an instance of `IsValue` for your type. Modify the `width` and " +"`height` attributes to use your new type." msgstr "" -"(簡単)ピクセルまたはパーセントの長さの何れかを表すデータ型を作成してくださ" +"(簡単)ピクセルまたはパーセントの何れかの長さを表すデータ型を作成してくださ" "い。\n" -"その型について `IsValue`のインスタンスを書いてください。\n" -"この型を使うように `width`と `height`属性を変更してください。" +"その型について`IsValue`のインスタンスを書いてください。\n" +"この新しい型を使うように`width`と`height`属性を変更してください。" #. type: Bullet: ' 1. ' #: text/chapter14.md:356 msgid "" "(Difficult) By defining type-level representatives for the Boolean values " "`true` and `false`, we can use a phantom type to encode whether an " -"`AttributeKey` represents an _empty attribute_ such as `disabled` or " +"`AttributeKey` represents an _empty attribute_, such as `disabled` or " "`checked`." msgstr "" -"(難しい)幻影型を使って真偽値 `true`、 `false`用の最上位の表現を定義すること" -"で、 `AttributeKey`が `disabled`や `checked`のような*空の属性*を表現している" -"かどうかをエンコードできます。" +"(難しい)真偽値`true`、`false`用の最上位の表現を定義することで、幻影型を使っ" +"て`AttributeKey`が`disabled`や`checked`のような*空の属性*を表現しているかどう" +"かをエンコードできます。" #. type: Plain text #: text/chapter14.md:361 @@ -12797,11 +12791,13 @@ msgid "" "In our final set of modifications to our API, we will use a construction " "called the _free monad_ to turn our `Content` type into a monad, enabling do " "notation. This will allow us to structure our HTML documents in a form in " -"which the nesting of elements becomes clearer - instead of this:" +"which the nesting of elements becomes clearer – instead of this:" msgstr "" -"APIに施す最後の変更は、 `Content`型をモナドにしてdo記法を使えるようにするため" -"に、 _Freeモナド_ と呼ばれる構造を使うことです。これによって入れ子になった要" -"素がわかりやすくなるようにHTML文書を構造化できます。以下の代わりに……" +"APIに施す最後の変更では、`Content`型をモナドにしてdo記法を使えるようにするた" +"めに、*Freeモナド*と呼ばれる構造を使っていきます。\n" +"これによって入れ子になった要素がわかりやすくなるような形式でHTML文書を構造化" +"できます。\n" +"以下の代わりに……" #. type: Fenced code block (haskell) #: text/chapter14.md:368 @@ -12855,22 +12851,22 @@ msgstr "" msgid "" "However, do notation is not the only benefit of a free monad. The free monad " "allows us to separate the _representation_ of our monadic actions from their " -"_interpretation_, and even support _multiple interpretations_ of the same " +"_interpretation_ and even support _multiple interpretations_ of the same " "actions." msgstr "" -"しかし、do記法だけがFreeモナドの恩恵だというわけではありません。Freeモナドが" -"あれば、モナドのアクションの _表現_ をその _解釈_ から分離し、同じアクション" -"に _複数の解釈_ を持たせることさえできます。" +"しかし、do記法だけがFreeモナドの恩恵ではありません。\n" +"Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複" +"数の解釈*を持たせることさえできます。" #. type: Plain text #: text/chapter14.md:394 msgid "" -"The `Free` monad is defined in the `free` library, in the `Control.Monad." +"The `Free` monad is defined in the `free` library in the `Control.Monad." "Free` module. We can find out some basic information about it using PSCi, as " "follows:" msgstr "" -"`Free`モナドは `free`ライブラリの `Control.Monad.Free`モジュールで定義されて" -"います。\n" +"`Free`モナドは`free`ライブラリの`Control.Monad.Free`モジュールで定義されてい" +"ます。\n" "PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができま" "す。" @@ -12891,13 +12887,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:403 msgid "" -"The kind of `Free` indicates that it takes a type constructor as an " -"argument, and returns another type constructor. In fact, the `Free` monad " -"can be used to turn any `Functor` into a `Monad`!" +"The kind of `Free` indicates that it takes a type constructor as an argument " +"and returns another type constructor. In fact, the `Free` monad can be used " +"to turn any `Functor` into a `Monad`!" msgstr "" "`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示していま" "す。\n" -"実は、`Free`モナドを使えば任意の`Functor`を`Monad`にできます。" +"実はなんと、`Free`モナドを使えば任意の`Functor`を`Monad`にできるのです。" #. type: Plain text #: text/chapter14.md:405 @@ -12905,14 +12901,13 @@ msgid "" "We begin by defining the _representation_ of our monadic actions. To do " "this, we need to create a `Functor` with one data constructor for each " "monadic action we wish to support. In our case, our two monadic actions will " -"be `elem` and `text`. In fact, we can simply modify our `Content` type as " -"follows:" +"be `elem` and `text`. We can simply modify our `Content` type as follows:" msgstr "" -"モナドのアクションの*表現*の定義から始めます。\n" -"こうするには、対応する各モナドアクションそれぞれについて、1つのデータ構築子を" -"持つ `Functor`を作成する必要があります。\n" -"今回の場合、2つのモナドのアクションは `elem`と `text`になります。\n" -"実際には、 `Content`型を次のように変更するだけです。" +"モナドの動作の*表現*の定義から始めます。\n" +"これには対応したい各モナド動作について、1つのデータ構築子を持つ`Functor`を作" +"成する必要があります。\n" +"今回の場合、2つのモナドの動作は`elem`と`text`になります。\n" +"`Content`型を次のように変更するだけでできます。" #. type: Fenced code block (haskell) #: text/chapter14.md:406 @@ -12938,16 +12933,16 @@ msgstr "" #: text/chapter14.md:417 msgid "" "Here, the `ContentF` type constructor looks just like our old `Content` data " -"type - however, it now takes a type argument `a`, and each data constructor " +"type – however, it now takes a type argument `a`, and each data constructor " "has been modified to take a value of type `a` as an additional argument. The " "`Functor` instance simply applies the function `f` to the value of type `a` " "in each data constructor." msgstr "" -"ここで、この `ContentF`型構築子は以前の `Content`データ型とよく似ています。\n" +"ここで、この`ContentF`型構築子は以前の`Content`データ型とよく似ています。\n" "しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引" "数として取るように変更されています。\n" -"`Functor`インスタンスでは、単に各データ構築子で型 `a`の構成要素に関数 `f`を適" -"用します。" +"`Functor`インスタンスでは、単に各データ構築子で型`a`の値に関数`f`を適用しま" +"す。" #. type: Plain text #: text/chapter14.md:419 @@ -12970,14 +12965,14 @@ msgstr "type Content = Free ContentF\n" #: text/chapter14.md:425 msgid "" "Instead of a type synonym, we might use a `newtype` to avoid exposing the " -"internal representation of our library to our users - by hiding the " +"internal representation of our library to our users – by hiding the " "`Content` data constructor, we restrict our users to only using the monadic " "actions we provide." msgstr "" -"型シノニムの代わりにnewtypeを使用して、使用者に対してライブラリの内部表現を露" +"型同義語の代わりに`newtype`を使用して、使用者に対してライブラリの内部表現を露" "出することを避けられます。\n" -"`Content`データ構築子を隠すことで、提供しているモナドのアクションだけを使うこ" -"とを使用者に制限しています。" +"`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使" +"用者に制限しています。" #. type: Plain text #: text/chapter14.md:427 @@ -13020,14 +13015,14 @@ msgstr "" msgid "" "In addition, we have to modify our `elem` and `text` functions, which become " "our new monadic actions for the `Content` monad. To do this, we can use the " -"`liftF` function, provided by the `Control.Monad.Free` module. Here is its " +"`liftF` function provided by the `Control.Monad.Free` module. Here is its " "type:" msgstr "" -"また、 `Content`モナドについての新しいモナドのアクションになる `elem`と " -"`text`関数を変更する必要があります。\n" +"また、`Content`モナドについての新しいモナドの動作になるよう、`elem`と`text`関" +"数を変更する必要があります。\n" "これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えま" "す。\n" -"この関数の型は次のようになっています。" +"以下がその型です。" #. type: Fenced code block (haskell) #: text/chapter14.md:440 @@ -13039,12 +13034,12 @@ msgstr "liftF :: forall f a. f a -> Free f a\n" #: text/chapter14.md:445 msgid "" "`liftF` allows us to construct an action in our free monad from a value of " -"type `f a` for some type `a`. In our case, we can simply use the data " -"constructors of our `ContentF` type constructor directly:" +"type `f a` for some type `a`. In our case, we can use the data constructors " +"of our `ContentF` type constructor directly:" msgstr "" -"`liftF`により、何らかの型 `a`について、型 `f a`の値からFreeモナドのアクション" -"を構築できるようになります。\n" -"今回の場合、 `ContentF`型構築子のデータ構築子をそのまま使うだけです。" +"`liftF`により、何らかの型`a`について、型`f a`の値からFreeモナドの動作を構築で" +"きるようになります。\n" +"今回の場合、`ContentF`型構築子のデータ構築子をそのまま使えます。" #. type: Fenced code block (haskell) #: text/chapter14.md:446 @@ -13125,31 +13120,30 @@ msgid "" "The `runFree` function is used to compute a _pure_ result. The `runFreeM` " "function allows us to use a monad to interpret the actions of our free monad." msgstr "" -"`runFree`関数は、 _純粋な_ 結果を計算するために使用されます。 `runFreeM`関数" -"があればFreeモナドのアクションを解釈するためにモナドが使えます。" +"`runFree`関数は、*純粋な*結果を計算するために使用されます。\n" +"`runFreeM`関数があればFreeモナドの動作を解釈するためにモナドが使えます。" #. type: Plain text #: text/chapter14.md:479 msgid "" -"_Note_: Technically, we are restricted to using monads `m` which satisfy the " -"stronger `MonadRec` constraint. In practice, this means that we don't need " -"to worry about stack overflow, since `m` supports safe _monadic tail " -"recursion_." +"_Note_: Technically, we are restricted to monads `m` that satisfy the " +"stronger `MonadRec` constraint. In practice, we don't need to worry about " +"stack overflow since `m` supports safe _monadic tail recursion_." msgstr "" -"*補足*:厳密には、より強い`MonadRec`制約を満たすモナド `m`を使用するよう制限" -"されています。\n" -"実際には、これはスタックオーバーフローを心配する必要がないことを意味しま" +"*補足*:厳密には、より強い`MonadRec`制約を満たすモナド`m`に制限されていま" "す。\n" -"なぜなら `m`は安全な*末尾再帰モナド*に対応しているからです。" +"実際、ら`m`は安全な*末尾再帰モナド*に対応してため、スタックオーバーフローを心" +"配する必要はありません。" #. type: Plain text #: text/chapter14.md:481 msgid "" "First, we have to choose a monad in which we can interpret our actions. We " -"will use the `Writer String` monad to accumulate a HTML string as our result." +"will use the `Writer String` monad to accumulate an HTML string as our " +"result." msgstr "" -"まず、アクションを解釈できるモナドを選ばなければなりません。\n" -"`Writer String`モナドを使って、結果のHTML文字列を累積することにします。" +"まず、動作を解釈できるモナドを選ばなければなりません。\n" +"`Writer String`モナドを使って、結果のHTML文字列を累算することにします。" #. type: Plain text #: text/chapter14.md:483 @@ -13159,7 +13153,7 @@ msgid "" "`Writer` monad:" msgstr "" "新しい`render`メソッドが開始すると、補助関数 `renderElement`に移譲し、" -"`execWriter`を使って`Writer`モナドで計算を走らせます。" +"`execWriter`を使って`Writer`モナドで計算します。" #. type: Fenced code block (haskell) #: text/chapter14.md:484 @@ -13194,8 +13188,8 @@ msgid "" "The definition of `renderElement` is straightforward, using the `tell` " "action from the `Writer` monad to accumulate several small strings:" msgstr "" -"`renderElement`の定義は直感的で、複数の小さな文字列を累積するために `Writer`" -"モナドの `tell`アクションを使っています。" +"`renderElement`の定義は直感的で、複数の小さな文字列を累算するために`Writer`モ" +"ナドの`tell`動作を使っています。" #. type: Fenced code block (haskell) #: text/chapter14.md:499 @@ -13299,10 +13293,10 @@ msgstr " renderContentItem :: ContentF (Content Unit) -> Writer String (Con #. type: Plain text #: text/chapter14.md:540 msgid "" -"We can implement this function by simply pattern matching on the two data " +"We can implement this function by pattern matching on the two data " "constructors of `ContentF`:" msgstr "" -"`ContentF`の2つのデータ構築子でパターン照合するだけでこの関数を実装できます。" +"`ContentF`の2つのデータ構築子でパターン照合すればこの関数を実装できます。" #. type: Fenced code block (haskell) #: text/chapter14.md:541 @@ -13325,13 +13319,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:551 msgid "" -"In each case, the expression `rest` has the type `Content Unit`, and " +"In each case, the expression `rest` has the type `Content Unit` and " "represents the remainder of the interpreted computation. We can complete " "each case by returning the `rest` action." msgstr "" -"それぞれの場合において、式 `rest`は型 `Content Unit`を持っており、解釈計算の" -"残りを表しています。\n" -"`rest`アクションを呼び出すことによってそれぞれの場合を完了できます。" +"それぞれの場合において、式`rest`は型`Content Unit`を持っており、解釈された計" +"算の残りを表しています。\n" +"`rest`動作を返すことでそれぞれの場合を完成できます。" #. type: Plain text #: text/chapter14.md:553 @@ -13379,9 +13373,9 @@ msgid "" "to interpret your new constructor appropriately." msgstr "" "(普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメント" -"を出力する新しいアクション `comment`に対応してください。\n" -"`liftF`を使ってこの新しいアクションを実装してください。\n" -"新しい構築子を適切に解釈するように、解釈 `renderContentItem`を更新してくださ" +"を出力する新しい動作`comment`に対応してください。\n" +"`liftF`を使ってこの新しい動作を実装してください。\n" +"新しい構築子を適切に解釈するように、解釈`renderContentItem`を更新してくださ" "い。" #. type: Title ## @@ -13397,36 +13391,35 @@ msgid "" "particularly interesting. In fact, aside from an arguably nicer syntax, our " "monad adds no extra functionality over a `Monoid`." msgstr "" -"全てのアクションが型 `Unit`の何かを返すようなモナドは、さほど興味深いものでは" -"ありません。\n" -"実際のところ、概ね良くなったと思われる構文は別として、このモナドは `Monoid`以" +"全動作が型`Unit`の何かを返すようなモナドは、さほど興味深いものではありませ" +"ん。\n" +"実際のところ、概ね良くなったと思われる構文は別として、このモナドは`Monoid`以" "上の機能を何ら追加していません。" #. type: Plain text #: text/chapter14.md:578 msgid "" "Let's illustrate the power of the free monad construction by extending our " -"language with a new monadic action which returns a non-trivial result." +"language with a new monadic action that returns a non-trivial result." msgstr "" -"非自明な結果を返す新しいモナドアクションでこの言語を拡張することで、Freeモナ" -"ド構造の威力をお見せしましょう。" +"非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナドを構" +"築する威力をお見せしましょう。" #. type: Plain text #: text/chapter14.md:580 msgid "" -"Suppose we want to generate HTML documents which contain hyperlinks to " +"Suppose we want to generate HTML documents that contain hyperlinks to " "different sections of the document using _anchors_. We can accomplish this " -"already, by generating anchor names by hand and including them at least " -"twice in the document: once at the definition of the anchor itself, and once " -"in each hyperlink. However, this approach has some basic issues:" -msgstr "" -"*アンカー*を使用して文書のさまざまな節へのハイパーリンクが含まれているHTML文" -"書を生成するとします。\n" -"これは既に達成できています。\n" -"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めればよいので" -"す。\n" -"1つはアンカーの定義自身に、もう1つはそれぞれのハイパーリンクにあります。\n" -"しかし、この方法には根本的な問題が幾つかあります。" +"by generating anchor names by hand and including them at least twice in the " +"document: once at the anchor's definition and once in each hyperlink. " +"However, this approach has some basic issues:" +msgstr "" +"*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を" +"生成したいとします。\n" +"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めれば、これは" +"達成できます。\n" +"1つはアンカーの定義自身に、もう1つは各ハイパーリンクにあります。\n" +"しかし、この手法には基本的な問題が幾つかあります。" #. type: Bullet: '- ' #: text/chapter14.md:583 @@ -13441,12 +13434,12 @@ msgstr "開発者がアンカー名を1つ以上の箇所で打ち間違うか #. type: Plain text #: text/chapter14.md:585 msgid "" -"In the interest of protecting the developer from their own mistakes, we can " -"introduce a new type which represents anchor names, and provide a monadic " -"action for generating new unique names." +"To protect the developer from their mistakes, we can introduce a new type " +"that represents anchor names and provide a monadic action for generating new " +"unique names." msgstr "" "開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい" -"一意な名前を生成するためのモナドアクションを提供できます。" +"一意な名前を生成するためのモナド動作を提供できます。" #. type: Plain text #: text/chapter14.md:587 @@ -13480,11 +13473,11 @@ msgstr "" #. type: Plain text #: text/chapter14.md:598 msgid "" -"Next, we define an instance for the `IsValue` type class for our new type, " -"so that we are able to use names in attribute values:" +"Next, we define an instance for the `IsValue` type class for our new type so " +"that we can use names in attribute values:" msgstr "" -"次に、属性値として `Name`を使うことができるように、新しい型に`IsValue`型クラ" -"スのインスタンスを定義します。" +"次に、属性値に`Name`を使えるよう、新しい型に`IsValue`型クラスのインスタンスを" +"定義します。" #. type: Fenced code block (haskell) #: text/chapter14.md:599 @@ -13582,7 +13575,10 @@ msgstr "" #: text/chapter14.md:636 #, no-wrap msgid "The `NewName` data constructor corresponds to an action which returns a value of type `Name`. Notice that instead of requiring a `Name` as a data constructor argument, we require the user to provide a _function_ of type `Name -> a`. Remembering that the type `a` represents the _rest of the computation_, we can see that this function provides a way to continue computation after a value of type `Name` has been returned.\n" -msgstr "`NewName`データ構築子は型 `Name`の値を返すアクションに対応しています。データ構築子の引数として `Name`を要求するのではなく、型 `Name -> a`の _関数_ を提供するように使用者に要求していることに注意してください。型 `a`は _計算の残り_ を表していることを思い出すと、この関数は、型 `Name`の値が返されたあとで、計算を継続する方法を提供しているのだとわかります。\n" +msgstr "" +"`NewName`データ構築子は型`Name`の値を返す動作に対応しています。\n" +"データ構築子の引数として`Name`を要求するのではなく、型`Name -> a`の*関数*を提供するように使用者に要求していることに注意してください。\n" +"型`a`は*計算の残り*を表していることを思い出すと、この関数は、型`Name`の値が返されたあとで、計算を継続する方法を提供しているのだとわかります。\n" #. type: Plain text #: text/chapter14.md:638 @@ -13611,8 +13607,7 @@ msgstr "" #: text/chapter14.md:647 msgid "" "Now we can build our new action by using the `liftF` function, as before:" -msgstr "" -"これで、以前と同じように`liftF`関数を使って新しいアクションを構築できます。" +msgstr "これで、以前と同じように`liftF`関数を使って新しい動作を構築できます。" #. type: Fenced code block (haskell) #: text/chapter14.md:648 @@ -13627,30 +13622,28 @@ msgstr "" #. type: Plain text #: text/chapter14.md:654 msgid "" -"Notice that we provide the `id` function as our continuation, meaning that " -"we return the result of type `Name` unchanged." +"Notice that we provide the `id` function as our continuation, meaning we " +"return the result of type `Name` unchanged." msgstr "" "`id`関数を継続として提供していることに注意してください。\n" -"これは型 `Name`の結果を変更せずに返すということを意味しています。" +"つまり型`Name`の結果を変更せずに返しています。" #. type: Plain text #: text/chapter14.md:656 msgid "" -"Finally, we need to update our interpretation function, to interpret the new " +"Finally, we need to update our interpretation function to interpret the new " "action. We previously used the `Writer String` monad to interpret our " -"computations, but that monad does not have the ability to generate new " -"names, so we must switch to something else. The `WriterT` monad transformer " -"can be used with the `State` monad to combine the effects we need. We can " -"define our interpretation monad as a type synonym to keep our type " -"signatures short:" -msgstr "" -"最後に、新しいアクションを解釈するために解釈関数を更新する必要があります。\n" -"以前は計算を解釈するために `Writer String`モナドを使っていましたが、このモナ" -"ドは新しい名前を生成する能力を持っていないので、何か他のものに切り替えなけれ" -"ばなりません。\n" -"`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせる" -"ことができます。\n" -"型注釈を短く保てるように、この解釈モナドを型同義語として定義しておきます。" +"computations, but that monad cannot generate new names, so we must switch to " +"something else. The `WriterT` monad transformer can be used with the `State` " +"monad to combine the effects we need. We can define our interpretation monad " +"as a type synonym to keep our type signatures short:" +msgstr "" +"最後に、新しい動作を解釈させるように解釈関数を更新する必要があります。\n" +"以前は計算を解釈するために`Writer String`モナドを使っていましたが、このモナド" +"は新しい名前を生成できないので、何か他のものに切り替えなければなりません。\n" +"`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせら" +"れます。\n" +"型注釈が短く保たれるよう、この解釈モナドを型同義語として定義できます。" #. type: Fenced code block (haskell) #: text/chapter14.md:657 @@ -13671,18 +13664,16 @@ msgstr "" #: text/chapter14.md:664 msgid "" "Because the `Writer` and `WriterT` monads use the same type class members to " -"abstract their actions, we do not need to change any actions - we only need " -"to replace every reference to `Writer String` with `Interp`. We do, however, " +"abstract their actions, we do not need to change any actions – we only need " +"to replace every reference to `Writer String` with `Interp`. However, we " "need to modify the handler used to run our computation. Instead of just " "`execWriter`, we now need to use `evalState` as well:" msgstr "" -"`Writer`と `WriterT`モナドはそれらのアクションを抽象化するのに同じ型クラスメ" -"ンバを使うので、どのアクションも変更する必要がありません。\n" -"必要なのは、 `Writer String`への参照全てを `Interp`で置き換えることだけで" -"す。\n" -"しかし、これを計算するために使われる制御子を変更しなければいけません。\n" -"こうなると単なる`execWriter`の代わりに、ここでも`evalState`を使う必要がありま" -"す。" +"`Writer`と`WriterT`モナドはそれらの動作を抽象化するのに同じ型クラスの構成要素" +"を使うので、どの動作も変更する必要がありません。\n" +"必要なのは、`Writer String`への参照全てを`Interp`で置き換えることだけです。\n" +"しかし、計算に使われる制御子は変更する必要があります。\n" +"単なる`execWriter`の代わりに、`evalState`も使う必要があります。" #. type: Fenced code block (haskell) #: text/chapter14.md:665 @@ -13733,10 +13724,10 @@ msgstr "" #: text/chapter14.md:683 msgid "" "With that, we can try out our new functionality in PSCi, by generating a " -"unique name inside the `Content` monad, and using it as both the name of an " +"unique name inside the `Content` monad and using it as both the name of an " "element and the target of a hyperlink:" msgstr "" -"以上をもって、この新しい機能をPSCiで試すことができます。\n" +"以上をもって、この新しい機能をPSCiで試せます。\n" "これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンク" "のリンク先の両方として使います。" @@ -13779,14 +13770,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:703 msgid "" -"You can verify that multiple calls to `newName` do in fact result in unique " -"names." +"You can verify that multiple calls to `newName` do, in fact, result in " +"unique names." msgstr "" -"複数回の `newName`の呼び出しの結果が、実際に一意な名前になっていることも確か" -"められます。" +"複数回の`newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめ" +"られます。" #. type: Bullet: ' 1. ' -#: text/chapter14.md:712 +#: text/chapter14.md:711 msgid "" "(Medium) We can simplify the API further by hiding the `Element` type from " "its users. Make these changes in the following steps:" @@ -13795,16 +13786,16 @@ msgstr "" "次の手順に従って、これらの変更を加えてください。" #. type: Bullet: ' - ' -#: text/chapter14.md:712 +#: text/chapter14.md:711 msgid "" "Combine functions like `p` and `img` (with return type `Element`) with the " "`elem` action to create new actions with return type `Content Unit`." msgstr "" -"`p`や `img`のような(返る型が `Element`の)関数を `elem`アクションと結合し" -"て、型 `Content Unit`を返す新しいアクションを作ってください。" +"`p`や`img`のような(返る型が`Element`の)関数を`elem`動作と結合して、型" +"`Content Unit`を返す新しい動作を作ってください。" #. type: Bullet: ' - ' -#: text/chapter14.md:712 +#: text/chapter14.md:711 msgid "" "Change the `render` function to accept an argument of type `Content Unit` " "instead of `Element`." @@ -13812,20 +13803,24 @@ msgstr "" "`Element`の代わりに型`Content Unit`の引数を受け付けるように`render`関数を変更" "してください。" -#. type: Plain text -#: text/chapter14.md:712 -#, no-wrap +#. type: Bullet: ' 1. ' +#: text/chapter14.md:711 msgid "" -" 1. (Medium) Hide the implementation of the `Content` monad by using a `newtype` instead of a type synonym. You should not export the data\n" -" constructor for your `newtype`.\n" -" 1. (Difficult) Modify the `ContentF` type to support a new action\n" +"(Medium) Hide the implementation of the `Content` monad using a `newtype` " +"instead of a type synonym. You should not export the data constructor for " +"your `newtype`." msgstr "" -" 1. (普通)型同義語の代わりに`newtype`を使うことによって`Content`モナドの実装を隠してください。\n" -" `newtype`用のデータ構築子はエクスポートすべきではありません。\n" -" 1. (難しい)`ContentF`型を変更して以下の新しいアクションに対応してください。\n" +"(普通)型同義語の代わりに`newtype`を使って`Content`モナドの実装を隠してくだ" +"さい。\n" +"`newtype`用のデータ構築子はエクスポートすべきではありません。" + +#. type: Bullet: ' 1. ' +#: text/chapter14.md:711 +msgid "(Difficult) Modify the `ContentF` type to support a new action" +msgstr "(難しい)`ContentF`型を変更して以下の新しい動作に対応してください。" #. type: Plain text -#: text/chapter14.md:716 +#: text/chapter14.md:715 #, no-wrap msgid "" " ```haskell\n" @@ -13837,69 +13832,70 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter14.md:718 +#: text/chapter14.md:717 #, no-wrap msgid " which returns a boolean value indicating whether or not the document is being rendered for display on a mobile device.\n" -msgstr " このアクションは、この文書がモバイルデバイス上での表示のためにレンダリングされているかどうかを示す真偽値を返します。\n" +msgstr " この動作は、この文書がモバイルデバイス上での表示のために描画されているかどうかを示す真偽値を返します。\n" #. type: Plain text -#: text/chapter14.md:720 +#: text/chapter14.md:719 #, no-wrap msgid " _Hint_: use the `ask` action and the `ReaderT` monad transformer to interpret this action. Alternatively, you might prefer to use the `RWS` monad.\n" msgstr "" -" *手掛かり*:`ask`アクションと`ReaderT`モナド変換子を使って、このアクションを解釈してください。\n" +" *手掛かり*:`ask`動作と`ReaderT`モナド変換子を使って、この動作を解釈してください。\n" " あるいは、`RWS`モナドを使うほうが好みの人もいるかもしれません。\n" #. type: Plain text -#: text/chapter14.md:724 +#: text/chapter14.md:723 msgid "" "In this chapter, we developed a domain-specific language for creating HTML " -"documents, by incrementally improving a naive implementation using some " +"documents by incrementally improving a naive implementation using some " "standard techniques:" msgstr "" "この章では、幾つかの標準的な技術を使って、素朴な実装を段階的に改善することに" "より、HTML文書を作成するための領域特化言語を開発しました。" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 msgid "" "We used _smart constructors_ to hide the details of our data representation, " -"only permitting the user to create documents which were _correct-by-" +"only permitting the user to create documents that were _correct-by-" "construction_." msgstr "" -"_スマート構築子_ を使ってデータ表現の詳細を隠し、利用者には _構築により正しい" -"_ 文書だけを作ることを許しました。" +"*スマート構築子*を使ってデータ表現の詳細を隠し、利用者には*構築により正しい*" +"文書だけを作ることを許しました。" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 msgid "" -"We used an _user-defined infix binary operator_ to improve the syntax of the " +"We used a _user-defined infix binary operator_ to improve the syntax of the " "language." msgstr "*独自に定義された中置2引数演算子*を使い、言語の構文を改善しました。" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 msgid "" "We used _phantom types_ to encode additional information in the types of our " "data, preventing the user from providing attribute values of the wrong type." msgstr "" -"_幻影型_ を使ってデータの型の中に追加の情報を折り込みました。これにより利用者" -"が誤った型の属性値を与えることを防いでいます。" +"*幻影型*を使ってデータの型の中に追加の情報を折り込みました。\n" +"これにより利用者が誤った型の属性値を与えることを防いでいます。" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 msgid "" "We used the _free monad_ to turn our array representation of a collection of " "content into a monadic representation supporting do notation. We then " -"extended this representation to support a new monadic action, and " -"interpreted the monadic computations using standard monad transformers." +"extended this representation to support a new monadic action and interpreted " +"the monadic computations using standard monad transformers." msgstr "" -"_Freeモナド_ を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変" -"えました。それからこの表現を新しいモナドアクションに対応するよう拡張し、標準" -"モナド変換子を使ってモナドの計算を解釈しました。" +"*Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変" +"えました。\n" +"それからこの表現を新しいモナド動作に対応するよう拡張し、標準的なモナド変換子" +"を使ってモナドの計算を解釈しました。" #. type: Plain text -#: text/chapter14.md:731 +#: text/chapter14.md:730 msgid "" "These techniques all leverage PureScript's module and type systems, either " "to prevent the user from making mistakes or to improve the syntax of the " @@ -13909,16 +13905,17 @@ msgstr "" "したりするために、PureScriptのモジュールと型システムを活用しています。" #. type: Plain text -#: text/chapter14.md:732 +#: text/chapter14.md:731 msgid "" -"The implementation of domain-specific languages in functional programming " -"languages is an area of active research, but hopefully this provides a " -"useful introduction some simple techniques, and illustrates the power of " -"working in a language with expressive types." +"Implementing domain-specific languages in functional programming languages " +"is an area of active research. Still, hopefully, this provides a useful " +"introduction to some simple techniques and illustrates the power of working " +"in a language with expressive types." msgstr "" "関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野で" -"すが、幾つかの簡単な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言" -"語で作業することの威力を示すことができていれば幸いです。" +"す。\n" +"それでも、幾つかの単純な技法に対して役に立つ導入を提供し、表現力豊かな型を持" +"つ言語で作業することの威力を示すことができていれば幸いです。" #. type: Title # #: text/chapter2.md:1 @@ -13935,10 +13932,10 @@ msgid "" "youtube.com/watch?v=GPjPwb6d-70) helpful if that better suits your learning " "style." msgstr "" -"この章では実際のPureScriptの開発環境を立ち上げ、幾つかの演習を解き、この本で" -"提供されているテストを使って答えを確認します。\n" -"もし映像を見る学習の仕方が合っているようでしたら、[この章を通しで進めるビデ" -"オ](https://www.youtube.com/watch?v=GPjPwb6d-70)が役に立つでしょう。" +"本章では実際のPureScriptの開発環境を立ち上げ、幾つかの演習を解き、本書で提供" +"されているテストを使って答えを確認します。\n" +"もし映像を見る学習の仕方が合っているようでしたら、[本章を通しで進めるビデオ]" +"(https://www.youtube.com/watch?v=GPjPwb6d-70)が役に立つでしょう。" #. type: Title ## #: text/chapter2.md:7 @@ -14009,8 +14006,8 @@ msgid "" "Now that you've installed the necessary development tools, clone this book's " "repo." msgstr "" -"ここまでで必要な開発ツールをインストールできているので、この本のリポジトリを" -"クローンしてください。" +"ここまでで必要な開発ツールをインストールできているので、本書のリポジトリをク" +"ローンしてください。" #. type: Fenced code block (sh) #: text/chapter2.md:23 @@ -14024,19 +14021,21 @@ msgid "" "The book repo contains PureScript example code and unit tests for the " "exercises that accompany each chapter. There's some initial setup required " "to reset the exercise solutions so they are ready to be solved by you. Use " -"the `resetSolutions.sh` script to simplify this process. While you're at it, " -"you should also strip out all the anchor comments with the `removeAnchors." -"sh` script (these anchors are used for copying code snippets into the book's " +"the `resetSolutions.sh` script to simplify this process. While at it, you " +"should also strip out all the anchor comments with the `removeAnchors.sh` " +"script (these anchors are used for copying code snippets into the book's " "rendered markdown, and you probably don't need this clutter in your local " "repo):" msgstr "" -"本のリポジトリにはPureScriptのコード例とそれぞれの章に付属する演習のための単" -"体テストが含まれます。演習の解法を白紙に戻すために必要な初期設定があり、この" -"設定をすることで解く準備ができます。この工程は`resetSolutions.sh`スクリプトを" -"使えば簡単にできます。また`removeAnchors.sh`スクリプトで全てのアンカーコメン" -"トを取り除いておくのもよいでしょう(これらのアンカーはコードスニペットを本の" -"変換後のMarkdownにコピーするために使われており、自分のローカルリポジトリでは" -"このアンカーで散らかっていないほうがよいでしょう)。" +"本書のリポジトリにはPureScriptのコード例と各章に付属する演習のための単体テス" +"トが含まれます。\n" +"演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準" +"備ができます。\n" +"この工程は`resetSolutions.sh`スクリプトを使えば簡単にできます。\n" +"また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくと良" +"いでしょう(これらのアンカーはコード片を本書のMarkdownから書き出した媒体に複" +"製するために使われており、自分のローカルリポジトリではこのアンカーで散らかっ" +"ていないほうが良いでしょう)。" #. type: Fenced code block (sh) #: text/chapter2.md:29 @@ -14095,16 +14094,16 @@ msgstr "" msgid "" "Note that the `answer` function (found in `src/Euler.purs`) has been " "modified to find the multiples of 3 and 5 below any integer. The test suite " -"(found in `test/Main.purs`) for this `answer` function is more comprehensive " -"than the test in the earlier getting-started guide. Don't worry about " -"understanding how this test framework code works while reading these early " -"chapters." -msgstr "" -"なお、`answer`関数(`src/Euler.purs`にあります)は、任意の整数以下の3と5の倍" -"数を見付けるように変更されています。\n" -"この`answer`関数のためのテストスート(`test/Main.purs`にあります)ははじめの" -"手引きの冒頭にあるテストよりも網羅的です。\n" -"はじめの章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い" +"(located in `test/Main.purs`) for this `answer` function is more " +"comprehensive than the test in the earlier getting-started guide. Don't " +"worry about understanding how this test framework code works while reading " +"these early chapters." +msgstr "" +"なお、(`src/Euler.purs`にある)`answer`関数は任意の整数以下の3と5の倍数を見" +"付けるように変更されています。\n" +"(`test/Main.purs`にある)この`answer`関数のためのテストスートははじめの手引" +"きの冒頭にあるテストよりも網羅的です。\n" +"前の方の章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い" "詰めなくて大丈夫です。" #. type: Plain text @@ -14114,16 +14113,16 @@ msgid "" "solutions in the `Test.MySolutions` module (`test/MySolutions.purs`), you " "can check your work against the provided test suite." msgstr "" -"本の残りの部分には多くの演習が含まれます。\n" +"本書の残りの部分には多くの演習が含まれます。\n" "`Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、" "提供されているテストスートを使って確認できます。" #. type: Plain text #: text/chapter2.md:59 msgid "" -"Let's work through this next exercise together in test-driven-development " +"Let's work through this next exercise together in a test-driven-development " "style." -msgstr "テスト駆動開発のスタイルでこの次の演習を一緒に進めてみましょう。" +msgstr "テスト駆動開発でこの次の演習を一緒に進めてみましょう。" #. type: Title ## #: text/chapter2.md:60 @@ -14151,7 +14150,7 @@ msgstr "解法" #: text/chapter2.md:67 msgid "" "We'll start by enabling the tests for this exercise. Move the start of the " -"block-comment down a few lines as shown below. Block comments start with `{-" +"block-comment down a few lines, as shown below. Block comments start with `{-" "` and end with `-}`:" msgstr "" "この演習のテストを有効にするところから始めます。\n" @@ -14200,11 +14199,11 @@ msgstr "" #. type: Plain text #: text/chapter2.md:86 msgid "" -"Let's first take a look at what happens with a faulty version of this " -"function. Add the following code to `test/MySolutions.purs`:" +"Let's first look at what happens with a faulty version of this function. Add " +"the following code to `test/MySolutions.purs`:" msgstr "" -"まずは、この関数が欠陥のあるバージョンになっているときに何が起こるのか見てみ" -"ましょう。以下のコードを`test/MySolutions.purs`に追加してください。" +"まずはこの関数に欠陥があるときに何が起こるのか見てみましょう。\n" +"以下のコードを`test/MySolutions.purs`に追加してください。" #. type: Fenced code block (hs) #: text/chapter2.md:87 @@ -14332,42 +14331,41 @@ msgstr "" #: text/chapter2.md:134 msgid "" "There will be many more exercises in the chapters ahead, and working through " -"those really helps with learning the material. If you're stumped by any of " -"the exercises, please reach out to any of the community resources listed in " -"the [Getting Help](https://book.purescript.org/chapter1.html#getting-help) " -"section of this book, or even file an issue in this [book's repo](https://" -"github.com/purescript-contrib/purescript-book/issues). This reader feedback " -"on which exercises could be made more approachable helps us improve the book." -msgstr "" -"この先の章にはもっと沢山の演習があり、それらに取り組むうちに学習の助けになっ" -"ているでしょう。\n" -"演習のどこかでお手上げになったら、この本の[困ったときは](chapter1.ja." -"md#getting-help)の節に挙げられているコミュニティの資料のどれかを見てみたり、" -"この[本のリポジトリ](https://github.com/purescript-contrib/purescript-book/" -"issues)にイシューを報告したりできます。\n" -"こうした演習の敷居を下げることに繋がる読者のフィードバックが、本の向上の助け" -"になっています。" +"those helps with learning the material. If any of the exercises stumps you, " +"please reach out to any of the community resources listed in the [Getting " +"Help](https://book.purescript.org/chapter1.html#getting-help) section of " +"this book, or even file an issue in this [book's repo](https://github.com/" +"purescript-contrib/purescript-book/issues). This reader feedback on which " +"exercises could be made more approachable helps us improve the book." +msgstr "" +"この先の章にはもっと沢山の演習があり、それらに取り組むうちに内容を学ぶ助けに" +"なっているでしょう。\n" +"演習のどこかでお手上げになったら、本書の[困ったときは](chapter1.ja." +"md#getting-help)の節に挙げられているコミュニティの資料のどれかに手を伸ばした" +"り、[本書のリポジトリ](https://github.com/purescript-contrib/purescript-book/" +"issues)でイシューを報告したりできます。\n" +"こうした演習の敷居を下げることに繋がる読者のフィードバックのお陰で本書が改善" +"されています。" #. type: Plain text #: text/chapter2.md:136 msgid "" "Once you solve all the exercises in a chapter, you may compare your answers " -"against those in the `no-peeking/Solutions.purs`. No peeking please without " -"putting in an honest effort to solve these yourself though. And even if you " +"against those in the `no-peeking/Solutions.purs`. No peeking, please, " +"without putting in an honest effort to solve these yourself. And even if you " "are stuck, try asking a community member for help first, as we would prefer " "to give you a small hint rather than spoil the exercise. If you found a more " -"elegant solution (that still only requires knowledge of covered content), " +"elegant solution (that only requires knowledge of the covered content), " "please send us a PR." msgstr "" "章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べ" "られます。\n" -"ただしカンニングしてはだめで、これらの演習を誠実に自力で解く労力を払わないこ" -"とがないようにしてください。\n" +"カンニングはせず、演習を誠実に自力で解く労力を割いてください。\n" "そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるよう" "にしてください。\n" -"演習のネタバレをするよりも、小さな手掛かりをあげたいからです。\n" -"もっとエレガントな解法(とはいえ本の内容で押さえられている知識のみを必要とす" -"るもの)を見つけたときはPRを送ってください。" +"ネタバレをするよりも小さな手掛かりをあげたいからです。\n" +"もっとエレガントな解法(とはいえ本書で押さえられている知識のみで済むもの)を" +"見つけたときはPRを送ってください。" #. type: Plain text #: text/chapter2.md:137 @@ -14441,43 +14439,57 @@ msgid "Here, we import several modules:" msgstr "ここでは、幾つかのモジュールをインポートします。" #. type: Bullet: '- ' -#: text/chapter3.md:24 +#: text/chapter3.md:25 +msgid "" +"The `Prelude` module, which contains a small set of standard definitions and " +"functions. It re-exports many foundational modules from the `purescript-" +"prelude` library." +msgstr "" +"`Prelude`モジュールには標準的な定義と関数の小さな集合が含まれます。\n" +"`purescript-prelude`ライブラリから多くの基礎的なモジュールを再エクスポートし" +"ているのです。" + +#. type: Bullet: '- ' +#: text/chapter3.md:25 msgid "The `Control.Plus` module, which defines the `empty` value." msgstr "`Control.Plus`モジュールには`empty`値が定義されています。" #. type: Bullet: '- ' -#: text/chapter3.md:24 +#: text/chapter3.md:25 msgid "" -"The `Data.List` module, which is provided by the `lists` package which can " -"be installed using Spago. It contains a few functions which we will need for " +"The `Data.List` module, provided by the `lists` package, which can be " +"installed using Spago. It contains a few functions that we will need for " "working with linked lists." msgstr "" -"`Data.List`モジュールは`lists`パッケージで提供されておりSpagoを使ってインス" -"トールできます。\n" -"連結リストを使うために必要な幾つかの関数が含まれています。" +"`Data.List`モジュールは`lists`パッケージで提供されています。\n" +"またこのパッケージはSpagoを使ってインストールできます。\n" +"モジュールには連結リストを使うために必要な幾つかの関数が含まれています。" #. type: Bullet: '- ' -#: text/chapter3.md:24 +#: text/chapter3.md:25 msgid "" "The `Data.Maybe` module, which defines data types and functions for working " "with optional values." msgstr "" -"`Data.Maybe`モジュールは、オプショナルな値を扱うためのデータ型と関数を定義し" -"ています。" +"`Data.Maybe`モジュールは、省略可能な値を扱うためのデータ型と関数を定義してい" +"ます。" #. type: Plain text -#: text/chapter3.md:26 +#: text/chapter3.md:27 msgid "" "Notice that the imports for these modules are listed explicitly in " -"parentheses. This is generally a good practice, as it helps to avoid " -"conflicting imports." -msgstr "" -"このモジュールのインポート内容が括弧内で明示的に列挙されていることに注目して" -"ください。明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に" -"良い習慣です。" +"parentheses (except for `Prelude`, which is typically imported as an open " +"import). This is generally a good practice, as it helps to avoid conflicting " +"imports." +msgstr "" +"これらのモジュールのインポート内容が括弧内で明示的に列挙されていることに注目" +"してください(`Prelude`は除きます。これは一括インポートされるのが普通で" +"す)。\n" +"明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣で" +"す。" #. type: Plain text -#: text/chapter3.md:28 +#: text/chapter3.md:29 msgid "" "Assuming you have cloned the book's source code repository, the project for " "this chapter can be built using Spago, with the following commands:" @@ -14486,7 +14498,7 @@ msgstr "" "コマンドでSpagoを使用して構築できます。" #. type: Fenced code block (text) -#: text/chapter3.md:29 +#: text/chapter3.md:30 #, no-wrap msgid "" "$ cd chapter3\n" @@ -14496,29 +14508,29 @@ msgstr "" "$ spago build\n" #. type: Title ## -#: text/chapter3.md:34 +#: text/chapter3.md:35 #, no-wrap msgid "Simple Types" msgstr "単純な型" #. type: Plain text -#: text/chapter3.md:37 +#: text/chapter3.md:38 msgid "" -"PureScript defines three built-in types which correspond to JavaScript's " -"primitive types: numbers, strings and booleans. These are defined in the " +"PureScript defines three built-in types corresponding to JavaScript's " +"primitive types: numbers, strings, and booleans. These are defined in the " "`Prim` module, which is implicitly imported by every module. They are called " "`Number`, `String`, and `Boolean`, respectively, and you can see them in " "PSCi by using the `:type` command to print the types of some simple values:" msgstr "" -"JavaScriptのプリミティブ型に対応する組み込みデータ型として、PureScriptでは数" -"値型と文字列型、真偽型の3つが定義されています。\n" +"JavaScriptの原始型に対応する組み込みデータ型として、PureScriptでは数値型と文" +"字列型、真偽型の3つが定義されています。\n" "これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポート" "されます。\n" -"これらはそれぞれ `Number`、 `String`、 `Boolean`と呼ばれており、PSCiで`:type`" -"コマンドを使うと簡単な値の型を表示させて確認できます。" +"それぞれ`Number`、`String`、`Boolean`と呼ばれており、PSCiで簡単な値の型を表示" +"するのに`:type`コマンドを使うと確認できます。" #. type: Fenced code block (text) -#: text/chapter3.md:38 +#: text/chapter3.md:39 #, no-wrap msgid "" "$ spago repl\n" @@ -14544,16 +14556,16 @@ msgstr "" "Boolean\n" #. type: Plain text -#: text/chapter3.md:52 +#: text/chapter3.md:53 msgid "" -"PureScript defines some other built-in types: integers, characters, arrays, " +"PureScript defines other built-in types: integers, characters, arrays, " "records, and functions." msgstr "" "PureScriptには他にも、整数、文字、配列、レコード、関数といった組み込み型が定" "義されています。" #. type: Plain text -#: text/chapter3.md:54 +#: text/chapter3.md:55 msgid "" "Integers are differentiated from floating point values of type `Number` by " "the lack of a decimal point:" @@ -14561,7 +14573,7 @@ msgstr "" "小数点以下を省くと整数になり、型 `Number`の浮動小数点数の値と区別されます。" #. type: Fenced code block (text) -#: text/chapter3.md:55 +#: text/chapter3.md:56 #, no-wrap msgid "" "> :type 1\n" @@ -14571,7 +14583,7 @@ msgstr "" "Int\n" #. type: Plain text -#: text/chapter3.md:61 +#: text/chapter3.md:62 msgid "" "Character literals are wrapped in single quotes, unlike string literals " "which use double quotes:" @@ -14579,7 +14591,7 @@ msgstr "" "二重引用符を使用する文字列直値とは異なり、文字直値は一重引用符で囲みます。" #. type: Fenced code block (text) -#: text/chapter3.md:62 +#: text/chapter3.md:63 #, no-wrap msgid "" "> :type 'a'\n" @@ -14589,7 +14601,7 @@ msgstr "" "Char\n" #. type: Plain text -#: text/chapter3.md:68 +#: text/chapter3.md:69 msgid "" "Arrays correspond to JavaScript arrays, but unlike in JavaScript, all " "elements of a PureScript array must have the same type:" @@ -14598,7 +14610,7 @@ msgstr "" "PureScriptの配列の全ての要素は同じ型を持つ必要があります。" #. type: Fenced code block (text) -#: text/chapter3.md:69 +#: text/chapter3.md:70 #, no-wrap msgid "" "> :type [1, 2, 3]\n" @@ -14620,18 +14632,16 @@ msgstr "" "Could not match type Int with type Boolean.\n" #. type: Plain text -#: text/chapter3.md:81 +#: text/chapter3.md:82 msgid "" -"The error in the last example is an error from the type checker, which " -"unsuccessfully attempted to _unify_ (i.e. make equal) the types of the two " -"elements." +"The last example shows an error from the type checker, which failed to " +"_unify_ (i.e., make equal) the types of the two elements." msgstr "" -"最後の例で起きているエラーは型検証器によって報告されたもので、配列の2つの要素" -"の型を*単一化*(Unification、等価にする意)しようとして失敗したことを示してい" -"ます。" +"最後の例は型検証器によるエラーを示しています。\n" +"配列の2つの要素の型を*単一化*(つまり等価にする意)するのに失敗したのです。" #. type: Plain text -#: text/chapter3.md:83 +#: text/chapter3.md:84 msgid "" "Records correspond to JavaScript's objects, and record literals have the " "same syntax as JavaScript's object literals:" @@ -14640,7 +14650,7 @@ msgstr "" "オブジェクト直値と同じ構文になっています。" #. type: Fenced code block (text) -#: text/chapter3.md:84 +#: text/chapter3.md:85 #, no-wrap msgid "" "> author = { name: \"Phil\", interests: [\"Functional Programming\", \"JavaScript\"] }\n" @@ -14658,18 +14668,19 @@ msgstr "" "}\n" #. type: Plain text -#: text/chapter3.md:94 +#: text/chapter3.md:95 msgid "" -"This type indicates that the specified object has two _fields_, a `name` " -"field which has type `String`, and an `interests` field, which has type " -"`Array String`, i.e. an array of `String`s." +"This type indicates that the specified object has two _fields_: a `name` " +"field with the type `String` and an `interests` field with the type `Array " +"String`, i.e., an array of `String`s." msgstr "" -"この型が示しているのは、指定されたオブジェクトは、 `String`型のフィールド " -"`name` と `Array String`つまり `String`の配列の型のフィールド `interests` と" -"いう2つの _フィールド_ (field) を持っているということです。" +"この型が示しているのは指定されたオブジェクトが2つの*フィールド*を持っていると" +"いうことです。\n" +"それぞれ`String`型のフィールド`name`と`Array String`型のフィールド`interests`" +"で、後者は`String`の配列ということです。" #. type: Plain text -#: text/chapter3.md:96 +#: text/chapter3.md:97 msgid "" "Fields of records can be accessed using a dot, followed by the label of the " "field to access:" @@ -14678,7 +14689,7 @@ msgstr "" "できます。" #. type: Fenced code block (text) -#: text/chapter3.md:97 +#: text/chapter3.md:98 #, no-wrap msgid "" "> author.name\n" @@ -14694,84 +14705,61 @@ msgstr "" "[\"Functional Programming\",\"JavaScript\"]\n" #. type: Plain text -#: text/chapter3.md:106 -msgid "" -"PureScript's functions correspond to JavaScript's functions. The PureScript " -"standard libraries provide plenty of examples of functions, and we will see " -"more in this chapter:" -msgstr "" -"PureScriptの関数はJavaScriptの関数に対応しています。PureScriptの標準ライブラ" -"リは多くの関数の例を提供しており、この章ではそれらをもう少し詳しく見ていきま" -"す。" - -#. type: Fenced code block (text) #: text/chapter3.md:107 -#, no-wrap msgid "" -"> import Prelude\n" -"> :type flip\n" -"forall a b c. (a -> b -> c) -> b -> a -> c\n" -"\n" -"> :type const\n" -"forall a b. a -> b -> a\n" +"PureScript's functions correspond to JavaScript's functions. Functions can " +"be defined at the top-level of a file by specifying arguments before the " +"equals sign:" msgstr "" -"> import Prelude\n" -"> :type flip\n" -"forall a b c. (a -> b -> c) -> b -> a -> c\n" -"\n" -"> :type const\n" -"forall a b. a -> b -> a\n" - -#. type: Plain text -#: text/chapter3.md:117 -msgid "" -"Functions can be defined at the top-level of a file by specifying arguments " -"before the equals sign:" -msgstr "" -"ファイルのトップレベルでは、等号の直前に引数を指定することで関数を定義できま" -"す。" +"PureScriptの関数はJavaScriptの関数に対応します。\n" +"関数はファイルの最上位で定義でき、等号の前に引数を指定します。" #. type: Fenced code block (haskell) -#: text/chapter3.md:118 +#: text/chapter3.md:108 #, no-wrap msgid "" +"import Prelude -- bring the (+) operator into scope\n" +"\n" "add :: Int -> Int -> Int\n" "add x y = x + y\n" msgstr "" +"import Prelude -- (+) 演算子をスコープに持ち込みます\n" +"\n" "add :: Int -> Int -> Int\n" "add x y = x + y\n" #. type: Plain text -#: text/chapter3.md:124 +#: text/chapter3.md:116 msgid "" -"Alternatively, functions can be defined inline, by using a backslash " -"character followed by a space-delimited list of argument names. To enter a " -"multi-line declaration in PSCi, we can enter \"paste mode\" by using the `:" -"paste` command. In this mode, declarations are terminated using the _Control-" -"D_ key sequence:" +"Alternatively, functions can be defined inline using a backslash character " +"followed by a space-delimited list of argument names. To enter a multi-line " +"declaration in PSCi, we can enter \"paste mode\" using the `:paste` command. " +"In this mode, declarations are terminated using the _Control-D_ key sequence:" msgstr "" -"バックスラッシュに続けて空白文字で区切られた引数名のリストを書くことで、関数" -"をインラインでも定義できます。\n" -"PSCiで複数行の宣言を入力するには、 `:paste`コマンドを使用して「貼り付けモー" +"代えて、バックスラッシュ文字に続けて空白文字で区切られた引数名のリストを書く" +"ことで、関数をインラインでも定義できます。\n" +"PSCiで複数行の宣言を入力するには、`:paste`コマンドを使用して「貼り付けモー" "ド」に入ります。\n" -"このモードでは、*Control-D*キーシーケンスを使用して宣言を終了します。" +"このモードでは、*Control-D*キーシーケンスを使って宣言を終了します。" #. type: Fenced code block (text) -#: text/chapter3.md:125 +#: text/chapter3.md:117 #, no-wrap msgid "" +"> import Prelude\n" "> :paste\n" "… add :: Int -> Int -> Int\n" "… add = \\x y -> x + y\n" "… ^D\n" msgstr "" +"> import Prelude\n" "> :paste\n" "… add :: Int -> Int -> Int\n" "… add = \\x y -> x + y\n" "… ^D\n" #. type: Plain text -#: text/chapter3.md:133 +#: text/chapter3.md:126 msgid "" "Having defined this function in PSCi, we can _apply_ it to its arguments by " "separating the two arguments from the function name by whitespace:" @@ -14780,7 +14768,7 @@ msgstr "" "て書くことで、関数をこれらの引数に*適用* (apply) できます。" #. type: Fenced code block (text) -#: text/chapter3.md:134 +#: text/chapter3.md:127 #, no-wrap msgid "" "> add 10 20\n" @@ -14790,117 +14778,13 @@ msgstr "" "30\n" #. type: Title ## -#: text/chapter3.md:139 -#, no-wrap -msgid "Quantified Types" -msgstr "量化された型" - -#. type: Plain text -#: text/chapter3.md:142 -msgid "" -"In the previous section, we saw the types of some functions defined in the " -"Prelude. For example, the `flip` function had the following type:" -msgstr "" -"前の節ではPreludeで定義された関数の型を幾つか見てきました。\n" -"例えば`flip`関数は次のような型を持っていました。" - -#. type: Fenced code block (text) -#: text/chapter3.md:143 -#, no-wrap -msgid "" -"> :type flip\n" -"forall a b c. (a -> b -> c) -> b -> a -> c\n" -msgstr "" -"> :type flip\n" -"forall a b c. (a -> b -> c) -> b -> a -> c\n" - -#. type: Plain text -#: text/chapter3.md:149 -msgid "" -"The keyword `forall` here indicates that `flip` has a _universally " -"quantified type_. It means that we can substitute any types for `a`, `b` and " -"`c`, and `flip` will work with those types." -msgstr "" -"この `forall`キーワードは、 `flip`が _全称量化された型_ (universally " -"quantified type) を持っていることを示しています。これは、 `a`や `b`、 `c`をど" -"の型に置き換えても、 `flip`はその型でうまく動作するという意味です。" - -#. type: Plain text -#: text/chapter3.md:151 -msgid "" -"For example, we might choose the type `a` to be `Int`, `b` to be `String` " -"and `c` to be `String`. In that case we could _specialize_ the type of " -"`flip` to" -msgstr "" -"例えば、 `a`を `Int`、 `b`を `String`、 `c`を `String`というように選んでみた" -"とします。この場合、 `flip`の型を次のように*特殊化* (specialize) できます。" - -#. type: Fenced code block (text) -#: text/chapter3.md:152 -#, no-wrap -msgid "(Int -> String -> String) -> String -> Int -> String\n" -msgstr "(Int -> String -> String) -> String -> Int -> String\n" - -#. type: Plain text -#: text/chapter3.md:157 -msgid "" -"We don't have to indicate in code that we want to specialize a quantified " -"type - it happens automatically. For example, we can just use `flip` as if " -"it had this type already:" -msgstr "" -"量化された型を特殊化したいということをコードで示す必要はありません。\n" -"特殊化は自動的に行われます。\n" -"例えば次のように単に`flip`を使用できます。\n" -"あたかも既にその型の`flip`を持っていたかのようです。" - -#. type: Fenced code block (text) -#: text/chapter3.md:158 -#, no-wrap -msgid "" -"> flip (\\n s -> show n <> s) \"Ten\" 10\n" -"\n" -"\"10Ten\"\n" -msgstr "" -"> flip (\\n s -> show n <> s) \"Ten\" 10\n" -"\n" -"\"10Ten\"\n" - -#. type: Plain text -#: text/chapter3.md:165 -msgid "" -"While we can choose any types for `a`, `b` and `c`, we have to be " -"consistent. The type of the function we passed to `flip` had to be " -"consistent with the types of the other arguments. That is why we passed the " -"string `\"Ten\"` as the second argument, and the number `10` as the third. " -"It would not work if the arguments were reversed:" -msgstr "" -"`a`、 `b`、 `c`の型はどんな型でも選ぶことができるといっても、型の不整合は生じ" -"ないようにしなければなりません。\n" -"`flip`に渡す関数の型は、他の引数の型と整合性がなくてはなりません。\n" -"第2引数として文字列 `\"Ten\"`、第3引数として数 `10`を渡したのはそれが理由で" -"す。\n" -"もし引数が逆になっているとうまくいかないでしょう。" - -#. type: Fenced code block (text) -#: text/chapter3.md:166 -#, no-wrap -msgid "" -"> flip (\\n s -> show n <> s) 10 \"Ten\"\n" -"\n" -"Could not match type Int with type String\n" -msgstr "" -"> flip (\\n s -> show n <> s) 10 \"Ten\"\n" -"\n" -"Could not match type Int with type String\n" - -#. type: Title ## -#: text/chapter3.md:172 +#: text/chapter3.md:132 #, no-wrap msgid "Notes On Indentation" msgstr "字下げについての注意" #. type: Plain text -#: text/chapter3.md:175 +#: text/chapter3.md:135 msgid "" "PureScript code is _indentation-sensitive_, just like Haskell, but unlike " "JavaScript. This means that the whitespace in your code is not meaningless, " @@ -14913,21 +14797,21 @@ msgstr "" "ドのまとまりを示すために使われているということです。" #. type: Plain text -#: text/chapter3.md:177 +#: text/chapter3.md:137 msgid "" -"If a declaration spans multiple lines, then any lines except the first must " -"be indented past the indentation level of the first line." +"If a declaration spans multiple lines, any lines except the first must be " +"indented past the indentation level of the first line." msgstr "" -"宣言が複数行にわたる場合は、最初の行以外は最初の行の字下げより深くしなければ" -"なりません。" +"宣言が複数行にわたる場合、最初の行以外は最初の行の字下げより深くしなければな" +"りません。" #. type: Plain text -#: text/chapter3.md:179 -msgid "Therefore, the following is valid PureScript code:" +#: text/chapter3.md:139 +msgid "Therefore, the following is a valid PureScript code:" msgstr "したがって、次は正しいPureScriptコードです。" #. type: Fenced code block (haskell) -#: text/chapter3.md:180 +#: text/chapter3.md:140 #, no-wrap msgid "" "add x y z = x +\n" @@ -14937,12 +14821,12 @@ msgstr "" " y + z\n" #. type: Plain text -#: text/chapter3.md:186 -msgid "But this is not valid code:" +#: text/chapter3.md:146 +msgid "But this is not a valid code:" msgstr "しかし、次は正しいコードではありません。" #. type: Fenced code block (haskell) -#: text/chapter3.md:187 +#: text/chapter3.md:147 #, no-wrap msgid "" "add x y z = x +\n" @@ -14952,16 +14836,16 @@ msgstr "" "y + z\n" #. type: Plain text -#: text/chapter3.md:193 +#: text/chapter3.md:153 msgid "" "In the second case, the PureScript compiler will try to parse _two_ " "declarations, one for each line." msgstr "" -"後者では、PureScriptコンパイラはそれぞれの行ごとに1つ、つまり*2つ*の宣言であ" -"ると構文解析します。" +"後者では、PureScriptコンパイラはそれぞれの行毎に1つ、つまり*2つ*の宣言である" +"と構文解析します。" #. type: Plain text -#: text/chapter3.md:195 +#: text/chapter3.md:155 msgid "" "Generally, any declarations defined in the same block should be indented at " "the same level. For example, in PSCi, declarations in a let statement must " @@ -14973,7 +14857,7 @@ msgstr "" "次は正しいコードです。" #. type: Fenced code block (text) -#: text/chapter3.md:196 +#: text/chapter3.md:156 #, no-wrap msgid "" "> :paste\n" @@ -14987,12 +14871,12 @@ msgstr "" "… ^D\n" #. type: Plain text -#: text/chapter3.md:204 -msgid "but this is not:" +#: text/chapter3.md:164 +msgid "But this is not:" msgstr "しかし、これは正しくありません。" #. type: Fenced code block (text) -#: text/chapter3.md:205 +#: text/chapter3.md:165 #, no-wrap msgid "" "> :paste\n" @@ -15006,55 +14890,74 @@ msgstr "" "… ^D\n" #. type: Plain text -#: text/chapter3.md:213 +#: text/chapter3.md:173 msgid "" -"Certain PureScript keywords (such as `where`, `of` and `let`) introduce a " -"new block of code, in which declarations must be further-indented:" +"Certain PureScript keywords introduce a new block of code, in which " +"declarations must be further-indented:" msgstr "" -"PureScriptの幾つかの予約語(例えば `where`や `of`、 `let`)は新たなコードのま" -"とまりを導入しますが、そのコードのまとまり内の宣言はそれより深く字下げされて" -"いる必要があります。" +"PureScriptの幾つかのキーワードは新たなコードのまとまりを導入します。\n" +"その中での宣言はそれより深く字下げされなければなりません。" #. type: Fenced code block (haskell) -#: text/chapter3.md:214 +#: text/chapter3.md:174 #, no-wrap msgid "" -"example x y z = foo + bar\n" -" where\n" +"example x y z =\n" +" let\n" " foo = x * y\n" " bar = y * z\n" +" in\n" +" foo + bar\n" msgstr "" -"example x y z = foo + bar\n" -" where\n" +"example x y z =\n" +" let\n" " foo = x * y\n" " bar = y * z\n" +" in\n" +" foo + bar\n" #. type: Plain text -#: text/chapter3.md:222 +#: text/chapter3.md:184 +msgid "This doesn't compile:" +msgstr "これはコンパイルされません。" + +#. type: Fenced code block (haskell) +#: text/chapter3.md:185 +#, no-wrap msgid "" -"Note how the declarations for `foo` and `bar` are indented past the " -"declaration of `example`." +"example x y z =\n" +" let\n" +" foo = x * y\n" +" bar = y * z\n" +" in\n" +" foo + bar\n" msgstr "" -"ここで `foo`や `bar`の宣言は `example`の宣言より深く字下げされていることに注" -"意してください。" +"example x y z =\n" +" let\n" +" foo = x * y\n" +" bar = y * z\n" +" in\n" +" foo + bar\n" #. type: Plain text -#: text/chapter3.md:224 +#: text/chapter3.md:195 msgid "" -"The only exception to this rule is the `where` keyword in the initial " -"`module` declaration at the top of a source file." +"If you want to learn more (or encounter any problems), see the [Syntax]" +"(https://github.com/purescript/documentation/blob/master/language/Syntax." +"md#syntax) documentation." msgstr "" -"ただし、ソースファイルの先頭、最初の `module`宣言における予約語 `where`だけ" -"は、この規則の唯一の例外になっています。" +"より多くを学びたければ(あるいは何か問題に遭遇したら)[構文](https://github." +"com/purescript/documentation/blob/master/language/Syntax.md#syntax)のドキュメ" +"ントを参照してください。" #. type: Title ## -#: text/chapter3.md:225 +#: text/chapter3.md:196 #, no-wrap msgid "Defining Our Types" msgstr "独自の型の定義" #. type: Plain text -#: text/chapter3.md:228 +#: text/chapter3.md:199 msgid "" "A good first step when tackling a new problem in PureScript is to write out " "type definitions for any values you will be working with. First, let's " @@ -15065,95 +14968,95 @@ msgstr "" "を定義してみます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:229 +#: text/chapter3.md:200 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}}\n" #. type: Plain text -#: text/chapter3.md:234 +#: text/chapter3.md:205 msgid "" -"This defines a _type synonym_ called `Entry` - the type `Entry` is " +"This defines a _type synonym_ called `Entry` – the type `Entry` is " "equivalent to the type on the right of the equals symbol: a record type with " -"three fields - `firstName`, `lastName` and `address`. The two name fields " -"will have type `String`, and the `address` field will have type `Address`, " -"defined as follows:" +"three fields – `firstName`, `lastName`, and `address`. The two name fields " +"will have the type `String`, and the `address` field will have the type " +"`Address`, defined as follows:" msgstr "" -"これは `Entry`という*型同義語*(type synonym、型シノニム)を定義していま" +"これは`Entry`という*型同義語*を定義しています。\n" +"型`Entry`は等号の右辺と等価ということです。\n" +"レコードの型は`firstName`、`lastName`、`phone`という3つのフィールドからなりま" "す。\n" -"型 `Entry`は等号の右辺と同じ型ということです。\n" -"レコードの型は何れも文字列である `firstName`、 `lastName`、 `phone`という3つ" -"のフィールドからなります。\n" -"前者の2つのフィールドは型 `String`を持ち、 `address`は以下のように定義された" -"型 `Address`を持っています。" +"2つの名前のフィールドは型`String`を持ち、`address`は以下で定義された型" +"`Address`を持ちます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:235 +#: text/chapter3.md:206 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Address}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Address}}\n" #. type: Plain text -#: text/chapter3.md:240 +#: text/chapter3.md:211 msgid "Note that records can contain other records." msgstr "なお、レコードには他のレコードを含めることができます。" #. type: Plain text -#: text/chapter3.md:242 +#: text/chapter3.md:213 msgid "" -"Now let's define a third type synonym, for our address book data structure, " +"Now let's define a third type synonym for our address book data structure, " "which will be represented simply as a linked list of entries:" msgstr "" -"それでは、3つめの型同義語も定義してみましょう。住所録のデータ構造としては、単" -"に項目の連結リストとして格納することにします。" +"それでは、住所録のデータ構造として3つめの型同義語も定義してみましょう。\n" +"単に項目の連結リストとして表すことにします。" #. type: Fenced code block (haskell) -#: text/chapter3.md:243 +#: text/chapter3.md:214 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}}\n" #. type: Plain text -#: text/chapter3.md:248 +#: text/chapter3.md:219 msgid "" -"Note that `List Entry` is not the same as `Array Entry`, which represents an " +"Note that `List Entry` differs from `Array Entry`, which represents an " "_array_ of entries." msgstr "" -"`List Entry`は `Array Entry`とは同じではないということに注意してください。 " -"`Array Entry`は住所録の項目の _配列_ を意味しています。" +"なお、`List Entry`は `Array Entry`とは同じではありません。\n" +"後者は項目の*配列*を表しています。" #. type: Title ## -#: text/chapter3.md:249 +#: text/chapter3.md:220 #, no-wrap msgid "Type Constructors and Kinds" msgstr "型構築子と種" #. type: Plain text -#: text/chapter3.md:252 +#: text/chapter3.md:223 msgid "" "`List` is an example of a _type constructor_. Values do not have the type " "`List` directly, but rather `List a` for some type `a`. That is, `List` " "takes a _type argument_ `a` and _constructs_ a new type `List a`." msgstr "" -"`List`は*型構築子*(type constructor、型コンストラクタ)の一例になっていま" -"す。`List`そのものは型ではなく、何らかの型 `a`があるとき `List a`が型になって" -"います。つまり、 `List`は _型引数_ (type argument) `a`をとり、新たな型 `List " -"a`を _構築_ するのです。" +"`List`は*型構築子*の一例になっています。\n" +"`List`そのものは型ではなく、何らかの型 `a`があるとき `List a`が型になっていま" +"す。\n" +"つまり、 `List`は*型引数*`a`を取り、新たな型 `List a`を*構築*するのです。" #. type: Plain text -#: text/chapter3.md:254 +#: text/chapter3.md:225 msgid "" "Note that just like function application, type constructors are applied to " -"other types simply by juxtaposition: the type `List Entry` is in fact the " -"type constructor `List` _applied_ to the type `Entry` - it represents a list " +"other types simply by juxtaposition: the type `List Entry` is, in fact, the " +"type constructor `List` _applied_ to the type `Entry` – it represents a list " "of entries." msgstr "" -"ちょうど関数適用と同じように、型構築子は他の型に並べることで適用されることに" -"注意してください。型 `List Entry`は実は型構築子 `List`が型 `Entry`に _適用_ " -"されたものです。これは住所録項目のリストを表しています。" +"なお、ちょうど関数適用と同じように、型構築子は他の型に並置するだけで適用され" +"ます。\n" +"実際、型`List Entry`は型構築子`List`が型`Entry`に*適用*されたもので、項目のリ" +"ストを表しています。" #. type: Plain text -#: text/chapter3.md:256 +#: text/chapter3.md:227 msgid "" "If we try to incorrectly define a value of type `List` (by using the type " "annotation operator `::`), we will see a new type of error:" @@ -15162,7 +15065,7 @@ msgstr "" "今まで見たことのない種類のエラーが表示されるでしょう。" #. type: Fenced code block (text) -#: text/chapter3.md:257 +#: text/chapter3.md:228 #, no-wrap msgid "" "> import Data.List\n" @@ -15174,7 +15077,7 @@ msgstr "" "In a type-annotated expression x :: t, the type t must have kind Type\n" #. type: Plain text -#: text/chapter3.md:264 +#: text/chapter3.md:235 msgid "" "This is a _kind error_. Just like values are distinguished by their _types_, " "types are distinguished by their _kinds_, and just like ill-typed values " @@ -15185,7 +15088,7 @@ msgstr "" "は*種エラー*を引き起こします。" #. type: Plain text -#: text/chapter3.md:266 +#: text/chapter3.md:237 msgid "" "There is a special kind called `Type` which represents the kind of all types " "which have values, like `Number` and `String`." @@ -15194,7 +15097,7 @@ msgstr "" "な種があります。" #. type: Plain text -#: text/chapter3.md:268 +#: text/chapter3.md:239 #, no-wrap msgid "There are also kinds for type constructors. For example, the kind `Type -> Type` represents a function from types to types, just like `List`. So the error here occurred because values are expected to have types with kind `Type`, but `List` has kind `Type -> Type`.\n" msgstr "" @@ -15203,7 +15106,7 @@ msgstr "" "ここでエラーが発生したのは、値が種 `Type`であるような型を持つと期待されていたのに、 `List`は種 `Type -> Type`を持っているためです。\n" #. type: Plain text -#: text/chapter3.md:270 +#: text/chapter3.md:241 msgid "" "To find out the kind of a type, use the `:kind` command in PSCi. For example:" msgstr "" @@ -15211,7 +15114,7 @@ msgstr "" "す。" #. type: Fenced code block (text) -#: text/chapter3.md:271 +#: text/chapter3.md:242 #, no-wrap msgid "" "> :kind Number\n" @@ -15235,7 +15138,7 @@ msgstr "" "Type\n" #. type: Plain text -#: text/chapter3.md:284 +#: text/chapter3.md:255 msgid "" "PureScript's _kind system_ supports other interesting kinds, which we will " "see later in the book." @@ -15244,13 +15147,142 @@ msgstr "" "は本書の他の部分で見ていくことになるでしょう。" #. type: Title ## +#: text/chapter3.md:256 +#, no-wrap +msgid "Quantified Types" +msgstr "量化された型" + +#. type: Plain text +#: text/chapter3.md:259 +msgid "" +"For illustration purposes, let's define a primitive function that takes any " +"two arguments and returns the first one:" +msgstr "" +"説明しやすくするため、任意の2つの引数を取り最初のものを返す原始的な関数を定義" +"しましょう。" + +#. type: Fenced code block (text) +#: text/chapter3.md:260 +#, no-wrap +msgid "" +"> :paste\n" +"… constantlyFirst :: forall a b. a -> b -> a\n" +"… constantlyFirst = \\a b -> a\n" +"… ^D\n" +msgstr "" +"> :paste\n" +"… constantlyFirst :: forall a b. a -> b -> a\n" +"… constantlyFirst = \\a b -> a\n" +"… ^D\n" + +#. type: Plain text +#: text/chapter3.md:275 +#, no-wrap +msgid "" +"> Note that if you use `:type` to ask about the type of `constantlyFirst`, it will be more verbose:\n" +">\n" +"> ```text\n" +"> : type constantlyFirst\n" +"> forall (a :: Type) (b :: Type). a -> b -> a\n" +"> ```\n" +">\n" +"> The type signature contains additional kind information, which explicitly notes that `a` and `b` should be concrete types.\n" +msgstr "" +"> なお、`:type`を使って`constantlyfirst`の型について尋ねた場合、もっと冗長になります。\n" +">\n" +"> ```text\n" +"> : type constantlyFirst\n" +"> forall (a :: Type) (b :: Type). a -> b -> a\n" +"> ```\n" +">\n" +"> 型シグネチャには追加で種の情報が含まれます。\n" +"> `a`と`b`が具体的な型であることが明記されています。\n" + +#. type: Plain text +#: text/chapter3.md:277 +msgid "" +"The keyword `forall` indicates that `constantlyFirst` has a _universally " +"quantified type_. It means we can substitute any types for `a` and `b` – " +"`constantlyFirst` will work with these types." +msgstr "" +"この`forall`キーワードは、`constantlyFirst`が*全称量化された型*を持つことを示" +"しています。\n" +"つまり`a`や`b`をどの型に置き換えても良く、`constantlyFirst`はその型で動作する" +"のです。" + +# FIXME: `b` - `String`は`b` to be `String`のような気がします。 +#. type: Plain text +#: text/chapter3.md:279 +msgid "" +"For example, we might choose the type `a` to be `Int` and `b` – `String`. In " +"that case, we can _specialize_ the type of `constantlyFirst` to" +msgstr "" +"例えば、`a`を`Int`、`b`を`String`と選んだとします。\n" +"その場合、`constantlyFirst`の型を次のように*特殊化*できます。" + +#. type: Fenced code block (text) +#: text/chapter3.md:280 +#, no-wrap +msgid "Int -> String -> Int\n" +msgstr "Int -> String -> Int\n" + +#. type: Plain text #: text/chapter3.md:285 +msgid "" +"We don't have to indicate in code that we want to specialize a quantified " +"type – it happens automatically. For example, we can use `constantlyFirst` " +"as if it had this type already:" +msgstr "" +"量化された型を特殊化したいということをコードで示す必要はありません。\n" +"特殊化は自動的に行われます。\n" +"例えば、あたかも既にその型に備わっていたかの如く`constantlyFirst`を使えます。" + +#. type: Fenced code block (text) +#: text/chapter3.md:286 +#, no-wrap +msgid "" +"> constantlyFirst 3 \"ignored\"\n" +"\n" +"3\n" +msgstr "" +"> constantlyFirst 3 \"ignored\"\n" +"\n" +"3\n" + +#. type: Plain text +#: text/chapter3.md:293 +msgid "" +"While we can choose any types for `a` and `b`, the return type of " +"`constantlyFirst` has to be the same as the type of the first argument " +"(because both of them are \"tied\" to the same `a`):" +msgstr "" +"`a`と`b`にはどんな型でも選べますが、`constantlyFirst`が返す型は最初の引数の型" +"と同じでなければなりません(両方とも同じ`a`に「紐付く」からです)。" + +#. type: Fenced code block (text) +#: text/chapter3.md:294 +#, no-wrap +msgid "" +":type constantlyFirst true \"ignored\"\n" +"Boolean\n" +"\n" +":type constantlyFirst \"keep\" 3\n" +"String\n" +msgstr "" +":type constantlyFirst true \"ignored\"\n" +"Boolean\n" +"\n" +":type constantlyFirst \"keep\" 3\n" +"String\n" + +#. type: Title ## +#: text/chapter3.md:302 #, no-wrap msgid "Displaying Address Book Entries" msgstr "住所録の項目の表示" #. type: Plain text -#: text/chapter3.md:288 +#: text/chapter3.md:305 msgid "" "Let's write our first function, which will render an address book entry as a " "string. We start by giving the function a type. This is optional, but good " @@ -15263,35 +15295,35 @@ msgstr "" "まずは関数に型を与えることから始めます。\n" "型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくように" "すると良いでしょう。\n" -"実際、トップレベルの宣言に型註釈が含まれていないと、PureScriptコンパイラが警" -"告を出します。\n" +"実際、最上位の宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出" +"します。\n" "型宣言は関数の名前とその型を `::`記号で区切るようにして書きます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:289 +#: text/chapter3.md:306 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_signature}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_signature}}\n" #. type: Plain text -#: text/chapter3.md:294 +#: text/chapter3.md:311 msgid "" -"This type signature says that `showEntry` is a function, which takes an " +"This type signature says that `showEntry` is a function that takes an " "`Entry` as an argument and returns a `String`. Here is the code for " "`showEntry`:" msgstr "" -"`showEntry`は引数として `Entry`を取り `String`を返す関数であるということを、" -"この型シグネチャは言っています。\n" -"`showEntry`のコードは次の通りです。" +"この型シグネチャが言っているのは、`showEntry`は引数として`Entry`を取り" +"`String`を返す関数であるということです。\n" +"以下は`showEntry`のコードです。" #. type: Fenced code block (haskell) -#: text/chapter3.md:295 +#: text/chapter3.md:312 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_implementation}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_implementation}}\n" #. type: Plain text -#: text/chapter3.md:300 +#: text/chapter3.md:317 msgid "" "This function concatenates the three fields of the `Entry` record into a " "single string, using the `showAddress` function to turn the record inside " @@ -15303,25 +15335,25 @@ msgstr "" "`showAddress`の定義は次の通りです。" #. type: Fenced code block (haskell) -#: text/chapter3.md:301 +#: text/chapter3.md:318 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showAddress}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showAddress}}\n" #. type: Plain text -#: text/chapter3.md:306 +#: text/chapter3.md:323 #, no-wrap msgid "A function definition begins with the name of the function, followed by a list of argument names. The result of the function is specified after the equals sign. Fields are accessed with a dot, followed by the field name. In PureScript, string concatenation uses the diamond operator (`<>`), instead of the plus operator like in JavaScript.\n" msgstr "関数定義は関数の名前で始まり、引数名のリストが続きます。関数の結果は等号の後ろに定義します。フィールドはドットに続けてフィールド名を書くことで参照できます。PureScriptでは、文字列連結はJavaScriptのような単一のプラス記号ではなく、ダイアモンド演算子(`<>`)を使用します。\n" #. type: Title ## -#: text/chapter3.md:307 +#: text/chapter3.md:324 #, no-wrap msgid "Test Early, Test Often" msgstr "はやめにテスト、たびたびテスト" #. type: Plain text -#: text/chapter3.md:310 +#: text/chapter3.md:327 msgid "" "The PSCi interactive mode allows for rapid prototyping with immediate " "feedback, so let's use it to verify that our first few functions behave as " @@ -15332,12 +15364,12 @@ msgstr "" "それではこの最初の関数が正しく動作するかをPSCiを使用して確認してみましょう。" #. type: Plain text -#: text/chapter3.md:312 +#: text/chapter3.md:329 msgid "First, build the code you've written:" msgstr "まず、これまでに書いたコードをビルドします。" #. type: Plain text -#: text/chapter3.md:318 +#: text/chapter3.md:335 msgid "" "Next, load PSCi, and use the `import` command to import your new module:" msgstr "" @@ -15345,7 +15377,7 @@ msgstr "" "使います。" #. type: Fenced code block (text) -#: text/chapter3.md:319 +#: text/chapter3.md:336 #, no-wrap msgid "" "$ spago repl\n" @@ -15357,7 +15389,7 @@ msgstr "" "> import Data.AddressBook\n" #. type: Plain text -#: text/chapter3.md:326 +#: text/chapter3.md:343 msgid "" "We can create an entry by using a record literal, which looks just like an " "anonymous object in JavaScript." @@ -15366,18 +15398,18 @@ msgstr "" "無名オブジェクトと同じような構文で名前に束縛します。" #. type: Fenced code block (text) -#: text/chapter3.md:327 +#: text/chapter3.md:344 #, no-wrap msgid "> address = { street: \"123 Fake St.\", city: \"Faketown\", state: \"CA\" }\n" msgstr "> address = { street: \"123 Fake St.\", city: \"Faketown\", state: \"CA\" }\n" #. type: Plain text -#: text/chapter3.md:332 +#: text/chapter3.md:349 msgid "Now, try applying our function to the example:" msgstr "それでは、この例に関数を適用してみてください。" #. type: Fenced code block (text) -#: text/chapter3.md:333 +#: text/chapter3.md:350 #, no-wrap msgid "" "> showAddress address\n" @@ -15389,14 +15421,14 @@ msgstr "" "\"123 Fake St., Faketown, CA\"\n" #. type: Plain text -#: text/chapter3.md:340 +#: text/chapter3.md:357 msgid "" "Let's also test `showEntry` by creating an address book entry record " "containing our example address:" msgstr "`showEntry`も、住所の例を含む住所録項目レコードを作って試しましょう。" #. type: Fenced code block (text) -#: text/chapter3.md:341 +#: text/chapter3.md:358 #, no-wrap msgid "" "> entry = { firstName: \"John\", lastName: \"Smith\", address: address }\n" @@ -15410,28 +15442,28 @@ msgstr "" "\"Smith, John: 123 Fake St., Faketown, CA\"\n" #. type: Title ## -#: text/chapter3.md:348 +#: text/chapter3.md:365 #, no-wrap msgid "Creating Address Books" msgstr "住所録の作成" #. type: Plain text -#: text/chapter3.md:351 +#: text/chapter3.md:368 msgid "" "Now let's write some utility functions for working with address books. We " -"will need a value which represents an empty address book: an empty list." +"will need a value representing an empty address book: an empty list." msgstr "" -"今度は住所録の操作を支援する関数を幾つか書いてみましょう。\n" -"空の住所録を表す値が必要ですが、これには空のリストを使います。" +"今度は住所録を扱う補助関数を幾つか書いてみましょう。\n" +"空の住所録を表す値が必要ですが、これは空のリストです。" #. type: Fenced code block (haskell) -#: text/chapter3.md:352 +#: text/chapter3.md:369 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:emptyBook}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:emptyBook}}\n" #. type: Plain text -#: text/chapter3.md:357 +#: text/chapter3.md:374 msgid "" "We will also need a function for inserting a value into an existing address " "book. We will call this function `insertEntry`. Start by giving its type:" @@ -15440,42 +15472,40 @@ msgstr "" "ことにします。関数の型を与えることから始めましょう。" #. type: Fenced code block (haskell) -#: text/chapter3.md:358 +#: text/chapter3.md:375 text/chapter3.md:459 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}}\n" #. type: Plain text -#: text/chapter3.md:363 +#: text/chapter3.md:380 msgid "" "This type signature says that `insertEntry` takes an `Entry` as its first " -"argument, and an `AddressBook` as a second argument, and returns a new " +"argument, an `AddressBook` as a second argument, and returns a new " "`AddressBook`." msgstr "" -"この型シグネチャに書かれているのは、最初の引数として `Entry`、第二引数として " -"`AddressBook`を取り、新しい `AddressBook`を返すということです。" +"この型シグネチャに書かれているのは、最初の引数として`Entry`、第2引数として" +"`AddressBook`を取り、新しい`AddressBook`を返すということです。" #. type: Plain text -#: text/chapter3.md:365 +#: text/chapter3.md:382 msgid "" "We don't modify the existing `AddressBook` directly. Instead, we return a " -"new `AddressBook` which contains the same data. As such, `AddressBook` is an " -"example of an _immutable data structure_. This is an important idea in " -"PureScript - mutation is a side-effect of code, and inhibits our ability to " +"new `AddressBook`, which contains the same data. As such, `AddressBook` is " +"an example of an _immutable data structure_. This is an important idea in " +"PureScript – mutation is a side-effect of code and inhibits our ability to " "reason effectively about its behavior, so we prefer pure functions and " "immutable data where possible." msgstr "" -"既存の `AddressBook`を直接変更することはしません。\n" -"その代わりに、同じデータが含まれている新しい `AddressBook`を返すようにしま" -"す。\n" -"このように、 `AddressBook`は*不変データ構造*の一例となっています。\n" +"既存の`AddressBook`を直接変更することはしません。\n" +"代わりに、同じデータが含まれている新しい`AddressBook`を返します。\n" +"このように`AddressBook`は*不変データ構造*の一例となっています。\n" "これはPureScriptにおける重要な考え方です。\n" -"変更はコードの副作用であり、効率の良いコードの挙動を考えるときの妨げになりま" -"す。\n" -"そのため、可能な限り純粋な関数や不変のデータにする方が好ましいのです。" +"変更はコードの副作用であり、効率良く挙動を探る上で妨げになります。\n" +"そのため可能な限り純粋関数や不変なデータにする方が好ましいのです。" #. type: Plain text -#: text/chapter3.md:367 +#: text/chapter3.md:384 msgid "" "To implement `insertEntry`, we can use the `Cons` function from `Data.List`. " "To see its type, open PSCi and use the `:type` command:" @@ -15484,7 +15514,7 @@ msgstr "" "この関数の型を見るには、PSCiを起動し `:type`コマンドを使います。" #. type: Fenced code block (text) -#: text/chapter3.md:368 +#: text/chapter3.md:385 #, no-wrap msgid "" "$ spago repl\n" @@ -15492,47 +15522,46 @@ msgid "" "> import Data.List\n" "> :type Cons\n" "\n" -"forall a. a -> List a -> List a\n" +"forall (a :: Type). a -> List a -> List a\n" msgstr "" "$ spago repl\n" "\n" "> import Data.List\n" "> :type Cons\n" "\n" -"forall a. a -> List a -> List a\n" +"forall (a :: Type). a -> List a -> List a\n" #. type: Plain text -#: text/chapter3.md:378 +#: text/chapter3.md:395 msgid "" -"This type signature says that `Cons` takes a value of some type `a`, and a " +"This type signature says that `Cons` takes a value of some type `a`, takes a " "list of elements of type `a`, and returns a new list with entries of the " "same type. Let's specialize this with `a` as our `Entry` type:" msgstr "" -"この型シグネチャで書かれているのは、`Cons`が何らかの型`a`の値と型`a`を要素に" -"持つリストを引数に取り、同じ型の要素を持つ新しいリストを返すということで" -"す。\n" +"この型シグネチャで書かれているのは、`Cons`が何らかの型`a`の値と型`a`の要素の" +"リストを取り、同じ型の項目を持つ新しいリストを返すということです。\n" "`a`を`Entry`型として特殊化してみましょう。" #. type: Fenced code block (haskell) -#: text/chapter3.md:379 +#: text/chapter3.md:396 #, no-wrap msgid "Entry -> List Entry -> List Entry\n" msgstr "Entry -> List Entry -> List Entry\n" #. type: Plain text -#: text/chapter3.md:384 +#: text/chapter3.md:401 msgid "But `List Entry` is the same as `AddressBook`, so this is equivalent to" msgstr "" "しかし、 `List Entry`はまさに `AddressBook`ですから、次と同じになります。" #. type: Fenced code block (haskell) -#: text/chapter3.md:385 +#: text/chapter3.md:402 #, no-wrap msgid "Entry -> AddressBook -> AddressBook\n" msgstr "Entry -> AddressBook -> AddressBook\n" #. type: Plain text -#: text/chapter3.md:390 +#: text/chapter3.md:407 msgid "" "In our case, we already have the appropriate inputs: an `Entry`, and an " "`AddressBook`, so can apply `Cons` and get a new `AddressBook`, which is " @@ -15544,77 +15573,192 @@ msgstr "" "これこそがまさに求めていた関数です。" #. type: Plain text -#: text/chapter3.md:392 +#: text/chapter3.md:409 msgid "Here is our implementation of `insertEntry`:" msgstr "`insertEntry`の実装は次のようになります。" #. type: Fenced code block (haskell) -#: text/chapter3.md:393 +#: text/chapter3.md:410 #, no-wrap msgid "insertEntry entry book = Cons entry book\n" msgstr "insertEntry entry book = Cons entry book\n" #. type: Plain text -#: text/chapter3.md:398 +#: text/chapter3.md:415 msgid "" -"This brings the two arguments `entry` and `book` into scope, on the left " -"hand side of the equals symbol, and then applies the `Cons` function to " +"This brings the two arguments `entry` and `book` into scope – on the left-" +"hand side of the equals symbol – and then applies the `Cons` function to " "create the result." msgstr "" -"等号の左側にある2つの引数`entry`と`book`がスコープに導入されますから、これら" -"に `Cons`関数を適用して結果の値を作成しています。" +"こうすると、等号の左側にある2つの引数`entry`と`book`がスコープに導入されま" +"す。\n" +"それから`Cons`関数を適用し、結果を作成しています。" #. type: Title ## -#: text/chapter3.md:399 +#: text/chapter3.md:416 #, no-wrap msgid "Curried Functions" msgstr "カリー化された関数" #. type: Plain text -#: text/chapter3.md:402 +#: text/chapter3.md:419 msgid "" "Functions in PureScript take exactly one argument. While it looks like the " -"`insertEntry` function takes two arguments, it is in fact an example of a " -"_curried function_." +"`insertEntry` function takes two arguments, it is an example of a _curried " +"function_. In PureScript, all functions are considered curried." msgstr "" -"PureScriptでは、関数は常に1つの引数だけを取ります。`insertEntry`関数は2つの引" -"数を取るように見えますが、これは実際には*カリー化された関数*の一例となってい" -"ます。" +"PureScriptの関数はきっかり1つの引数を取ります。\n" +"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一" +"例なのです。\n" +"PureScriptでは全ての関数はカリー化されたものと見做されます。" + +#. type: Plain text +#: text/chapter3.md:421 +msgid "" +"Currying means converting a function that takes multiple arguments into a " +"function that takes them one at a time. When we call a function, we pass it " +"one argument, and it returns another function that also takes one argument " +"until all arguments are passed." +msgstr "" +"カリー化が意味するのは複数の引数を取る関数を1度に1つ取る関数に変換することで" +"す。\n" +"関数を呼ぶときに1つの引数を渡し、これまた1つの引数を取る別の関数を返し、と" +"いったことを全ての引数が渡されるまで続けます。" + +#. type: Plain text +#: text/chapter3.md:423 +msgid "" +"For example, when we pass `5` to `add`, we get another function, which takes " +"an int, adds 5 to it, and returns the sum as a result:" +msgstr "" +"例えば`add`に`5`に渡すと別の関数が得られます。\n" +"その関数は整数を取り、5を足し、合計を結果として返します。" + +#. type: Fenced code block (haskell) +#: text/chapter3.md:424 +#, no-wrap +msgid "" +"add :: Int -> Int -> Int\n" +"add x y = x + y\n" +"\n" +"addFive :: Int -> Int\n" +"addFive = add 5\n" +msgstr "" +"add :: Int -> Int -> Int\n" +"add x y = x + y\n" +"\n" +"addFive :: Int -> Int\n" +"addFive = add 5\n" + +#. type: Plain text +#: text/chapter3.md:433 +msgid "" +"`addFive` is the result of _partial application_, which means we pass less " +"than the total number of arguments to a function that takes multiple " +"arguments. Let's give it a try:" +msgstr "" +"`addFive`は*部分適用*の結果です。\n" +"つまり複数の引数を取る関数に、引数の全個数より少ない数だけ渡すのです。\n" +"試してみましょう。" + +#. type: Plain text +#: text/chapter3.md:443 +#, no-wrap +msgid "" +"> Note that you must define the `add` function if you haven't already:\n" +">\n" +"> ```text\n" +"> > import Prelude\n" +"> > :paste\n" +">… add :: Int -> Int -> Int\n" +">… add x y = x + y\n" +">… ^D\n" +"> ```\n" +msgstr "" +"> なお、お済みでなければ`add`関数を定義しなくてはなりません。\n" +">\n" +"> ```text\n" +"> > import Prelude\n" +"> > :paste\n" +">… add :: Int -> Int -> Int\n" +">… add x y = x + y\n" +">… ^D\n" +"> ```\n" + +#. type: Fenced code block (text) +#: text/chapter3.md:444 +#, no-wrap +msgid "" +"> :paste\n" +"… addFive :: Int -> Int\n" +"… addFive = add 5\n" +"… ^D\n" +"\n" +"> addFive 1\n" +"6\n" +"\n" +"> add 5 1\n" +"6\n" +msgstr "" +"> :paste\n" +"… addFive :: Int -> Int\n" +"… addFive = add 5\n" +"… ^D\n" +"\n" +"> addFive 1\n" +"6\n" +"\n" +"> add 5 1\n" +"6\n" + +#. type: Plain text +#: text/chapter3.md:458 +msgid "" +"To better understand currying and partial application, try making a few " +"other functions, for example, out of `add`. And when you're done, let's " +"return to the `insertEntry`." +msgstr "" +"カリー化と部分適用をもっと理解するには、例にあった`add`とは別の関数を2、3作っ" +"てみてください。\n" +"そしてそれができたら`insertEntry`に戻りましょう。" #. type: Plain text -#: text/chapter3.md:404 +#: text/chapter3.md:464 #, no-wrap -msgid "The `->` operator in the type of `insertEntry` associates to the right, which means that the compiler parses the type as\n" -msgstr "`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。\n" +msgid "The `->` operator (in the type signature) associates to the right, which means that the compiler parses the type as\n" +msgstr "" +"(型シグネチャ中の)`->`演算子は右結合です。\n" +"つまりコンパイラは型を次のように解釈します。\n" #. type: Fenced code block (haskell) -#: text/chapter3.md:405 +#: text/chapter3.md:465 #, no-wrap msgid "Entry -> (AddressBook -> AddressBook)\n" msgstr "Entry -> (AddressBook -> AddressBook)\n" #. type: Plain text -#: text/chapter3.md:410 +#: text/chapter3.md:470 msgid "" -"That is, `insertEntry` is a function which returns a function! It takes a " -"single argument, an `Entry`, and returns a new function, which in turn takes " -"a single `AddressBook` argument and returns a new `AddressBook`." +"`insertEntry` takes a single argument, an `Entry`, and returns a new " +"function, which in turn takes a single `AddressBook` argument and returns a " +"new `AddressBook`." msgstr "" -"すなわち、 `insertEntry`は関数を返す関数である、ということです。\n" -"この関数は単一の引数 `Entry`を取り、それから単一の引数 `AddressBook`を取り新" -"しい `AddressBook`を返す新しい関数を返すのです。" +"`insertEntry`は単一の引数`Entry`を取り、新しい関数を返します。\n" +"そして今度はその関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返" +"します。" #. type: Plain text -#: text/chapter3.md:412 +#: text/chapter3.md:472 msgid "" -"This means that we can _partially apply_ `insertEntry` by specifying only " -"its first argument, for example. In PSCi, we can see the result type:" +"This means we can _partially apply_ `insertEntry` by specifying only its " +"first argument, for example. In PSCi, we can see the result type:" msgstr "" -"これは例えば、最初の引数だけを与えると `insertEntry`を _部分適用_ (partial " -"application) できることを意味します。PSCiでこの結果の型を見てみましょう。" +"これはつまり、最初の引数だけを与えて`insertEntry`を*部分適用*できたりするとい" +"うことです。\n" +"PSCiで結果の型が見られます。" #. type: Fenced code block (text) -#: text/chapter3.md:413 +#: text/chapter3.md:473 #, no-wrap msgid "" "> :type insertEntry entry\n" @@ -15626,7 +15770,7 @@ msgstr "" "AddressBook -> AddressBook\n" #. type: Plain text -#: text/chapter3.md:420 +#: text/chapter3.md:480 msgid "" "As expected, the return type was a function. We can apply the resulting " "function to a second argument:" @@ -15635,7 +15779,7 @@ msgstr "" "この結果の関数に2つ目の引数も適用できます。" #. type: Fenced code block (text) -#: text/chapter3.md:421 +#: text/chapter3.md:481 #, no-wrap msgid "" "> :type (insertEntry entry) emptyBook\n" @@ -15645,14 +15789,16 @@ msgstr "" "AddressBook\n" #. type: Plain text -#: text/chapter3.md:427 +#: text/chapter3.md:487 msgid "" -"Note though that the parentheses here are unnecessary - the following is " +"Note though, that the parentheses here are unnecessary – the following is " "equivalent:" -msgstr "ここで括弧は不要であることにも注意してください。次の式は同等です。" +msgstr "" +"ただし、ここでの括弧は不要です。\n" +"以下は等価です。" #. type: Fenced code block (text) -#: text/chapter3.md:428 +#: text/chapter3.md:488 #, no-wrap msgid "" "> :type insertEntry entry emptyBook\n" @@ -15662,26 +15808,26 @@ msgstr "" "AddressBook\n" #. type: Plain text -#: text/chapter3.md:434 +#: text/chapter3.md:494 msgid "" -"This is because function application associates to the left, and this " -"explains why we can just specify function arguments one after the other, " -"separated by whitespace." +"This is because function application associates to the left, which explains " +"why we can specify function arguments one after the other, separated by " +"whitespace." msgstr "" -"これは関数適用が左結合であるためで、なぜ空白で区切った引数を関数に指定するだ" -"けでいいのかの説明にもなっています。" +"これは関数適用が左に結合するためで、なぜ空白で区切った引数を次々に関数に指定" +"するだけでいいのかの説明にもなっています。" #. type: Plain text -#: text/chapter3.md:436 +#: text/chapter3.md:496 #, no-wrap -msgid "The `->` operator in function types is a _type constructor_ for functions. It takes two type arguments, the function's argument type and the return type. The left and right operands respectively.\n" +msgid "The `->` operator in function types is a _type constructor_ for functions. It takes two type arguments: the function's argument type and the return type – the left and right operands, respectively.\n" msgstr "" "関数の型の`->`演算子は関数の*型構築子*です。\n" "この演算子は2つの型引数を取ります。\n" "左右の被演算子はそれぞれ関数の引数の型と返り値の型です。\n" #. type: Plain text -#: text/chapter3.md:438 +#: text/chapter3.md:498 msgid "" "Note that in the rest of the book, I will talk about things like \"functions " "of two arguments\". However, it is to be understood that this means a " @@ -15694,12 +15840,12 @@ msgstr "" "引数を取り2つ目の引数を取る別の関数を返すのです。" #. type: Plain text -#: text/chapter3.md:440 +#: text/chapter3.md:500 msgid "Now consider the definition of `insertEntry`:" msgstr "今度は `insertEntry`の定義について考えてみます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:441 +#: text/chapter3.md:501 #, no-wrap msgid "" "insertEntry :: Entry -> AddressBook -> AddressBook\n" @@ -15709,23 +15855,23 @@ msgstr "" "insertEntry entry book = Cons entry book\n" #. type: Plain text -#: text/chapter3.md:447 +#: text/chapter3.md:507 msgid "" "If we explicitly parenthesize the right-hand side, we get `(Cons entry) " "book`. That is, `insertEntry entry` is a function whose argument is just " "passed along to the `(Cons entry)` function. But if two functions have the " -"same result for every input, then they are the same function! So we can " -"remove the argument `book` from both sides:" +"same result for every input, then they are the same! So we can remove the " +"argument `book` from both sides:" msgstr "" -"もし式の右辺に明示的に括弧をつけるなら、 `(Cons entry) book`となります。\n" -"`insertEntry entry`はその引数が単に関数 `(Cons entry)`に渡されるような関数だ" -"ということです。\n" -"でもこの2つの関数はどんな入力についても同じ結果を返しますから、つまりこれらは" -"同じ関数です。\n" -"よって、両辺から引数 `book`を削除できます。" +"もし式の右辺に明示的に括弧をつけるなら、`(Cons entry) book`となります。\n" +"つまり`insertEntry entry`はその引数が単に関数`(Cons entry)`に渡されるような関" +"数だということです。\n" +"ところがこの2つの関数はどんな入力についても同じ結果を返すので、となると同じ関" +"数ではないですか。\n" +"よって、両辺から引数`book`を削除できます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:448 +#: text/chapter3.md:508 #, no-wrap msgid "" "insertEntry :: Entry -> AddressBook -> AddressBook\n" @@ -15735,46 +15881,47 @@ msgstr "" "insertEntry entry = Cons entry\n" #. type: Plain text -#: text/chapter3.md:454 +#: text/chapter3.md:514 msgid "But now, by the same argument, we can remove `entry` from both sides:" msgstr "しかし今や同様の議論により、両辺から `entry`も削除できます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:455 +#: text/chapter3.md:515 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}}\n" #. type: Plain text -#: text/chapter3.md:460 +#: text/chapter3.md:520 msgid "" -"This process is called _eta conversion_, and can be used (along with some " -"other techniques) to rewrite functions in _point-free form_, which means " -"functions defined without reference to their arguments." +"This process, called _eta conversion_, can be used (along with other " +"techniques) to rewrite functions in _point-free form_, which means functions " +"defined without reference to their arguments." msgstr "" -"この処理は _イータ変換_ (eta conversion) と呼ばれ、(その他の技法を併用して)" -"引数を参照することなく関数を定義する _ポイントフリー形式_ (point-free form) " -"へと関数を書き換えるのに使うことができます。" +"この処理は*イータ変換*と呼ばれ、(その他の技法を併用して)*ポイントフリー形式" +"*へと関数を書き換えるのに使えます。\n" +"つまり、引数を参照せずに関数を定義できるのです。" #. type: Plain text -#: text/chapter3.md:462 +#: text/chapter3.md:522 msgid "" "In the case of `insertEntry`, _eta conversion_ has resulted in a very clear " -"definition of our function - \"`insertEntry` is just cons on lists\". " -"However, it is arguable whether point-free form is better in general." +"definition of our function – \"`insertEntry` is just cons on lists\". " +"However, it is arguable whether the point-free form is better in general." msgstr "" -"`insertEntry`の場合には、イータ変換によって「`insertEntry`は単にリストに対す" -"るconsだ」となり、関数の定義はとても明確になりました。しかし、一般的にポイン" -"トフリー形式のほうがいいのかどうかには議論の余地があります。" +"`insertEntry`の場合、イータ変換によって「`insertEntry`は単にリストにおける" +"consだ」となり、とても明快な関数の定義になりました。\n" +"しかし、一般にポイントフリー形式のほうがいいのかどうかには議論の余地がありま" +"す。" #. type: Title ## -#: text/chapter3.md:463 +#: text/chapter3.md:523 #, no-wrap msgid "Property Accessors" msgstr "プロパティ取得子" #. type: Plain text -#: text/chapter3.md:466 +#: text/chapter3.md:526 msgid "" "One common pattern is to use a function to access individual fields (or " "\"properties\") of a record. An inline function to extract an `Address` from " @@ -15785,13 +15932,13 @@ msgstr "" "`Entry`から`Address`を取り出すインライン関数は次のように書けます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:467 +#: text/chapter3.md:527 #, no-wrap msgid "\\entry -> entry.address\n" msgstr "\\entry -> entry.address\n" #. type: Plain text -#: text/chapter3.md:472 +#: text/chapter3.md:532 msgid "" "PureScript also allows [_property accessor_](https://github.com/purescript/" "documentation/blob/master/language/Syntax.md#property-accessors) shorthand, " @@ -15804,13 +15951,13 @@ msgstr "" "イン関数は次と等価です。" #. type: Fenced code block (haskell) -#: text/chapter3.md:473 +#: text/chapter3.md:533 #, no-wrap msgid "_.address\n" msgstr "_.address\n" #. type: Plain text -#: text/chapter3.md:478 +#: text/chapter3.md:538 msgid "" "This works with any number of levels or properties, so a function to extract " "the city associated with an `Entry` could be written as:" @@ -15819,18 +15966,18 @@ msgstr "" "ように書けます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:479 +#: text/chapter3.md:539 #, no-wrap msgid "_.address.city\n" msgstr "_.address.city\n" #. type: Plain text -#: text/chapter3.md:484 text/chapter5.md:247 +#: text/chapter3.md:544 text/chapter5.md:247 msgid "For example:" msgstr "以下は一例です。" #. type: Fenced code block (text) -#: text/chapter3.md:485 +#: text/chapter3.md:545 #, no-wrap msgid "" "> address = { street: \"123 Fake St.\", city: \"Faketown\", state: \"CA\" }\n" @@ -15850,46 +15997,46 @@ msgstr "" "\"Faketown\"\n" #. type: Title ## -#: text/chapter3.md:495 +#: text/chapter3.md:555 #, no-wrap msgid "Querying the Address Book" msgstr "住所録に問い合わせる" #. type: Plain text -#: text/chapter3.md:498 +#: text/chapter3.md:558 msgid "" "The last function we need to implement for our minimal address book " "application will look up a person by name and return the correct `Entry`. " "This will be a nice application of building programs by composing small " -"functions - a key idea from functional programming." +"functions – a key idea from functional programming." msgstr "" "最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索" -"し適切な `Entry`を返すものです。これは小さな関数を組み合わせることでプログラ" -"ムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるで" -"しょう。" +"し適切な`Entry`を返すものです。\n" +"これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログ" +"ラミングで鍵となる考え方のよい応用例になるでしょう。" #. type: Plain text -#: text/chapter3.md:500 +#: text/chapter3.md:560 msgid "" -"We can first filter the address book, keeping only those entries with the " -"correct first and last names. Then we can simply return the head (i.e. " -"first) element of the resulting list." +"We can filter the address book, keeping only those entries with the correct " +"first and last names. Then we can return the head (i.e., first) element of " +"the resulting list." msgstr "" -"まずは住所録を絞り込み、該当する姓名を持つ項目だけを保持するようにするのがい" -"いでしょう。それから、結果のリストの先頭の (head) 要素を返すだけです。" +"住所録を絞り込めば該当する姓名を持つ項目だけを保持するようにできます。\n" +"そうすれば結果のリストの先頭(つまり最初)の要素を返せます。" #. type: Plain text -#: text/chapter3.md:502 +#: text/chapter3.md:562 msgid "" "With this high-level specification of our approach, we can calculate the " -"type of our function. First open PSCi, and find the types of the `filter` " +"type of our function. First, open PSCi, and find the types of the `filter` " "and `head` functions:" msgstr "" -"この大まかな仕様に従って、この関数の型を計算できます。まずPSCiを起動し、 " -"`filter`関数と `head`関数の型を見てみましょう。" +"この大まかな道筋の仕様があれば関数の型を計算できます。\n" +"まずPSCiを開いて`filter`関数と`head`関数の型を探してみましょう。" #. type: Fenced code block (text) -#: text/chapter3.md:503 +#: text/chapter3.md:563 #, no-wrap msgid "" "$ spago repl\n" @@ -15897,59 +16044,58 @@ msgid "" "> import Data.List\n" "> :type filter\n" "\n" -"forall a. (a -> Boolean) -> List a -> List a\n" +"forall (a :: Type). (a -> Boolean) -> List a -> List a\n" "\n" "> :type head\n" "\n" -"forall a. List a -> Maybe a\n" +"forall (a :: Type). List a -> Maybe a\n" msgstr "" "$ spago repl\n" "\n" "> import Data.List\n" "> :type filter\n" "\n" -"forall a. (a -> Boolean) -> List a -> List a\n" +"forall (a :: Type). (a -> Boolean) -> List a -> List a\n" "\n" "> :type head\n" "\n" -"forall a. List a -> Maybe a\n" +"forall (a :: Type). List a -> Maybe a\n" #. type: Plain text -#: text/chapter3.md:517 +#: text/chapter3.md:577 msgid "Let's pick apart these two types to understand their meaning." msgstr "" "型の意味を理解するために、これらの2つの型の一部を取り出してみましょう。" #. type: Plain text -#: text/chapter3.md:519 +#: text/chapter3.md:579 msgid "" "`filter` is a curried function of two arguments. Its first argument is a " -"function, which takes an element of the list and returns a `Boolean` value " -"as a result. Its second argument is a list of elements, and the return value " -"is another list." +"function, which takes an element of the list and returns a `Boolean` value. " +"Its second argument is a list of elements, and the return value is another " +"list." msgstr "" -"`filter`はカリー化された2引数の関数です。\n" -"最初の引数は、リストの要素を取り `Boolean`値を結果として返す関数です。\n" +"`filter`は2引数のカリー化された関数です。\n" +"最初の引数は関数で、リストの要素を取り`Boolean`値を返します。\n" "第2引数は要素のリストで、返り値は別のリストです。" #. type: Plain text -#: text/chapter3.md:521 +#: text/chapter3.md:581 msgid "" -"`head` takes a list as its argument, and returns a type we haven't seen " +"`head` takes a list as its argument and returns a type we haven't seen " "before: `Maybe a`. `Maybe a` represents an optional value of type `a`, and " "provides a type-safe alternative to using `null` to indicate a missing value " "in languages like JavaScript. We will see it again in more detail in later " "chapters." msgstr "" -"`head`は引数としてリストを取り、 `Maybe a`という今まで見たことがないような型" -"を返します。\n" -"`Maybe a`は型 `a`のオプショナルな値、つまり `a`の値を持つか持たないかのどちら" -"かの値を示しており、JavaScriptのような言語で値がないことを示すために使われる " -"`null`の型安全な代替手段を提供します。\n" -"これについては後の章で詳しく扱います。" +"`head`は引数としてリストを取り、 `Maybe a`という今までに見たことがない型を返" +"します。\n" +"`Maybe a`は型`a`の省略可能な値を表しており、JavaScriptのような言語で値がない" +"ことを示すための`null`を使う代わりとなる、型安全な代替を提供します。\n" +"後の章で改めて詳しく見ていきます。" #. type: Plain text -#: text/chapter3.md:523 +#: text/chapter3.md:583 msgid "" "The universally quantified types of `filter` and `head` can be _specialized_ " "by the PureScript compiler, to the following types:" @@ -15958,7 +16104,7 @@ msgstr "" "に _特殊化_ (specialized) されます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:524 +#: text/chapter3.md:584 #, no-wrap msgid "" "filter :: (Entry -> Boolean) -> AddressBook -> AddressBook\n" @@ -15970,20 +16116,20 @@ msgstr "" "head :: AddressBook -> Maybe Entry\n" #. type: Plain text -#: text/chapter3.md:531 +#: text/chapter3.md:591 msgid "" "We know that we will need to pass the first and last names that we want to " -"search for, as arguments to our function." -msgstr "検索する関数の引数として姓と名前を渡す必要があるのもわかっています。" +"search for as arguments to our function." +msgstr "関数の引数として姓名を渡す必要があるだろうということは分かっています。" #. type: Plain text -#: text/chapter3.md:533 +#: text/chapter3.md:593 #, no-wrap msgid "We also know that we will need a function to pass to `filter`. Let's call this function `filterEntry`. `filterEntry` will have type `Entry -> Boolean`. The application `filter filterEntry` will then have type `AddressBook -> AddressBook`. If we pass the result of this function to the `head` function, we get our result of type `Maybe Entry`.\n" msgstr "`filter`に渡す関数も必要になることもわかります。この関数を `filterEntry`と呼ぶことにしましょう。 `filterEntry`は `Entry -> Boolean`という型を持っています。 `filter filterEntry`という関数適用の式は、 `AddressBook -> AddressBook`という型を持つでしょう。もしこの関数の結果を `head`関数に渡すと、型 `Maybe Entry`の結果を得ることになります。\n" #. type: Plain text -#: text/chapter3.md:535 +#: text/chapter3.md:595 msgid "" "Putting these facts together, a reasonable type signature for our function, " "which we will call `findEntry`, is:" @@ -15992,31 +16138,30 @@ msgstr "" "`findEntry`と呼ぶことにしましょう。" #. type: Fenced code block (haskell) -#: text/chapter3.md:536 +#: text/chapter3.md:596 #, no-wrap msgid "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_signature}}\n" msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_signature}}\n" #. type: Plain text -#: text/chapter3.md:541 +#: text/chapter3.md:601 msgid "" -"This type signature says that `findEntry` takes two strings, the first and " -"last names, and a `AddressBook`, and returns an optional `Entry`. The " +"This type signature says that `findEntry` takes two strings: the first and " +"last names, takes an `AddressBook`, and returns an optional `Entry`. The " "optional result will contain a value only if the name is found in the " "address book." msgstr "" "この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び" -"`AddressBook`を引数に取り、`Entry`のオプション型の値を結果として返すというこ" -"とです。\n" -"オプショナルな結果は名前が住所録で発見された場合にのみ値を持ちます。" +"`AddressBook`を引数に取り、省略可能な`Entry`を返すということです。\n" +"省略可能な結果は名前が住所録に見付かった場合にのみ値を持ちます。" #. type: Plain text -#: text/chapter3.md:543 +#: text/chapter3.md:603 msgid "And here is the definition of `findEntry`:" msgstr "そして、 `findEntry`の定義は次のようになります。" #. type: Fenced code block (haskell) -#: text/chapter3.md:544 +#: text/chapter3.md:604 #, no-wrap msgid "" "findEntry firstName lastName book = head (filter filterEntry book)\n" @@ -16030,12 +16175,12 @@ msgstr "" " filterEntry entry = entry.firstName == firstName && entry.lastName == lastName\n" #. type: Plain text -#: text/chapter3.md:552 +#: text/chapter3.md:612 msgid "Let's go over this code step by step." msgstr "一歩ずつこのコードを調べてみましょう。" #. type: Plain text -#: text/chapter3.md:554 +#: text/chapter3.md:614 msgid "" "`findEntry` brings three names into scope: `firstName` and `lastName`, both " "representing strings, and `book`, an `AddressBook`." @@ -16044,17 +16189,17 @@ msgstr "" "型の `book`という3つの名前をスコープに導入します。" #. type: Plain text -#: text/chapter3.md:556 +#: text/chapter3.md:616 msgid "" -"The right hand side of the definition combines the `filter` and `head` " +"The right-hand side of the definition combines the `filter` and `head` " "functions: first, the list of entries is filtered, and the `head` function " "is applied to the result." msgstr "" -"定義の右辺では `filter`関数と `head`関数が組み合わされています。\n" -"まず項目のリストを絞り込み、その結果に `head`関数を適用しています。" +"定義の右辺では`filter`関数と`head`関数が組み合わさっています。\n" +"まず項目のリストを絞り込み、その結果に`head`関数を適用しています。" #. type: Plain text -#: text/chapter3.md:558 +#: text/chapter3.md:618 msgid "" "The predicate function `filterEntry` is defined as an auxiliary declaration " "inside a `where` clause. This way, the `filterEntry` function is available " @@ -16072,87 +16217,90 @@ msgstr "" "`filterEntry`が `findEntry`の内部にあることは必須になっています。" #. type: Plain text -#: text/chapter3.md:560 +#: text/chapter3.md:620 msgid "" -"Note that, just like for top-level declarations, it was not necessary to " +"Note that, just like for top-level declarations, it was unnecessary to " "specify a type signature for `filterEntry`. However, doing so is recommended " "as a form of documentation." msgstr "" -"最上位での宣言と同じように、必ずしも `filterEntry`の型シグネチャを指定しなく" -"てもよいことに注意してください。ただし、ドキュメントとしても役に立つので型シ" -"グネチャを書くことは推奨されています。" +"なお、最上位での宣言と同じように、必ずしも`filterEntry`の型シグネチャを指定し" +"なくても構いません。\n" +"ただし、ドキュメントの一形態として指定しておくことが推奨されます。" #. type: Title ## -#: text/chapter3.md:561 +#: text/chapter3.md:621 #, no-wrap msgid "Infix Function Application" msgstr "中置の関数適用" #. type: Plain text -#: text/chapter3.md:564 +#: text/chapter3.md:624 msgid "" -"Most of the functions discussed so far used _prefix_ function application, " -"where the function name was put _before_ the arguments. For example, when " -"using the `insertEntry` function to add an `Entry` (`john`) to an empty " +"Most functions discussed so far used _prefix_ function application, where " +"the function name was put _before_ the arguments. For example, when using " +"the `insertEntry` function to add an `Entry` (`john`) to an empty " "`AddressBook`, we might write:" msgstr "" -"これまでお話しした関数のほとんどは _前置_ 関数適用でした。関数名が引数の _前" -"_ に置かれていたということです。例えば`insertEntry`関数を使って`Entry` " -"(`john`) を空の`AddressBook`に追加する場合、以下のように書けます。" +"これまでお話しした関数のほとんどは*前置*関数適用でした。\n" +"関数名が引数の*前*に置かれていたということです。\n" +"例えば`insertEntry`関数を使って`Entry` (`john`) を空の`AddressBook`に追加する" +"場合、以下のように書けます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:565 +#: text/chapter3.md:625 #, no-wrap msgid "> book1 = insertEntry john emptyBook\n" msgstr "> book1 = insertEntry john emptyBook\n" #. type: Plain text -#: text/chapter3.md:570 +#: text/chapter3.md:630 msgid "" "However, this chapter has also included examples of _infix_ [binary " "operators](https://github.com/purescript/documentation/blob/master/language/" "Syntax.md#binary-operators), such as the `==` operator in the definition of " "`filterEntry`, where the operator is put _between_ the two arguments. These " -"infix operators are actually defined in the PureScript source as infix " -"aliases for their underlying _prefix_ implementations. For example, `==` is " -"defined as an infix alias for the prefix `eq` function with the line:" +"infix operators are defined in the PureScript source as infix aliases for " +"their underlying _prefix_ implementations. For example, `==` is defined as " +"an infix alias for the prefix `eq` function with the line:" msgstr "" -"しかしこの章には _中置_ [2引数演算子](https://github.com/purescript/" +"しかし本章には*中置*[2引数演算子](https://github.com/purescript/" "documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれて" -"います。例えば`filterEntry`の定義中の`==`演算子で、演算子が2つの引数の _間_ " -"に置かれています。実はこうした中置演算子はPureScriptのソースコードで、背後に" -"ある _前置_ 版の実装への中置別称として定義されています。例えば`==`は以下の行" -"により前置の`eq`関数の中置別称として定義されています。" +"います。\n" +"`filterEntry`の定義中の`==`演算子がそうで、2つの引数の*間*に置かれていま" +"す。\n" +"PureScriptのソースコードでこうした中置演算子は隠れた*前置*の実装への中置別称" +"として定義されています。\n" +"例えば`==`は以下の行により前置の`eq`関数の中置別称として定義されています。" #. type: Fenced code block (haskell) -#: text/chapter3.md:571 +#: text/chapter3.md:631 #, no-wrap msgid "infix 4 eq as ==\n" msgstr "infix 4 eq as ==\n" #. type: Plain text -#: text/chapter3.md:576 +#: text/chapter3.md:636 msgid "" -"and therefore `entry.firstName == firstName` in `filterEntry` could be " -"replaced with the `eq entry.firstName firstName`. We'll cover a few more " -"examples of defining infix operators later in this section." +"Therefore `entry.firstName == firstName` in `filterEntry` could be replaced " +"with the `eq entry.firstName firstName`. We'll cover a few more examples of " +"defining infix operators later in this section." msgstr "" "したがって`filterEntry`中の`entry.firstName == firstName`は`eq entry." -"firstName firstName`で置き換えられます。この節の後のほうで中置演算子を定義す" -"る例にもう少し触れます。" +"firstName firstName`で置き換えられます。\n" +"この節の後のほうで中置演算子を定義する例にもう少し触れます。" #. type: Plain text -#: text/chapter3.md:578 +#: text/chapter3.md:638 msgid "" -"There are situations where putting a prefix function in an infix position as " -"an operator leads to more readable code. One example is the `mod` function:" +"In some situations, putting a prefix function in an infix position as an " +"operator leads to more readable code. One example is the `mod` function:" msgstr "" -"前置関数を演算子としての中置の位置に置くとより読みやすいコードになる場面があ" -"ります。\n" +"前置関数を演算子としての中置の位置に置くと、より読みやすいコードになる場面が" +"あります。\n" "その一例が`mod`関数です。" #. type: Fenced code block (text) -#: text/chapter3.md:579 +#: text/chapter3.md:639 #, no-wrap msgid "" "> mod 8 3\n" @@ -16162,18 +16310,18 @@ msgstr "" "2\n" #. type: Plain text -#: text/chapter3.md:585 +#: text/chapter3.md:645 msgid "" -"The above usage works fine, but is awkward to read. A more familiar phrasing " +"The above usage works fine but is awkward to read. A more familiar phrasing " "is \"eight mod three\", which you can achieve by wrapping a prefix function " "in backticks (\\`):" msgstr "" -"上の用例は正しく動きますが、読みづらいです。\n" -"より馴染みのある表現の仕方は「8 mod 3」ですが、バックスラッシュ (\\`) の中に" -"前置関数を包めばこのように書けます。" +"上の用例でも充分動作しますが、読みにくいです。\n" +"より馴染みのある表現の仕方は「8 mod 3」です。\n" +"バックスラッシュ (\\`) の中に前置関数を包むとそのように書けます。" #. type: Fenced code block (text) -#: text/chapter3.md:586 +#: text/chapter3.md:646 #, no-wrap msgid "" "> 8 `mod` 3\n" @@ -16183,7 +16331,7 @@ msgstr "" "2\n" #. type: Plain text -#: text/chapter3.md:592 +#: text/chapter3.md:652 msgid "" "In the same way, wrapping `insertEntry` in backticks turns it into an infix " "operator, such that `book1` and `book2` below are equivalent:" @@ -16192,7 +16340,7 @@ msgstr "" "例えば以下の`book1`と`book2`は等価です。" #. type: Fenced code block (haskell) -#: text/chapter3.md:593 +#: text/chapter3.md:653 #, no-wrap msgid "" "book1 = insertEntry john emptyBook\n" @@ -16202,7 +16350,7 @@ msgstr "" "book2 = john `insertEntry` emptyBook\n" #. type: Plain text -#: text/chapter3.md:599 +#: text/chapter3.md:659 msgid "" "We can make an `AddressBook` with multiple entries by using multiple " "applications of `insertEntry` as a prefix function (`book3`) or as an infix " @@ -16213,7 +16361,7 @@ msgstr "" "(`book4`) として適用するかの2択があります。" #. type: Fenced code block (haskell) -#: text/chapter3.md:600 +#: text/chapter3.md:660 #, no-wrap msgid "" "book3 = insertEntry john (insertEntry peggy (insertEntry ned emptyBook))\n" @@ -16223,7 +16371,7 @@ msgstr "" "book4 = john `insertEntry` (peggy `insertEntry` (ned `insertEntry` emptyBook))\n" #. type: Plain text -#: text/chapter3.md:606 +#: text/chapter3.md:666 msgid "" "We can also define an infix operator alias (or synonym) for `insertEntry.` " "We'll arbitrarily choose `++` for this operator, give it a [precedence]" @@ -16239,37 +16387,37 @@ msgstr "" "master/language/Syntax.md#associativity)とします。" #. type: Fenced code block (haskell) -#: text/chapter3.md:607 +#: text/chapter3.md:667 #, no-wrap msgid "infixr 5 insertEntry as ++\n" msgstr "infixr 5 insertEntry as ++\n" #. type: Plain text -#: text/chapter3.md:612 +#: text/chapter3.md:672 msgid "This new operator lets us rewrite the above `book4` example as:" msgstr "この新しい演算子で上の`book4`の例を次のように書き直せます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:613 +#: text/chapter3.md:673 #, no-wrap msgid "book5 = john ++ (peggy ++ (ned ++ emptyBook))\n" msgstr "book5 = john ++ (peggy ++ (ned ++ emptyBook))\n" #. type: Plain text -#: text/chapter3.md:618 +#: text/chapter3.md:678 msgid "" -"and the right associativity of our new `++` operator lets us get rid of the " +"The right associativity of our new `++` operator lets us get rid of the " "parentheses without changing the meaning:" -msgstr "そして新しい`++`演算子が右結合なので意味を変えずに括弧を除去できます。" +msgstr "新しい`++`演算子の右結合性により、意味を変えずに括弧を除去できます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:619 +#: text/chapter3.md:679 #, no-wrap msgid "book6 = john ++ peggy ++ ned ++ emptyBook\n" msgstr "book6 = john ++ peggy ++ ned ++ emptyBook\n" #. type: Plain text -#: text/chapter3.md:624 +#: text/chapter3.md:684 msgid "" "Another common technique for eliminating parens is to use `apply`'s infix " "operator `$`, along with your standard prefix functions." @@ -16278,18 +16426,18 @@ msgstr "" "`$`を使うというものです。" #. type: Plain text -#: text/chapter3.md:626 +#: text/chapter3.md:686 msgid "For example, the earlier `book3` example could be rewritten as:" msgstr "例えば前の`book3`の例は以下のように書き直せます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:627 +#: text/chapter3.md:687 #, no-wrap msgid "book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook\n" msgstr "book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook\n" #. type: Plain text -#: text/chapter3.md:632 +#: text/chapter3.md:692 msgid "" "Substituting `$` for parens is usually easier to type and (arguably) easier " "to read. A mnemonic to remember the meaning of this symbol is to think of " @@ -16303,18 +16451,18 @@ msgstr "" "があります。" #. type: Plain text -#: text/chapter3.md:634 +#: text/chapter3.md:694 msgid "" -"Note that `$` isn't special syntax that's hardcoded into the language. It's " +"Note that `$` isn't a special syntax hardcoded into the language. It's " "simply the infix operator for a regular function called `apply`, which is " "defined in `Data.Function` as follows:" msgstr "" "なお、`($)`は言語にハードコードされた特別な構文ではありません。\n" -"単に`apply`という名前の通常の関数のための中置演算子であって、`Data.Function`" +"単に`apply`という名前の普通の関数のための中置演算子であって、`Data.Function`" "で以下のように定義されています。" #. type: Fenced code block (haskell) -#: text/chapter3.md:635 +#: text/chapter3.md:695 #, no-wrap msgid "" "apply :: forall a b. (a -> b) -> a -> b\n" @@ -16328,7 +16476,7 @@ msgstr "" "infixr 0 apply as $\n" #. type: Plain text -#: text/chapter3.md:643 +#: text/chapter3.md:703 #, no-wrap msgid "The `apply` function takes another function (of type `(a -> b)`) as its first argument and a value (of type `a`) as its second argument, then calls that function with that value. If it seems like this function doesn't contribute anything meaningful, you are absolutely correct! Your program is logically identical without it (see [referential transparency](https://en.wikipedia.org/wiki/Referential_transparency)). The syntactic utility of this function comes from the special properties assigned to its infix operator. `$` is a right-associative (`infixr`), low precedence (`0`) operator, which lets us remove sets of parentheses for deeply-nested applications.\n" msgstr "" @@ -16339,7 +16487,7 @@ msgstr "" "`$`は右結合 (`infixr`) で低い優先度 (`0`) の演算子ですが、これにより深い入れ子になった適用から括弧の束を削除できるのです。\n" #. type: Plain text -#: text/chapter3.md:645 +#: text/chapter3.md:705 msgid "" "Another parens-busting opportunity for the `$` operator is in our earlier " "`findEntry` function:" @@ -16348,20 +16496,20 @@ msgstr "" "す。" #. type: Fenced code block (haskell) -#: text/chapter3.md:646 +#: text/chapter3.md:706 #, no-wrap msgid "findEntry firstName lastName book = head $ filter filterEntry book\n" msgstr "findEntry firstName lastName book = head $ filter filterEntry book\n" #. type: Plain text -#: text/chapter3.md:651 +#: text/chapter3.md:711 msgid "" "We'll see an even more elegant way to rewrite this line with \"function " "composition\" in the next section." msgstr "この行をより簡潔に書き換える方法を次節の「関数合成」で見ていきます。" #. type: Plain text -#: text/chapter3.md:653 +#: text/chapter3.md:713 msgid "" "If you'd like to use a concise infix operator alias as a prefix function, " "you can surround it in parentheses:" @@ -16369,7 +16517,7 @@ msgstr "" "名前の短い中置演算子を前置関数として使いたければ括弧で囲むことができます。" #. type: Fenced code block (text) -#: text/chapter3.md:654 +#: text/chapter3.md:714 #, no-wrap msgid "" "> 8 + 3\n" @@ -16385,7 +16533,7 @@ msgstr "" "11\n" #. type: Plain text -#: text/chapter3.md:663 +#: text/chapter3.md:723 msgid "" "Alternatively, operators can be partially applied by surrounding the " "expression with parentheses and using `_` as an operand in an [operator " @@ -16402,7 +16550,7 @@ msgstr "" "に束縛しているので、もはや別に無名とも言えなくなっていますが)。" #. type: Fenced code block (text) -#: text/chapter3.md:664 +#: text/chapter3.md:724 #, no-wrap msgid "" "> add3 = (3 + _)\n" @@ -16414,14 +16562,14 @@ msgstr "" "5\n" #. type: Plain text -#: text/chapter3.md:671 +#: text/chapter3.md:731 msgid "" "To summarize, the following are equivalent definitions of a function that " "adds `5` to its argument:" msgstr "纏めると、以下は引数に`5`を加える関数の等価な定義です。" #. type: Fenced code block (haskell) -#: text/chapter3.md:672 +#: text/chapter3.md:732 #, no-wrap msgid "" "add5 x = 5 + x\n" @@ -16443,13 +16591,13 @@ msgstr "" "add5 x = 5 `(+)` x -- よおポチ、中置に目がないっていうから、中置の中に中置を入れといたぜ\n" #. type: Title ## -#: text/chapter3.md:683 +#: text/chapter3.md:743 #, no-wrap msgid "Function Composition" msgstr "関数合成" #. type: Plain text -#: text/chapter3.md:686 +#: text/chapter3.md:746 msgid "" "Just like we were able to simplify the `insertEntry` function by using eta " "conversion, we can simplify the definition of `findEntry` by reasoning about " @@ -16459,7 +16607,7 @@ msgstr "" "考察すると `findEntry`の定義を簡略化できます。" #. type: Plain text -#: text/chapter3.md:688 +#: text/chapter3.md:748 msgid "" "Note that the `book` argument is passed to the `filter filterEntry` " "function, and the result of this application is passed to `head`. In other " @@ -16471,13 +16619,13 @@ msgstr "" "成_ (composition) に `book`が渡されるということです。" #. type: Plain text -#: text/chapter3.md:690 +#: text/chapter3.md:750 #, no-wrap msgid "In PureScript, the function composition operators are `<<<` and `>>>`. The first is \"backwards composition\", and the second is \"forwards composition\".\n" msgstr "PureScriptの関数合成演算子は `<<<`と `>>>`です。前者は「逆方向の合成」であり、後者は「順方向の合成」です。\n" #. type: Plain text -#: text/chapter3.md:692 +#: text/chapter3.md:752 msgid "" "We can rewrite the right-hand side of `findEntry` using either operator. " "Using backwards-composition, the right-hand side would be" @@ -16486,13 +16634,13 @@ msgstr "" "逆順の合成を使用すると、右辺は次のようになります。" #. type: Fenced code block (haskell) -#: text/chapter3.md:693 +#: text/chapter3.md:753 #, no-wrap msgid "(head <<< filter filterEntry) book\n" msgstr "(head <<< filter filterEntry) book\n" #. type: Plain text -#: text/chapter3.md:698 +#: text/chapter3.md:758 msgid "" "In this form, we can apply the eta conversion trick from earlier, to arrive " "at the final form of `findEntry`:" @@ -16501,7 +16649,7 @@ msgstr "" "ような形式に到達します。" #. type: Fenced code block (haskell) -#: text/chapter3.md:699 +#: text/chapter3.md:759 #, no-wrap msgid "" "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_implementation}}\n" @@ -16511,18 +16659,18 @@ msgstr "" " ...\n" #. type: Plain text -#: text/chapter3.md:705 +#: text/chapter3.md:765 msgid "An equally valid right-hand side would be:" msgstr "右辺を次のようにしても同じく妥当です。" #. type: Fenced code block (haskell) -#: text/chapter3.md:706 +#: text/chapter3.md:766 #, no-wrap msgid "filter filterEntry >>> head\n" msgstr "filter filterEntry >>> head\n" #. type: Plain text -#: text/chapter3.md:711 +#: text/chapter3.md:771 msgid "" "Either way, this gives a clear definition of the `findEntry` function: " "\"`findEntry` is the composition of a filtering function and the `head` " @@ -16532,19 +16680,19 @@ msgstr "" "いう `findEntry`関数のわかりやすい定義を与えます。" #. type: Plain text -#: text/chapter3.md:713 +#: text/chapter3.md:773 msgid "" -"I will let you make your own decision which definition is easier to " -"understand, but it is often useful to think of functions as building blocks " -"in this way - each function executing a single task, and solutions assembled " -"using function composition." +"I will let you decide which definition is easier to understand, but it is " +"often useful to think of functions as building blocks in this way: each " +"function executes a single task, and solutions are assembled using function " +"composition." msgstr "" -"どちらの定義のほうがわかりやすいかの判断はお任せしますが、このように関数を部" -"品として捉えると有用なことがよくあります。関数は1つの役目だけをこなし、機能を" -"関数合成で組み立てるというように。" +"どちらの定義のほうが分かりやすいかの判断はお任せしますが、このように関数を部" +"品として捉えるとしばしば有用です。\n" +"各関数は1つの役目をこなすようにし、解法を関数合成を使って組み立てるのです。" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 msgid "" "(Easy) Test your understanding of the `findEntry` function by writing down " "the types of each of its major subexpressions. For example, the type of the " @@ -16558,7 +16706,7 @@ msgstr "" "*補足*:この問題にはテストがありません。" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 msgid "" "(Medium) Write a function `findEntryByStreet :: String -> AddressBook -> " "Maybe Entry` which looks up an `Entry` given a street address. _Hint_ " @@ -16572,7 +16720,7 @@ msgstr "" "実装した関数をPSCiと`spago test`を走らせてテストしてください。" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 msgid "" "(Medium) Rewrite `findEntryByStreet` to replace `filterEntry` with the " "composition (using `<<<` or `>>>`) of: a property accessor (using the `_.` " @@ -16585,96 +16733,96 @@ msgstr "" "が与えられた通りの住所に等しいかを判定する関数です。" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 msgid "" -"(Medium) Write a function `isInBook` which tests whether a name appears in a " +"(Medium) Write a function `isInBook` that tests whether a name appears in a " "`AddressBook`, returning a Boolean value. _Hint_: Use PSCi to find the type " "of the `Data.List.null` function, which tests whether a list is empty or not." msgstr "" -"(普通)指定された名前が `AddressBook`に存在するかどうかを調べて真偽値で返す" -"関数`isInBook`を書いてみましょう。\n" -"*手掛かり*:リストが空かどうかを調べる `Data.List.null`関数の型をPSCiで調べて" -"みてみましょう。" +"(普通)名前が`AddressBook`に存在するかどうかを調べて真偽値で返す関数" +"`isInBook`を書いてみましょう。\n" +"*手掛かり*:PSCiを使って`Data.List.null`関数の型を見付けてください。\n" +"この関数はリストが空かどうかを調べます。" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 msgid "" "(Difficult) Write a function `removeDuplicates` which removes \"duplicate\" " "address book entries. We'll consider entries duplicated if they share the " "same first and last names, while ignoring `address` fields. _Hint_: Use PSCi " "to find the type of the `Data.List.nubByEq` function, which removes " "duplicate elements from a list based on an equality predicate. Note that the " -"first element in each set of duplicates (closest to list head) is the one " -"that is kept." +"first element in each set of duplicates (closest to the list head) is the " +"one that is kept." msgstr "" -"(難しい)「重複」している項目を住所録から削除する関数 `removeDuplicates`を書" -"いてみましょう。\n" +"(難しい)「重複」している住所録の項目を削除する関数`removeDuplicates`を書い" +"てみましょう。\n" "項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複してい" "ると考えます。\n" -"*手掛かり*:関数 `Data.List.nubBy`の型を、PSCiを使用して調べてみましょう。\n" -"この関数は値同士の等価性を定義する述語関数に基づいてリストから重複要素を削除" -"します。\n" -"なお、それぞれの重複する項目の集合における最初の要素(リストの先頭に最も近" +"*手掛かり*:`Data.List.nubByEq`関数の型をPSCiを使って調べましょう。\n" +"この関数は等価性の述語に基づいてリストから重複要素を削除します。\n" +"なお、それぞれの重複する項目の集合において最初の要素(リストの先頭に最も近" "い)が保持する項目です。" #. type: Plain text -#: text/chapter3.md:725 +#: text/chapter3.md:785 msgid "" -"In this chapter, we covered several new functional programming concepts:" -msgstr "この章では、関数型プログラミングの新しい概念を幾つも導入しました。" +"In this chapter, we covered several new functional programming concepts and " +"learned how to:" +msgstr "" +"この章では関数型プログラミングの新しい概念を幾つか押さえ、以下の方法を学びま" +"した。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "" -"How to use the interactive mode PSCi to experiment with functions and test " -"ideas." +"Use the interactive mode PSCi to experiment with functions and test ideas." msgstr "" -"対話的モードのPSCiを使用して、関数を調べるなどの思いついたことを試す方法" +"対話的モードのPSCiを使用して、関数で実験したり思いついたことを試したりする。" #. type: Bullet: '- ' -#: text/chapter3.md:733 -msgid "" -"The role of types as both a correctness tool, and an implementation tool." -msgstr "検証や実装の道具としての型の役割" +#: text/chapter3.md:793 +msgid "Use types as both a correctness tool and an implementation tool." +msgstr "正確さのための道具として、また実装のための道具として型を使う。" #. type: Bullet: '- ' -#: text/chapter3.md:733 -msgid "" -"The use of curried functions to represent functions of multiple arguments." -msgstr "多引数関数を表現する、カリー化された関数の使用" +#: text/chapter3.md:793 +msgid "Use curried functions to represent functions of multiple arguments." +msgstr "多引数の関数を表現するためにカリー化された関数を使う。" #. type: Bullet: '- ' -#: text/chapter3.md:733 -msgid "Creating programs from smaller components by composition." -msgstr "関数合成で小さな部品を組み合わせてのプログラムの構築" +#: text/chapter3.md:793 +msgid "Create programs from smaller components by composition." +msgstr "合成により小さな部品からプログラムを作る。" #. type: Bullet: '- ' -#: text/chapter3.md:733 -msgid "Structuring code neatly using `where` expressions." -msgstr "`where`節を利用したコードの構造化" +#: text/chapter3.md:793 +msgid "Structure code neatly using `where` expressions." +msgstr "`where`式を使ってコードを手際良く構造化する。" #. type: Bullet: '- ' -#: text/chapter3.md:733 -msgid "How to avoid null values by using the `Maybe` type." -msgstr "`Maybe`型を使用してnull値を回避する方法" +#: text/chapter3.md:793 +msgid "Avoid null values by using the `Maybe` type." +msgstr "`Maybe`型を使用してnull値を回避する。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "" -"Using techniques like eta conversion and function composition to refactor " -"code into a clear specification." +"Use techniques like eta conversion and function composition to refactor code " +"into a clear specification." msgstr "" -"イータ変換や関数合成のような手法を利用した、よりわかりやすいコードへの再構成" +"イータ変換や関数合成のような技法を使ってより分かりやすい仕様にリファクタす" +"る。" #. type: Plain text -#: text/chapter3.md:734 +#: text/chapter3.md:794 msgid "In the following chapters, we'll build on these ideas." msgstr "次の章からは、これらの考えかたに基づいて進めていきます。" #. type: Title # #: text/chapter4.md:1 #, no-wrap -msgid "Recursion, Maps And Folds" +msgid "Recursion, Maps, And Folds" msgstr "再帰、マップ、畳み込み" #. type: Plain text @@ -16685,15 +16833,16 @@ msgid "" "programming, which we will use throughout this book." msgstr "" "この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて" -"見ていきましょう。再帰は関数型プログラミングの基本的な手法であり、この本の全" -"体に亙って使われます。" +"見ていきましょう。\n" +"再帰は関数型プログラミングの基本的な手法であり、本書全体にわたって使われます。" #. type: Plain text #: text/chapter4.md:8 msgid "" "We will also cover some standard functions from PureScript's standard " -"libraries. We will see the `map` and `fold` functions, as well as some " -"useful special cases, like `filter` and `concatMap`." +"libraries. We will `map`, `fold`, and some useful special cases, like " +"`filter` and `concatMap`." msgstr "" "また、PureScriptの標準ライブラリから標準的な関数を幾つか取り扱います。\n" "`map`や`fold`といった関数だけでなく、`filter`や`concatMap`といった特別な場合" @@ -16704,12 +16853,13 @@ msgstr "" msgid "" "The motivating example for this chapter is a library of functions for " "working with a virtual filesystem. We will apply the techniques learned in " -"this chapter to write functions which compute properties of the files " +"this chapter to write functions that compute properties of the files " "represented by a model of a filesystem." msgstr "" "この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用" -"います。この章で学ぶ手法を応用して、擬似的なファイルシステムによって表される" -"ファイルのプロパティを計算する関数を記述します。" +"います。\n" +"この章で学ぶ技術を応用し、ファイルシステムのモデルにより表現されるファイルの" +"プロパティを計算する関数を書きます。" #. type: Plain text #: text/chapter4.md:14 @@ -16784,8 +16934,8 @@ msgid "" msgstr "" "再帰は*分割統治*戦略と密接な関係があります。\n" "分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部" -"分に分割してそれぞれの部分について問題を解き、部分ごとの答えから最終的な答え" -"を組み立てるということです。" +"分に分割してそれぞれの部分について問題を解き、部分毎の答えから最終的な答えを" +"組み立てるということです。" #. type: Plain text #: text/chapter4.md:30 @@ -16807,20 +16957,18 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factorial}}\n" #: text/chapter4.md:38 msgid "" "Here, we can see how the factorial function is computed by reducing the " -"problem to a subproblem - that of computing the factorial of a smaller " -"integer. When we reach zero, the answer is immediate." +"problem to a subproblem – computing the factorial of a smaller integer. When " +"we reach zero, the answer is immediate." msgstr "" -"部分問題へ問題を分割することによって階乗関数がどのように計算されるかがわかり" -"ます。より小さい数へと階乗を計算していくということです。ゼロに到達すると、答" -"えは直ちに求まります。" +"このように、問題を部分問題へ分割することによって階乗関数の計算方法が見てとれ" +"ます。\n" +"より小さい数の階乗を計算していくということです。\n" +"ゼロに到達すると、答えは直ちに求まります。" #. type: Plain text #: text/chapter4.md:40 -msgid "" -"Here is another common example, which computes the _Fibonacci function_:" -msgstr "" -"次は、 _フィボナッチ関数_ (Fibonacci function) を計算するという、これまたよく" -"ある例です。" +msgid "Here is another common example that computes the _Fibonacci function_:" +msgstr "次は、*フィボナッチ関数*を計算するという、これまたよくある例です。" #. type: Fenced code block (haskell) #: text/chapter4.md:41 @@ -16844,15 +16992,11 @@ msgstr "" #. type: Plain text #: text/chapter4.md:48 -msgid "" -"Note that, while the above examples of `factorial` and `fib` work as " -"intended, a more idiomatic implementation would use pattern matching instead " -"of `if`/`then`/`else`. Pattern matching techniques are discussed in a later " -"chapter." +#, no-wrap +msgid "> Note that, while the above examples of `factorial` and `fib` work as intended, a more idiomatic implementation would use pattern matching instead of `if`/`then`/`else`. Pattern-matching techniques are discussed in a later chapter.\n" msgstr "" -"なお上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実" -"装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。パ" -"ターン照合の技法は後の章でお話しします。" +"> なお、上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。\n" +"> パターン照合の技法は後の章でお話しします。\n" #. type: Title ## #: text/chapter4.md:49 @@ -16906,59 +17050,60 @@ msgstr "" msgid "" "In this function, we use an `if .. then .. else` expression to branch based " "on the emptiness of the array. The `null` function returns `true` on an " -"empty array. Empty arrays have length zero, and a non-empty array has a " +"empty array. Empty arrays have a length of zero, and a non-empty array has a " "length that is one more than the length of its tail." msgstr "" "この関数では配列が空かどうかで分岐するために`if ... then ... else`式を使って" "います。\n" -"この`null`関数は配列が空のときに`true`を返します。\n" -"空の配列の長さはゼロであり、空でない配列の長さは配列の先頭を取り除いた残りの" -"部分の長さより1大きいというわけです。" +"この`null`関数は空の配列で`true`を返します。\n" +"空の配列の長さはゼロであり、空でない配列の長さは尾鰭の長さより1大きいというわ" +"けです。" #. type: Plain text #: text/chapter4.md:67 msgid "" "The `tail` function returns a `Maybe` wrapping the given array without its " -"first element. If the array is empty (i.e. it doesn't have a tail) `Nothing` " -"is returned. The `fromMaybe` function takes a default value and a `Maybe` " -"value. If the latter is `Nothing` it returns the default, in the other case " -"it returns the value wrapped by `Just`." +"first element. If the array is empty (i.e., it doesn't have a tail), " +"`Nothing` is returned. The `fromMaybe` function takes a default value and a " +"`Maybe` value. If the latter is `Nothing` it returns the default; in the " +"other case, it returns the value wrapped by `Just`." msgstr "" "`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返しま" -"す。配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。`fromMaybe`" -"関数は既定値と`Maybe`値を取ります。後者が`Nothing`であれば既定値を返し、そう" -"でなければ`Just`に包まれた値を返します。" +"す。\n" +"配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。\n" +"`fromMaybe`関数は既定値と`Maybe`値を取ります。\n" +"後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返しま" +"す。" #. type: Plain text #: text/chapter4.md:69 msgid "" -"This example is obviously a very impractical way to find the length of an " -"array in JavaScript, but should provide enough help to allow you to complete " -"the following exercises:" +"This example is a very impractical way to find the length of an array in " +"JavaScript, but it should provide enough help to allow you to complete the " +"following exercises:" msgstr "" "JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえ" -"ませんが、次の演習を完遂するための手がかりとしては充分でしょう。" +"ませんが、次の演習を完遂するための手掛かりとしては充分でしょう。" #. type: Bullet: ' 1. ' #: text/chapter4.md:74 msgid "" -"(Easy) Write a recursive function `isEven` which returns `true` if and only " +"(Easy) Write a recursive function `isEven` that returns `true` if and only " "if its input is an even integer." msgstr "" -"(簡単)入力が偶数であるとき、かつそのときに限り`true`に返すような再帰関数を" -"書いてみましょう。" +"(簡単)入力が偶数であるとき、かつそのときに限り`true`に返す再帰関数`isEven`" +"を書いてみましょう。" #. type: Bullet: ' 2. ' #: text/chapter4.md:74 msgid "" -"(Medium) Write a recursive function `countEven` which counts the number of " +"(Medium) Write a recursive function `countEven` that counts the number of " "even integers in an array. _Hint_: the function `head` (also available in " "`Data.Array`) can be used to find the first element in a non-empty array." msgstr "" -"(少し難しい)配列内の偶数の数を数える再帰関数`countEven`を書いてみましょ" -"う。\n" -"*手掛かり*:`Data.Array`モジュールの`head`関数を使うと、空でない配列の最初の" -"要素を見つけることができます。" +"(普通)配列内の偶数の整数を数える再帰関数`countEven`を書いてみましょう。\n" +"*手掛かり*:`head`関数(これも`Data.Array`モジュールから手に入ります)を使う" +"と、空でない配列の最初の要素を見つけられます。" #. type: Title ## #: text/chapter4.md:75 @@ -16971,23 +17116,24 @@ msgstr "マップ" msgid "" "The `map` function is an example of a recursive function on arrays. It is " "used to transform the elements of an array by applying a function to each " -"element in turn. Therefore, it changes the _contents_ of the array, but " -"preserves its _shape_ (i.e. its length)." +"element in turn. Therefore, it changes the _contents_ of the array but " +"preserves its _shape_ (i.e., its length)." msgstr "" -"`map`関数は配列に対する再帰関数の1つです。この関数を使うと、配列の各要素に順" -"番に関数を適用することで、配列の要素を変換できます。そのため、配列の*内容*は" -"変更されますが、その*形状*(ここでは「長さ」)は保存されます。" +"`map`関数は配列に対する再帰関数の一例です。\n" +"配列の各要素に順番に関数を適用し、配列の要素を変換するのに使われます。\n" +"そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存" +"されます。" #. type: Plain text #: text/chapter4.md:80 msgid "" -"When we cover _type classes_ later in the book we will see that the `map` " +"When we cover _type classes_ later in the book, we will see that the `map` " "function is an example of a more general pattern of shape-preserving " "functions which transform a class of type constructors called _functors_." msgstr "" -"本書の後半で _型クラス_ (type class) の内容を押さえるとき、`map`関数が形状保" -"存関数のより一般的な様式の一例であることを見ていきます。これは _関手_ " -"(functor) と呼ばれる型構築子のクラスを変換するものです。" +"本書の後半で*型クラス*の内容を押さえるとき、`map`関数が形状を保存する関数のよ" +"り一般的な様式の一例であることを見ていきます。\n" +"この関数は*関手*と呼ばれる型構築子のクラスを変換するものです。" #. type: Plain text #: text/chapter4.md:82 @@ -17013,7 +17159,7 @@ msgstr "" #. type: Plain text #: text/chapter4.md:92 msgid "" -"Notice how `map` is used - we provide a function which should be \"mapped " +"Notice how `map` is used – we provide a function that should be \"mapped " "over\" the array in the first argument, and the array itself in its second." msgstr "" "`map`がどのように使われているかに注目してください。\n" @@ -17057,8 +17203,8 @@ msgstr "" #. type: Plain text #: text/chapter4.md:105 #, no-wrap -msgid "There is an operator which is equivalent to the `map` function when used with arrays, called `<$>`. This operator can be used infix like any other binary operator:\n" -msgstr "配列を扱うときは、`map`関数と等価な`<$>`という演算子が存在します。この演算子は他の二項演算子と同じように中置で使用できます。\n" +msgid "There is an operator which is equivalent to the `map` function when used with arrays, called `<$>`.\n" +msgstr "配列を扱う際は`map`関数と等価な`<$>`という演算子が存在します。\n" #. type: Fenced code block (text) #: text/chapter4.md:106 @@ -17080,10 +17226,10 @@ msgstr "それでは`map`の型を見てみましょう。" #, no-wrap msgid "" "> :type map\n" -"forall a b f. Functor f => (a -> b) -> f a -> f b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Functor f => (a -> b) -> f a -> f b\n" msgstr "" "> :type map\n" -"forall a b f. Functor f => (a -> b) -> f a -> f b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Functor f => (a -> b) -> f a -> f b\n" #. type: Plain text #: text/chapter4.md:119 @@ -17099,8 +17245,8 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:120 #, no-wrap -msgid "forall a b. (a -> b) -> Array a -> Array b\n" -msgstr "forall a b. (a -> b) -> Array a -> Array b\n" +msgid "forall (a :: Type) (b :: Type). (a -> b) -> Array a -> Array b\n" +msgstr "forall (a :: Type) (b :: Type). (a -> b) -> Array a -> Array b\n" #. type: Plain text #: text/chapter4.md:125 @@ -17127,12 +17273,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:133 #, no-wrap -msgid "Even though the infix operator `<$>` looks like special syntax, it is in fact just an alias for a regular PureScript function. The function is simply _applied_ using infix syntax. In fact, the function can be used like a regular function by enclosing its name in parentheses. This means that we can used the parenthesized name `(<$>)` in place of `map` on arrays:\n" +msgid "Even though the infix operator `<$>` looks like special syntax, it is in fact just an alias for a regular PureScript function. The function is simply _applied_ using infix syntax. In fact, the function can be used like a regular function by enclosing its name in parentheses. This means that we can use the parenthesized name `(<$>)` in place of `map` on arrays:\n" msgstr "" "中置演算子`<$>`は特別な構文のように見えるかもしれませんが、実はPureScriptの普通の関数の別称です。\n" "中置構文を使用した単なる*適用*にすぎません。\n" "実際、括弧でその名前を囲むと、この関数を通常の関数のように使用できます。\n" -"これは、`map`代わりに、括弧で囲まれた`(<$>)`という名前を使って配列に関数を適用できるということです。\n" +"これは、`map`代わりに、括弧で囲まれた`(<$>)`という名前が使えるということです。\n" #. type: Fenced code block (text) #: text/chapter4.md:134 @@ -17205,7 +17351,7 @@ msgid "In the example above, we parenthesized the expression `1 .. 5`, but this msgstr "" "上記の例では、`1 .. 5`という式は括弧で囲まれていましたが、実際にはこれは必要ありません。\n" "なぜなら、`Data.Array`モジュールは、`<$>`に割り当てられた優先順位より高い優先順位を`..`演算子に割り当てているからです。\n" -"上の例では、`..`の優先順位は、予約語`infix`のあとに書かれた数の`8` と定義されていました。\n" +"上の例では、`..`の優先順位は、キーワード`infix`のあとに書かれた数の`8` と定義されていました。\n" "ここでは`<$>`の優先順位よりも高い優先順位を`..`に割り当てており、このため括弧を付け加える必要がないということです。\n" #. type: Fenced code block (text) @@ -17227,10 +17373,11 @@ msgid "" "any expression using the same operator multiple times or using multiple " "operators of the same precedence." msgstr "" -"中置演算子に(左または右の)*結合性*を与えたい場合は、代わりに予約語`infixl`" -"と`infixr`を使います。`infix`を使うと何ら結合性は割り当てられず、同じ演算子を" -"複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まな" -"ければいけなくなります。" +"中置演算子に(左または右の)*結合性*を与えたい場合は、代わりにキーワード" +"`infixl`と`infixr`を使います。\n" +"`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同" +"じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなりま" +"す。" #. type: Title ## #: text/chapter4.md:168 @@ -17248,7 +17395,7 @@ msgid "" msgstr "" "`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供" "しています。\n" -"この関数は、述語関数に適合する要素のみを残し、既存の配列から新しい配列を作成" +"この関数は、述語関数に照合する要素のみを残し、既存の配列から新しい配列を作成" "する機能を提供します。" #. type: Plain text @@ -17349,7 +17496,7 @@ msgid "" "> import Data.Array\n" "\n" "> :type concat\n" -"forall a. Array (Array a) -> Array a\n" +"forall (a :: Type). Array (Array a) -> Array a\n" "\n" "> concat [[1, 2, 3], [4, 5], [6]]\n" "[1, 2, 3, 4, 5, 6]\n" @@ -17357,7 +17504,7 @@ msgstr "" "> import Data.Array\n" "\n" "> :type concat\n" -"forall a. Array (Array a) -> Array a\n" +"forall (a :: Type). Array (Array a) -> Array a\n" "\n" "> concat [[1, 2, 3], [4, 5], [6]]\n" "[1, 2, 3, 4, 5, 6]\n" @@ -17365,14 +17512,15 @@ msgstr "" #. type: Plain text #: text/chapter4.md:205 msgid "" -"There is a related function called `concatMap` which is like a combination " -"of the `concat` and `map` functions. Where `map` takes a function from " -"values to values (possibly of a different type), `concatMap` takes a " -"function from values to arrays of values." +"There is a related function called `concatMap` which is a combination of the " +"`concat` and `map` functions. Where `map` takes a function from values to " +"values (possibly of a different type), `concatMap` takes a function from " +"values to arrays of values." msgstr "" -"関連する関数として、`concat`と`map`を組み合わせたような`concatMap`と呼ばれる" -"関数もあります。`map`は(相異なる型の可能性がある)値からの値への関数を引数に" -"取りますが、それに対して`concatMap`は値から値の配列への関数を取ります。" +"関連する関数として、`concat`と`map`を組み合わせた`concatMap`と呼ばれる関数も" +"あります。\n" +"`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それ" +"に対して`concatMap`は値から値の配列への関数を取ります。" #. type: Plain text #: text/chapter4.md:207 @@ -17386,7 +17534,7 @@ msgid "" "> import Data.Array\n" "\n" "> :type concatMap\n" -"forall a b. (a -> Array b) -> Array a -> Array b\n" +"forall (a :: Type) (b :: Type). (a -> Array b) -> Array a -> Array b\n" "\n" "> concatMap (\\n -> [n, n * n]) (1 .. 5)\n" "[1,1,2,4,3,9,4,16,5,25]\n" @@ -17394,7 +17542,7 @@ msgstr "" "> import Data.Array\n" "\n" "> :type concatMap\n" -"forall a b. (a -> Array b) -> Array a -> Array b\n" +"forall (a :: Type) (b :: Type). (a -> Array b) -> Array a -> Array b\n" "\n" "> concatMap (\\n -> [n, n * n]) (1 .. 5)\n" "[1,1,2,4,3,9,4,16,5,25]\n" @@ -17452,8 +17600,8 @@ msgstr "" #. type: Plain text #: text/chapter4.md:229 msgid "" -"We can perform this computation using an array comprehension. We will do so " -"in steps, using PSCi as our interactive development environment." +"We can perform this computation using array comprehension. We will do so in " +"steps, using PSCi as our interactive development environment." msgstr "" "配列内包表記を使用するとこれを計算できます。\n" "PSCiを対話式の開発環境として使用し、1つずつこの手順を進めていきましょう。" @@ -17629,18 +17777,11 @@ msgstr "" #. type: Plain text #: text/chapter4.md:292 -msgid "" -"_Note_: Just like `map` and `concatMap` allowed us to write _array " -"comprehensions_, the more general operators `map` and `bind` allow us to " -"write so-called _monad comprehensions_. We'll see plenty more examples of " -"_monads_ later in the book, but in this chapter, we will only consider " -"arrays." +#, no-wrap +msgid "> _Note_: Just like `map` and `concatMap` allowed us to write _array comprehensions_, the more general operators `map` and `bind` allow us to write so-called _monad comprehensions_. We'll see plenty more examples of _monads_ later in the book, but in this chapter, we will only consider arrays.\n" msgstr "" -"*補足*:`map`と`concatMap`が _配列内包表記_ を書けるようにしているように、" -"もっと一般的な演算子である`map`と`bind`は _モナド内包表記_ (monad " -"comprehensions) と呼ばれているものを書けるようにします。本書の後半では _モナ" -"ド_ (monad) の例をたっぷり見ていくことになりますが、この章では配列のみを考え" -"ます。" +"> *補足*:`map`と`concatMap`があることで*配列内包表記*を書けるように、もっと一般的な演算子である`map`と`bind`があることで*モナド内包表記*と呼ばれているものが書けます。\n" +"> 本書の後半では*モナド*の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。\n" #. type: Plain text #: text/chapter4.md:294 @@ -17657,37 +17798,37 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factors}}\n" #. type: Plain text #: text/chapter4.md:300 msgid "" -"The keyword `do` introduces a block of code which uses do notation. The " -"block consists of expressions of a few types:" +"The keyword `do` introduces a block of code that uses do notation. The block " +"consists of expressions of a few types:" msgstr "" -"キーワード`do`はdo記法を使うコードのブロックを導入します。このブロックは幾つ" -"かの種類の式で構成されています。" +"キーワード`do`はdo記法を使うコードのブロックを導入します。\n" +"このブロックは幾つかの種類の式で構成されています。" #. type: Bullet: '- ' #: text/chapter4.md:304 msgid "" -"Expressions which bind elements of an array to a name. These are indicated " +"Expressions that bind elements of an array to a name. These are indicated " "with the backwards-facing arrow `<-`, with a name on the left, and an " "expression on the right whose type is an array." msgstr "" "配列の要素を名前に束縛する式。\n" -"これは後ろ向きの矢印`<-`で示されていて、その左側は名前、右側は配列の型を持つ" -"式です。" +"これは後ろ向きの矢印`<-`で示されており、左側には名前が、右側には配列の型を持" +"つ式があります。" #. type: Bullet: '- ' #: text/chapter4.md:304 msgid "" -"Expressions which do not bind elements of the array to names. The `do` " +"Expressions that do not bind elements of the array to names. The `do` " "_result_ is an example of this kind of expression and is illustrated in the " "last line, `pure [i, j]`." msgstr "" "名前に配列の要素を束縛しない式。\n" -"`do`の _結果_ はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されてい" -"ます。" +"`do`の*結果*はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されていま" +"す。" #. type: Bullet: '- ' #: text/chapter4.md:304 -msgid "Expressions which give names to expressions, using the `let` keyword." +msgid "Expressions that give names to expressions, using the `let` keyword." msgstr "`let`キーワードを使用し、式に名前を与える式。" #. type: Plain text @@ -17720,12 +17861,11 @@ msgstr "" #. type: Plain text #: text/chapter4.md:315 msgid "" -"In the case of arrays, `pure` simply constructs a singleton array. In fact, " -"we could modify our `factors` function to use this form, instead of using " -"`pure`:" +"In the case of arrays, `pure` simply constructs a singleton array. We can " +"modify our `factors` function to use this form, instead of using `pure`:" msgstr "" "配列の場合、`pure`は単に1要素の配列を作成します。\n" -"実際、`factors`関数を変更して、`pure`の代わりにこの形式も使うようにできます。" +"`factors`関数を変更して、`pure`の代わりにこの形式も使うようにできます。" #. type: Fenced code block (haskell) #: text/chapter4.md:316 @@ -17786,12 +17926,12 @@ msgid "" "> import Control.Alternative\n" "\n" "> :type guard\n" -"forall m. Alternative m => Boolean -> m Unit\n" +"forall (m :: Type -> Type). Alternative m => Boolean -> m Unit\n" msgstr "" "> import Control.Alternative\n" "\n" "> :type guard\n" -"forall m. Alternative m => Boolean -> m Unit\n" +"forall (m :: Type -> Type). Alternative m => Boolean -> m Unit\n" #. type: Plain text #: text/chapter4.md:342 @@ -17836,12 +17976,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:360 msgid "" -"That is, if `guard` is passed an expression which evaluates to `true`, then " -"it returns an array with a single element. If the expression evaluates to " +"If we pass an expression to `guard` that evaluates to `true`, then it " +"returns an array with a single element. If the expression evaluates to " "`false`, then its result is empty." msgstr "" "つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返" -"すのです。もし式が`false`と評価された場合は、その結果は空です。" +"すのです。\n" +"もし式が`false`と評価された場合は、その結果は空です。" #. type: Plain text #: text/chapter4.md:362 @@ -17865,20 +18006,20 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 msgid "" -"(Easy) Write a function `isPrime` which tests if its integer argument is " -"prime or not. _Hint_: Use the `factors` function." +"(Easy) Write a function `isPrime`, which tests whether its integer argument " +"is prime. _Hint_: Use the `factors` function." msgstr "" -"(簡単)整数の引数が素数であるかどうかを調べる関数`isPrime`を定義してみましょ" -"う。\n" +"(簡単)関数`isPrime`を書いてください。\n" +"この関数は整数の引数が素数であるかを調べます。\n" "*手掛かり*:`factors`関数を使ってください。" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 msgid "" "(Medium) Write a function `cartesianProduct` which uses do notation to find " -"the _cartesian product_ of two arrays, i.e. the set of all pairs of elements " -"`a`, `b`, where `a` is an element of the first array, and `b` is an element " -"of the second." +"the _cartesian product_ of two arrays, i.e., the set of all pairs of " +"elements `a`, `b`, where `a` is an element of the first array, and `b` is an " +"element of the second." msgstr "" "(普通)do記法を使い、2つの配列の*直積集合*を見つけるための関数" "`cartesianProduct`を書いてみましょう。\n" @@ -17888,16 +18029,16 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 msgid "" -"(Medium) Write a function `triples :: Int -> Array (Array Int)` which takes " +"(Medium) Write a function `triples :: Int -> Array (Array Int)`, which takes " "a number `n` and returns all Pythagorean triples whose components (the `a`, " -"`b` and `c` values) are each less than or equal to `n`. A _Pythagorean " +"`b`, and `c` values) are each less than or equal to `n`. A _Pythagorean " "triple_ is an array of numbers `[a, b, c]` such that `a² + b² = c²`. _Hint_: " "Use the `guard` function in an array comprehension." msgstr "" -"(普通)数値`n`を取って構成要素(値`a`, `b`, `c`)がそれぞれ`n`以下であるよう" -"な全てのピタゴラスの3つ組 (pythagorean triples) を返す関数`triples :: Int -> " -"Array (Array Int)`を書いてください。\n" -"*ピタゴラスの3つ組*は数値の配列`[a, b, c]`で `a² + b² = c²` です。\n" +"(普通)関数`triples :: Int -> Array (Array Int)`を書いてください。\n" +"この関数は数値`n`を取り、構成要素(値`a`、`b`、`c`)がそれぞれ`n`以下であるよ" +"うな全てのピタゴラスの3つ組 (pythagorean triples) を返します。\n" +"*ピタゴラスの3つ組*は`a² + b² = c²`であるような数値の配列`[a, b, c]`です。\n" "*手掛かり*:配列内包表記で`guard`関数を使ってください。" #. type: Bullet: ' 1. ' @@ -17905,14 +18046,14 @@ msgstr "" msgid "" "(Difficult) Write a function `primeFactors` which produces the [prime " "factorization](https://www.mathsisfun.com/prime-factorization.html) of `n`, " -"i.e. the array of prime integers whose product is `n`. _Hint_: for an " -"integer greater than 1, break the problem down into two subproblems: finding " -"the first factor, and finding the remaining factors." +"i.e., the array of prime integers whose product is `n`. _Hint_: for an " +"integer greater than 1, break the problem into two subproblems: finding the " +"first factor and the remaining factors." msgstr "" -"(難しい)`factors`関数を使用して、数`n`の[素因数分解](https://www." -"mathsisfun.com/prime-factorization.html)を求める関数`primeFactors`を定義して" -"みましょう。\n" -"数`n`の素因数分解とは、素数の積が`n`であるような整数の配列のことです。\n" +"(難しい)`factors`関数を使用して、`n`の[素因数分解](https://www.mathsisfun." +"com/prime-factorization.html)を求める関数`primeFactors`を定義してみましょ" +"う。\n" +"`n`の素因数分解とは、積が`n`であるような素数の配列のことです。\n" "*手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してくださ" "い。\n" "最初の因数を探し、それから残りの因数を探すのです。" @@ -17927,15 +18068,15 @@ msgstr "畳み込み" #: text/chapter4.md:373 msgid "" "Left and right folds over arrays provide another class of interesting " -"functions which can be implemented using recursion." +"functions that can be implemented using recursion." msgstr "" -"配列における左右の畳み込みは、再帰を用いて実装される別の興味深い一揃いの関数" +"配列における左右の畳み込みは、再帰を用いて実装できる別の興味深い一揃いの関数" "を提供します。" #. type: Plain text #: text/chapter4.md:375 msgid "" -"Start by importing the `Data.Foldable` module, and inspecting the types of " +"Start by importing the `Data.Foldable` module and inspecting the types of " "the `foldl` and `foldr` functions using PSCi:" msgstr "" "PSCiを使って、`Data.Foldable`モジュールをインポートし、`foldl`と`foldr`関数の" @@ -17948,56 +18089,55 @@ msgid "" "> import Data.Foldable\n" "\n" "> :type foldl\n" -"forall a b f. Foldable f => (b -> a -> b) -> b -> f a -> b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (b -> a -> b) -> b -> f a -> b\n" "\n" "> :type foldr\n" -"forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (a -> b -> b) -> b -> f a -> b\n" msgstr "" "> import Data.Foldable\n" "\n" "> :type foldl\n" -"forall a b f. Foldable f => (b -> a -> b) -> b -> f a -> b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (b -> a -> b) -> b -> f a -> b\n" "\n" "> :type foldr\n" -"forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b\n" +"forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (a -> b -> b) -> b -> f a -> b\n" #. type: Plain text #: text/chapter4.md:387 msgid "" -"These types are actually more general than we are interested in right now. " -"For the purposes of this chapter, we can assume that PSCi had given the " -"following (more specific) answer:" +"These types are more general than we are interested in right now. For this " +"chapter, we can simplify and assume the following (more specific) type " +"signatures:" msgstr "" "これらの型は、現在興味があるものよりも一般化されています。\n" -"この章の目的に対して、PSCiは以下の(より具体的な)答えをくれていると考えてお" -"きましょう。" +"この章では単純化して以下の(より具体的な)型シグネチャと見て構いません。" #. type: Fenced code block (text) #: text/chapter4.md:388 #, no-wrap msgid "" -"> :type foldl\n" +"-- foldl\n" "forall a b. (b -> a -> b) -> b -> Array a -> b\n" "\n" -"> :type foldr\n" +"-- foldr\n" "forall a b. (a -> b -> b) -> b -> Array a -> b\n" msgstr "" -"> :type foldl\n" +"-- foldl\n" "forall a b. (b -> a -> b) -> b -> Array a -> b\n" "\n" -"> :type foldr\n" +"-- foldr\n" "forall a b. (a -> b -> b) -> b -> Array a -> b\n" #. type: Plain text #: text/chapter4.md:397 msgid "" -"In both of these cases, the type `a` corresponds to the type of elements of " -"our array. The type `b` can be thought of as the type of an \"accumulator\", " +"In both cases, the type `a` corresponds to the type of elements of our " +"array. The type `b` can be thought of as the type of an \"accumulator\", " "which will accumulate a result as we traverse the array." msgstr "" -"どちらの型でも、`a`は配列の要素の型に対応しています。\n" -"型`b`は、配列を走査 (traverse) したときの結果を累積する「累積器」" -"(accumulator) の型だと考えることができます。" +"どちらの場合でも、型`a`は配列の要素の型に対応しています。\n" +"型`b`は「累算器」の型として考えることができます。\n" +"累算器とは配列を走査しつつ結果を累算するものです。" #. type: Plain text #: text/chapter4.md:399 @@ -18013,8 +18153,16 @@ msgstr "" #. type: Plain text #: text/chapter4.md:401 #, no-wrap -msgid "Let's see these functions in action. Let's use `foldl` to sum an array of integers. The type `a` will be `Int`, and we can also choose the result type `b` to be `Int`. We need to provide three arguments: a function `Int -> Int -> Int`, which will add the next element to the accumulator, an initial value for the accumulator of type `Int`, and an array of `Int`s to add. For the first argument, we can just use the addition operator, and the initial value of the accumulator will be zero:\n" -msgstr "実際にこれらの関数の動きを見てみましょう。`foldl`を使用して数の配列の和を求めてみます。型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。ここでは、次の要素を累積器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累積器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。最初の引数としては、加算演算子を使用できますし、累積器の初期値はゼロになります。\n" +msgid "Let's see these functions in action. Let's use `foldl` to sum an array of integers. The type `a` will be `Int`, and we can also choose the result type `b` to be `Int`. We need to provide three arguments: a function `Int -> Int -> Int`, which will add the next element to the accumulator, an initial value for the accumulator of type `Int`, and an array of `Int`s to add. For the first argument, we can use the addition operator, and the initial value of the accumulator will be zero:\n" +msgstr "" +"実際にこれらの関数の動きを見てみましょう。\n" +"`foldl`を使用して数の配列の和を求めてみます。\n" +"型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。\n" +"ここでは3つの引数を与える必要があります。\n" +"1つ目は次の要素を累算器に加算する`Int -> Int -> Int`という型の関数です。\n" +"2つ目は累算器の`Int`型の初期値です。\n" +"3つ目は和を求めたい`Int`の配列です。\n" +"最初の引数としては、加算演算子を使用できますし、累算器の初期値はゼロになります。\n" #. type: Fenced code block (text) #: text/chapter4.md:402 @@ -18048,13 +18196,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:415 msgid "" -"Let's write an example where the choice of folding function does matter, in " -"order to illustrate the difference. Instead of the addition function, let's " -"use string concatenation to build a string:" +"Let's write an example where the choice of folding function matters to " +"illustrate the difference. Instead of the addition function, let's use " +"string concatenation to build a string:" msgstr "" -"`foldl`と`foldr`の違いを説明するために、畳み込み関数の選択が影響する例も書い" -"てみましょう。\n" -"加算関数の代わりに、文字列連結を使用して文字列を作ってみます。" +"違いを説明するために、畳み込み関数の選択が大事になってくる例も書きましょ" +"う。\n" +"加算関数の代わりに、文字列連結を使用して文字列を構築しましょう。" #. type: Fenced code block (text) #: text/chapter4.md:416 @@ -18089,8 +18237,8 @@ msgstr "(((((\"\" <> show 1) <> show 2) <> show 3) <> show 4) <> show 5)\n" #. type: Plain text #: text/chapter4.md:431 -msgid "whereas the right fold is equivalent to this:" -msgstr "それに対し、右畳み込みは以下に相当します。" +msgid "Whereas the right fold is equivalent to this:" +msgstr "それに対し、右畳み込みは以下と等価です。" #. type: Fenced code block (text) #: text/chapter4.md:432 @@ -18107,17 +18255,17 @@ msgstr "末尾再帰" #. type: Plain text #: text/chapter4.md:439 msgid "" -"Recursion is a powerful technique for specifying algorithms, but comes with " -"a problem: evaluating recursive functions in JavaScript can lead to stack " +"Recursion is a powerful technique for specifying algorithms but comes with a " +"problem: evaluating recursive functions in JavaScript can lead to stack " "overflow errors if our inputs are too large." msgstr "" -"再帰はアルゴリズムを定義するための強力な手法ですが、問題も抱えています。\n" -"JavaScriptで再帰関数を評価するとき、入力が大きすぎるとスタックオーバーフロー" +"再帰はアルゴリズムを指定する強力な手法ですが、問題も抱えています。\n" +"JavaScriptで再帰関数を評価するとき、入力が大き過ぎるとスタックオーバーフロー" "でエラーを起こす可能性があるのです。" #. type: Plain text #: text/chapter4.md:441 -msgid "It is easy to verify this problem, with the following code in PSCi:" +msgid "It is easy to verify this problem with the following code in PSCi:" msgstr "PSCiで次のコードを入力すると、この問題を簡単に検証できます。" #. type: Fenced code block (text) @@ -18153,55 +18301,48 @@ msgstr "" #. type: Plain text #: text/chapter4.md:458 msgid "" -"This is a problem. If we are going to adopt recursion as a standard " -"technique from functional programming, then we need a way to deal with " -"possibly unbounded recursion." +"This is a problem. If we adopt recursion as a standard technique from " +"functional programming, we need a way to deal with possibly unbounded " +"recursion." msgstr "" -"これは問題です。関数型プログラミングの基本的な手法として再帰を採用しようとす" -"るなら、境界がない可能性がある再帰でも扱える方法が必要です。" +"これは問題です。\n" +"関数型プログラミングの標準的な手法として再帰を採用しようとするなら、境界がな" +"い再帰がありうるときでも扱える方法が必要です。" #. type: Plain text #: text/chapter4.md:460 msgid "" -"PureScript provides a partial solution to this problem in the form of _tail " +"PureScript provides a partial solution to this problem through _tail " "recursion optimization_." msgstr "" -"PureScriptは _末尾再帰最適化_ (tail recursion optimization) の形でこの問題に" -"対する部分的な解決策を提供しています。" +"PureScriptは*末尾再帰最適化*の形でこの問題に対する部分的な解決策を提供してい" +"ます。" #. type: Plain text #: text/chapter4.md:462 -msgid "" -"_Note_: more complete solutions to the problem can be implemented in " -"libraries using so-called _trampolining_, but that is beyond the scope of " -"this chapter. The interested reader can consult the documentation for the " -"[`free`](https://pursuit.purescript.org/packages/purescript-free) and " -"[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec) " -"packages." +#, no-wrap +msgid "> _Note_: more complete solutions to the problem can be implemented in libraries using so-called _trampolining_, but that is beyond the scope of this chapter. The interested reader can consult the documentation for the [`free`](https://pursuit.purescript.org/packages/purescript-free) and [`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec) packages.\n" msgstr "" -"*補足*:この問題へのより完全な解決策としては、いわゆる*トランポリン*を使用し" -"たライブラリで実装する方法がありますが、それはこの章で扱う範囲を超えていま" -"す。\n" -"この内容に興味のある読者は[`free`](https://pursuit.purescript.org/packages/" -"purescript-free)や[`tailrec`](https://pursuit.purescript.org/packages/" -"purescript-tailrec)パッケージのドキュメントを参照してみてください。" +"> *補足*:この問題へのより完全な解決策としては、いわゆる*トランポリン*を使用するライブラリで実装できますが、それはこの章で扱う範囲を超えています。\n" +"> 興味のある読者は[`free`](https://pursuit.purescript.org/packages/purescript-free)や[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec)パッケージのドキュメントをあたると良いでしょう。\n" #. type: Plain text #: text/chapter4.md:464 msgid "" -"The key observation which enables tail recursion optimization is the " -"following: a recursive call in _tail position_ to a function can be replaced " -"with a _jump_, which does not allocate a stack frame. A call is in _tail " -"position_ when it is the last call made before a function returns. This is " -"the reason why we observed a stack overflow in the example - the recursive " -"call to `f` was _not_ in tail position." -msgstr "" -"末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 _末尾位置_ " -"(tail position) にある関数の再帰的な呼び出しは、スタックフレームが確保されな" -"い _ジャンプ_ に置き換えることができます。関数が戻るより前の最後の呼び出しで" -"あるとき、呼び出しが _末尾位置_ にあるといいます。なぜこの例でスタックオー" -"バーフローが見られたのかはこれが理由です。この`f`の再帰呼び出しは、末尾位置 _" -"ではない_ からです。" +"The key observation that enables tail recursion optimization: a recursive " +"call in _tail position_ to a function can be replaced with a _jump_, which " +"does not allocate a stack frame. A call is in _tail position_ when it is the " +"last call made before a function returns. This is why we observed a stack " +"overflow in the example – the recursive call to `f` was _not_ in tail " +"position." +msgstr "" +"末尾再帰最適化を可能にする上で鍵となる観点は以下となります。\n" +"*末尾位置*にある関数の再帰的な呼び出しは*ジャンプ*に置き換えられます。\n" +"このジャンプではスタックフレームが確保されません。\n" +"関数が戻るより前の最後の呼び出しであるとき、呼び出しが*末尾位置*にあるといい" +"ます。\n" +"なぜ先の例でスタックオーバーフローが見られたのかはこれが理由です。\n" +"`f`の再帰呼び出しが末尾位置*でなかったからです。" #. type: Plain text #: text/chapter4.md:466 @@ -18229,36 +18370,36 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}}\n #. type: Plain text #: text/chapter4.md:474 msgid "" -"Notice that the recursive call to `factorialTailRec` is the last thing that " -"happens in this function - it is in tail position." +"Notice that the recursive call to `factorialTailRec` is the last thing in " +"this function – it is in tail position." msgstr "" -"`fact`への再帰呼び出しは、この関数の中で起こる最後のものである、つまり末尾位" -"置にあることに注意してください。" +"`factorialTailRec`への再帰呼び出しがこの関数の最後にある点に注目してくださ" +"い。\n" +"つまり末尾位置にあるのです。" #. type: Title ## #: text/chapter4.md:475 #, no-wrap msgid "Accumulators" -msgstr "累積器" +msgstr "累算器" #. type: Plain text #: text/chapter4.md:478 msgid "" -"One common way to turn a function which is not tail recursive into a tail " -"recursive function is to use an _accumulator parameter_. An accumulator " -"parameter is an additional parameter which is added to a function which " -"_accumulates_ a return value, as opposed to using the return value to " -"accumulate the result." +"One common way to turn a not tail recursive function into a tail recursive " +"is to use an _accumulator parameter_. An accumulator parameter is an " +"additional parameter added to a function that _accumulates_ a return value, " +"as opposed to using the return value to accumulate the result." msgstr "" -"末尾再帰ではない関数を末尾再帰関数に変える一般的な方法としては、 _累積器引数" -"_ (accumulator parameter) を使用する方法があります。累積器引数は関数に追加さ" -"れる余剰の引数で返り値を _累積_ するものです。これは結果を累積するために返り" -"値を使うのとは対称的です。" +"末尾再帰ではない関数を末尾再帰関数に変える一般的な方法は、*累算器引数*を使用" +"することです。\n" +"累算器引数は関数に追加される余剰の引数で、返り値を*累算*するものです。\n" +"これは結果を累算するために返り値を使うのとは対照的です。" #. type: Plain text #: text/chapter4.md:480 msgid "" -"For example, consider again the `length` function presented in the beginning " +"For example, consider again the `length` function presented at the beginning " "of the chapter:" msgstr "例えば章の初めに示した`length`関数を再考しましょう。" @@ -18301,36 +18442,37 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}}\n" #: text/chapter4.md:496 msgid "" "In this case, we delegate to the helper function `length'`, which is tail " -"recursive - its only recursive call is in the last case, and is in tail " -"position. This means that the generated code will be a _while loop_, and " -"will not blow the stack for large inputs." -msgstr "" -"ここでは、配列を逆転させる作業を補助関数`length'`に委譲しています。`length'`" -"は末尾再帰です。その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。こ" -"れは、生成されたコードが _whileループ_ となり、大きな入力でもスタックが溢れな" -"いことを意味します。" +"recursive – its only recursive call is in the last case, in tail position. " +"This means that the generated code will be a _while loop_ and not blow the " +"stack for large inputs." +msgstr "" +"ここでは補助関数`length'`に委譲しています。\n" +"この関数は末尾再帰です。\n" +"その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。\n" +"つまり、生成されるコードは*whileループ*となり、大きな入力でもスタックが溢れま" +"せん。" #. type: Plain text #: text/chapter4.md:498 msgid "" "To understand the implementation of `lengthTailRec`, note that the helper " "function `length'` essentially uses the accumulator parameter to maintain an " -"additional piece of state - the partial result. It starts out at 0, and " -"grows by adding 1 for every element in the input array." +"additional piece of state – the partial result. It starts at 0 and grows by " +"adding 1 for every element in the input array." msgstr "" -"`lengthTailRec`の実装を理解するために補助関数`length'`に着目しましょう。この" -"関数は必然的に累積器引数を使って追加の状態……これは部分的な結果です……を保持し" -"ています。0から始まり、入力の配列中の全ての要素それぞれについて1ずつ足されて" -"大きくなっていきます。" +"`lengthTailRec`の実装を理解する上では、補助関数`length'`が基本的に累算器引数" +"を使って追加の状態を保持していることに注目してください。\n" +"追加の状態とは、部分的な結果です。\n" +"0から始まり、入力の配列中の全ての各要素について1ずつ足されて大きくなっていき" +"ます。" #. type: Plain text #: text/chapter4.md:500 msgid "" -"Note also that while we might think of the accumulator as \"state\", there " -"is no direct mutation going on." +"Note also that while we might think of the accumulator as a \"state\", there " +"is no direct mutation." msgstr "" -"累積器を「状態」と考えることもできますが、直接には変更されているわけではない" -"ことにも注意してください。" +"なお、累算器を「状態」と考えることもできますが、直接には変更されていません。" #. type: Title ## #: text/chapter4.md:501 @@ -18341,23 +18483,23 @@ msgstr "明示的な再帰より畳み込みを選ぼう" #. type: Plain text #: text/chapter4.md:504 msgid "" -"If we can write our recursive functions using tail recursion, then we can " -"benefit from tail recursion optimization, so it becomes tempting to try to " -"write all of our functions in this form. However, it is often easy to forget " -"that many functions can be written directly as a fold over an array or " -"similar data structure. Writing algorithms directly in terms of combinators " -"such as `map` and `fold` has the added advantage of code simplicity - these " -"combinators are well-understood, and as such, communicate the _intent_ of " -"the algorithm much better than explicit recursion." -msgstr "" -"末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けることがで" -"きるので、全ての関数をこの形で書こうとする誘惑にかられます。\n" +"If we can write our recursive functions using tail recursion, we can benefit " +"from tail recursion optimization, so it becomes tempting to try to write all " +"of our functions in this form. However, it is often easy to forget that many " +"functions can be written directly as a fold over an array or similar data " +"structure. Writing algorithms directly in terms of combinators such as `map` " +"and `fold` has the added advantage of code simplicity – these combinators " +"are well-understood, and as such, communicate the _intent_ of the algorithm " +"much better than explicit recursion." +msgstr "" +"末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けられるの" +"で、全ての関数をこの形で書こうとする誘惑にかられます。\n" "しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書く" "ことができることを忘れがちです。\n" "`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、" "コードの単純さという利点があります。\n" -"これらの部品はよく知られており、明示的な再帰よりもアルゴリズムの*意図*をより" -"はっきりとさせるのです。" +"これらの部品はよく知られており、だからこそ明示的な再帰よりもアルゴリズムの*意" +"図*がより良く伝わるのです。" #. type: Plain text #: text/chapter4.md:506 @@ -18425,7 +18567,7 @@ msgid "" msgstr "" "(普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`" "を書いてください。\n" -"*手掛かり*:累積器引数を使ってください。" +"*手掛かり*:累算器引数を使ってください。" #. type: Bullet: ' 4. ' #: text/chapter4.md:527 @@ -18441,19 +18583,18 @@ msgstr "仮想ファイルシステム" #. type: Plain text #: text/chapter4.md:531 msgid "" -"In this section, we're going to apply what we've learned, writing functions " -"which will work with a model of a filesystem. We will use maps, folds and " -"filters to work with a predefined API." +"In this section, we'll apply what we've learned, writing functions that will " +"work with a model of a filesystem. We will use maps, folds, and filters to " +"work with a predefined API." msgstr "" -"この節では、これまで学んだことを応用して、模擬的なファイルシステムで動作する" -"関数を書いていきます。\n" -"事前に定義されたAPIで動作するように、マップ、畳み込み、及びフィルタを使用しま" -"す。" +"この節ではこれまで学んだことを応用してファイルシステムのモデルを扱う関数を書" +"きます。\n" +"事前に定義されたAPIを扱う上でマップ、畳み込み、及びフィルタを使用します。" #. type: Plain text #: text/chapter4.md:533 msgid "" -"The `Data.Path` module defines an API for a virtual filesystem, as follows:" +"The `Data.Path` module defines an API for a virtual filesystem as follows:" msgstr "" "`Data.Path`モジュールでは、次のように仮想ファイルシステムのAPIが定義されてい" "ます。" @@ -18481,9 +18622,8 @@ msgstr "`filename`関数は`Path`のファイル名を返します。" #. type: Bullet: '- ' #: text/chapter4.md:540 msgid "" -"The `size` function returns the file size for a `Path` which represents a " -"file." -msgstr "`size`関数は`Path`が示すファイルの大きさを返します。" +"The `size` function returns the file size for a `Path` representing a file." +msgstr "`size`関数はファイルを表す`Path`のファイルの大きさを返します。" #. type: Bullet: '- ' #: text/chapter4.md:540 @@ -18558,11 +18698,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:573 msgid "" -"The `Test.Examples` module defines functions which use the `Data.Path` API. " +"The `Test.Examples` module defines functions that use the `Data.Path` API. " "You do not need to modify the `Data.Path` module, or understand its " "implementation. We will work entirely in the `Test.Examples` module." msgstr "" -"`Test.Examples`モジュールでは`Data.Path`APIを使用する関数を定義しています。\n" +"`Test.Examples`モジュールでは`Data.Path` APIを使用する関数を定義していま" +"す。\n" "`Data.Path`モジュールを変更したり定義を理解したりする必要はありません。\n" "全て`Test.Examples`モジュールだけで作業します。" @@ -18575,11 +18716,12 @@ msgstr "全てのファイルの一覧" #. type: Plain text #: text/chapter4.md:577 msgid "" -"Let's write a function which performs a deep enumeration of all files inside " +"Let's write a function that performs a deep enumeration of all files inside " "a directory. This function will have the following type:" msgstr "" -"それでは、ディレクトリの中身を含めた全てのファイルを列挙する関数を書いてみま" -"しょう。この関数は以下のような型を持つでしょう。" +"それでは、ディレクトリの中身を含めた全てのファイルを深く列挙する関数を書いて" +"みましょう。\n" +"この関数は以下のような型を持つでしょう。" #. type: Fenced code block (haskell) #: text/chapter4.md:578 @@ -18593,13 +18735,14 @@ msgid "" "We can define this function by recursion. First, we can use `ls` to " "enumerate the immediate children of the directory. For each child, we can " "recursively apply `allFiles`, which will return an array of paths. " -"`concatMap` will allow us to apply `allFiles` and flatten the results at the " -"same time." +"`concatMap` will allow us to apply `allFiles` and flatten the results " +"simultaneously." msgstr "" -"再帰を使ってこの関数を定義できます。まずは`ls`を使用してディレクトリの直接の" -"子を列挙します。それぞれの子について再帰的に`allFiles`を適用すると、それぞれ" -"パスの配列が返ってくるでしょう。同時に`concatMap`を適用すると、この結果を平坦" -"にできます。" +"再帰を使ってこの関数を定義できます。\n" +"`ls`を使うとディレクトリ直下の子が列挙されます。\n" +"それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返り" +"ます。\n" +"`concatMap`を使うと、`allFiles`を適用して平坦化するまでを一度にできます。" #. type: Plain text #: text/chapter4.md:585 @@ -18614,15 +18757,11 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_implementat #. type: Plain text #: text/chapter4.md:591 -msgid "" -"_Note_: the cons operator `:` actually has poor performance on immutable " -"arrays, so it is not recommended in general. Performance can be improved by " -"using other data structures, such as linked lists and sequences." +#, no-wrap +msgid "> _Note_: the cons operator `:` has poor performance on immutable arrays, so it is not generally recommended. Performance can be improved by using other data structures, such as linked lists and sequences.\n" msgstr "" -"*補足*:実はcons演算子`:`は、不変な配列に対して効率性が悪いので、一般的には推" -"奨されません。\n" -"連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させるこ" -"とができます。" +"> *補足*:実はcons演算子`:`は、不変な配列に対して効率性が悪いので、一般的には推奨されません。\n" +"> 連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させられます。\n" #. type: Plain text #: text/chapter4.md:593 @@ -18662,15 +18801,15 @@ msgstr "" msgid "" "Recall that a backwards arrow corresponds to choosing an element from an " "array. The first step is to choose an element from the immediate children of " -"the argument. Then we simply call the function recursively for that file. " -"Since we are using do notation, there is an implicit call to `concatMap` " -"which concatenates all of the recursive results." +"the argument. Then we call the function recursively for that file. Since we " +"use do notation, there is an implicit call to `concatMap`, which " +"concatenates all of the recursive results." msgstr "" "逆向きの矢印は配列から要素を選択するのに相当することを思い出してください。\n" "最初の工程は引数の直接の子から要素を選択することです。\n" -"それから、単にそのファイルに対してこの再帰関数を呼びします。\n" -"do記法を使用しているので、再帰的な結果を全て連結する`concatMap`が暗黙に呼び出" -"されています。" +"それからそのファイルに対して再帰関数を呼び出します。\n" +"do記法を使用しているので`concatMap`が暗黙に呼び出されています。\n" +"この関数は再帰的な結果を全て連結します。" #. type: Plain text #: text/chapter4.md:608 @@ -18686,11 +18825,12 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}}\n" #. type: Plain text #: text/chapter4.md:614 msgid "" -"Try out the new version in PSCi - you should get the same result. I'll let " +"Try out the new version in PSCi – you should get the same result. I'll let " "you decide which version you find clearer." msgstr "" -"PSCiで新しいコードを試してみてください。同じ結果が返ってくるはずです。どちら" -"のほうがわかりやすいかの選定はお任せします。" +"PSCiで新しいコードを試してみてください。\n" +"同じ結果が返ってくるはずです。\n" +"どちらのほうがわかりやすいかの選定はお任せします。" #. type: Bullet: ' 1. ' #: text/chapter4.md:619 @@ -18743,29 +18883,28 @@ msgstr "" #, no-wrap msgid "" " _Hint_: Try to write this function as an array comprehension using do notation.\n" -" 3. (Difficult) Write a function `largestSmallest` which takes a `Path` and returns an array containing the single largest and single smallest files in the `Path`. _Note_: consider the cases where there are zero or one files in the `Path` by returning an empty array or a one-element array respectively.\n" +" 3. (Difficult) Write a function `largestSmallest` which takes a `Path` and returns an array containing the single largest and single smallest files in the `Path`. _Note_: consider the cases where there are zero or one files in the `Path` by returning an empty or one-element array, respectively.\n" msgstr "" " *手掛かり*:この関数をdo記法を使った配列内包表記で書いてみましょう。\n" -" 3. (難しい)`Path`を取って`Path`に最大のファイルと最小のファイルを1つずつ含む配列を返す関数`largestSmallest`を書いてください。\n" -" *補足*:空配列や1要素の配列を返すことで、`Path`にゼロか1個のファイルがある場合についても考慮してください。\n" +" 3. (難しい)`Path`中の最大のファイルと最小のファイルを1つずつ含む配列を返す関数`largestSmallest`を書いてください。\n" +" *補足*:空配列や1要素の配列を返すことで、`Path`にそれぞれゼロか1個のファイルがある場合についても考慮してください。\n" #. type: Plain text #: text/chapter4.md:633 msgid "" -"In this chapter, we covered the basics of recursion in PureScript, as a " -"means of expressing algorithms concisely. We also introduced user-defined " -"infix operators, standard functions on arrays such as maps, filters and " -"folds, and array comprehensions which combine these ideas. Finally, we " -"showed the importance of using tail recursion in order to avoid stack " -"overflow errors, and how to use accumulator parameters to convert functions " -"to tail recursive form." +"In this chapter, we covered the basics of recursion in PureScript to express " +"algorithms concisely. We also introduced user-defined infix operators, " +"standard functions on arrays such as maps, filters, and folds, and array " +"comprehensions that combine these ideas. Finally, we showed the importance " +"of using tail recursion to avoid stack overflow errors and how to use " +"accumulator parameters to convert functions to tail recursive form." msgstr "" -"この章では、アルゴリズムを簡潔に表現する手段として、PureScriptでの再帰の基本" -"を説明しました。\n" +"この章ではアルゴリズムを簡潔に表現するためにPureScriptでの再帰の基本を押さえ" +"ました。\n" "また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関" "数、及びこれらの概念を組み合わせた配列内包表記を導入しました。\n" "最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの" -"重要性、累積器引数を使用して末尾再帰形に関数を変換する方法を示しました。" +"重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。" #. type: Title # #: text/chapter5.md:1 @@ -18776,11 +18915,12 @@ msgstr "パターン照合" #. type: Plain text #: text/chapter5.md:6 msgid "" -"This chapter will introduce two new concepts: algebraic data types, and " +"This chapter will introduce two new concepts: algebraic data types and " "pattern matching. We will also briefly cover an interesting feature of the " "PureScript type system: row polymorphism." msgstr "" -"この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。" +"この章では、代数的データ型とパターン照合という、2つの新しい概念を導入しま" +"す。\n" "また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱" "います。" @@ -18788,31 +18928,33 @@ msgstr "" #: text/chapter5.md:8 msgid "" "Pattern matching is a common technique in functional programming and allows " -"the developer to write compact functions which express potentially complex " -"ideas, by breaking their implementation down into multiple cases." +"the developer to write compact functions, which express potentially complex " +"ideas by breaking their implementation down into multiple cases." msgstr "" -"パターン照合は関数型プログラミングにおける一般的な手法で、複数の場合に実装を" -"分解することにより、開発者は水面下では複雑な動作をする関数を簡潔に書くことが" -"できます。" +"パターン照合は関数型プログラミングにおける一般的な手法であり、開発者が簡潔に" +"関数を書けるようになります。\n" +"関数の実装を複数の場合に分解することにより、水面下の複雑なアイディアが表現さ" +"れるのです。" #. type: Plain text #: text/chapter5.md:10 msgid "" -"Algebraic data types are a feature of the PureScript type system which " -"enable a similar level of expressiveness in the language of types - they are " -"closely related to pattern matching." +"Algebraic data types are a feature of the PureScript type system, which " +"enables a similar level of expressiveness in the language of types – they " +"are closely related to pattern matching." msgstr "" "代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等" -"の水準の表現力を可能にしています。パターン照合とも密接に関連しています。" +"の水準の表現力を可能にしています。\n" +"パターン照合とも密接に関連しています。" #. type: Plain text #: text/chapter5.md:12 msgid "" -"The goal of the chapter will be to write a library to describe and " -"manipulate simple vector graphics using algebraic types and pattern matching." +"The chapter's goal will be to write a library to describe and manipulate " +"simple vector graphics using algebraic types and pattern matching." msgstr "" "この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラ" -"フィックスを描画し操作するためのライブラリを書くことです。" +"フィックスを記述し操作するためのライブラリを書くことです。" #. type: Plain text #: text/chapter5.md:16 @@ -18825,12 +18967,13 @@ msgstr "" #. type: Plain text #: text/chapter5.md:18 msgid "" -"The `Data.Picture` module defines a data type `Shape` for simple shapes, and " +"The `Data.Picture` module defines a data type `Shape` for simple shapes and " "a type `Picture` for collections of shapes, along with functions for working " "with those types." msgstr "" -"`Data.Picture`モジュールは、簡単な図形を表すデータ型 `Shape`や、図形の集合で" -"ある型 `Picture`、及びこれらの型を扱うための関数を定義しています。" +"`Data.Picture`モジュールは簡単な図形を表すデータ型`Shape`やその図形の集合であ" +"る型`Picture`を定義します。\n" +"また、これらの型を扱うための関数もあります。" #. type: Plain text #: text/chapter5.md:20 @@ -18838,8 +18981,8 @@ msgid "" "The module imports the `Data.Foldable` module, which provides functions for " "folding data structures:" msgstr "" -"このモジュールでは、データ構造の畳込みを行う関数を提供する `Data.Foldable`モ" -"ジュールもインポートします。" +"このモジュールでは、データ構造を畳込む関数を提供する`Data.Foldable`モジュール" +"もインポートします。" #. type: Fenced code block (haskell) #: text/chapter5.md:21 @@ -18867,23 +19010,21 @@ msgstr "{{#include ../exercises/chapter5/src/Data/Picture.purs:picture_import_as msgid "" "This makes the types and functions in that module available for use, but " "only by using the _qualified name_, like `Number.max`. This can be useful to " -"avoid overlapping imports, or just to make it clearer which modules certain " -"things are imported from." +"avoid overlapping imports or clarify which modules certain things are " +"imported from." msgstr "" -"こうすると型や関数をモジュール内で使用できるようになりますが、`Number.max`の" -"ように*修飾名*を使ったときに限定されます。重複したインポートを避けたり、どの" -"モジュールからインポートされたのかを明らかにするのに役立ちます。" +"こうすると型や関数をモジュール内で使用できるようになりますが、\n" +"`Number.max`のように*修飾名*を使ったときに限定されます。\n" +"重複したインポートを避けたり、どのモジュールからインポートされたのかを明らか" +"にするのに役立ちます。" #. type: Plain text #: text/chapter5.md:34 -msgid "" -"_Note_: it is not necessary to use the same module name as the original " -"module for a qualified import. Shorter qualified names like `import Data." -"Number as N` are possible, and quite common." +#, no-wrap +msgid "> _Note_: Using the same module name as the original module for a qualified import is unnecessary – shorter qualified names like `import Data.Number as N` are possible and quite common.\n" msgstr "" -"*補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありませ" -"ん。\n" -"`import Math as M`などのより短い名前にできますし、かなりよく見掛けます。" +"> *補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありません。\n" +"> `import Math as M`などのより短い名前にできますし、かなりよく見掛けます。\n" #. type: Title ## #: text/chapter5.md:35 @@ -18894,10 +19035,10 @@ msgstr "単純なパターン照合" #. type: Plain text #: text/chapter5.md:38 msgid "" -"Let's begin by looking at an example. Here is a function which computes the " +"Let's begin by looking at an example. Here is a function that computes the " "greatest common divisor of two integers using pattern matching:" msgstr "" -"それではコード例を見ることから始めましょう。\n" +"例を見ることから始めましょう。\n" "パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになりま" "す。" @@ -18911,16 +19052,16 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcd}}\n" #: text/chapter5.md:44 msgid "" "This algorithm is called the Euclidean Algorithm. If you search for its " -"definition online, you will likely find a set of mathematical equations " -"which look a lot like the code above. This is one benefit of pattern " -"matching: it allows you to define code by cases, writing simple, declarative " -"code which looks like a specification of a mathematical function." +"definition online, you will likely find a set of mathematical equations that " +"look like the code above. One benefit of pattern matching is that it allows " +"you to define code by cases, writing simple, declarative code that looks " +"like a mathematical function specification." msgstr "" "このアルゴリズムはユークリッドの互除法と呼ばれています。\n" "その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が" "見つかるでしょう。\n" -"パターン照合の利点の1つは、上記のようにコードを場合分けして定義でき、数学関数" -"の定義と似たような簡潔で宣言型なコードを書くことができることです。" +"パターン照合の利点の1つは、コードを場合分けして定義でき、数学関数の仕様に似た" +"単純で宣言型なコードを定義できることです。" #. type: Plain text #: text/chapter5.md:46 @@ -18928,7 +19069,7 @@ msgid "" "A function written using pattern matching works by pairing sets of " "conditions with their results. Each line is called an _alternative_ or a " "_case_. The expressions on the left of the equals sign are called " -"_patterns_, and each case consists of one or more patterns, separated by " +"_patterns_, and each case consists of one or more patterns separated by " "spaces. Cases describe which conditions the arguments must satisfy before " "the expression on the right of the equals sign should be evaluated and " "returned. Each case is tried in order, and the first case whose patterns " @@ -18941,8 +19082,8 @@ msgstr "" "以上のパターンで構成されています。\n" "場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなけれ" "ばならない条件を表現しています。\n" -"それぞれの場合は上からこの順番に試されていき、最初に入力に適合した場合が返り" -"値を決定します。" +"それぞれの場合は上からこの順番に試されていき、最初にパターンが入力に照合した" +"場合が返り値を決定します。" #. type: Plain text #: text/chapter5.md:48 @@ -18977,16 +19118,16 @@ msgstr "それ以外の場合、関数は最後の行の式を評価して返し #. type: Plain text #: text/chapter5.md:54 msgid "" -"Note that patterns can bind values to names - each line in the example binds " +"Note that patterns can bind values to names – each line in the example binds " "one or both of the names `n` and `m` to the input values. As we learn about " -"different kinds of patterns, we will see that different types of patterns " -"correspond to different ways to choose names from the input arguments." +"different patterns, we will see that different patterns correspond to " +"different ways to choose names from the input arguments." msgstr "" "なお、パターンでは値を名前に束縛できます。\n" "この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛して" "います。\n" -"さまざまな種類のパターンについて学んでいくうちに、それぞれの種類のパターンが" -"入力の引数から名前を選ぶさまざまな方法に対応することがわかるでしょう。" +"様々な種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力" +"の引数から名前を選ぶ様々な方法に対応することがわかるでしょう。" #. type: Title ## #: text/chapter5.md:55 @@ -19004,7 +19145,7 @@ msgstr "上記のコード例では、2種類のパターンを示しました msgid "" "Integer literals patterns, which match something of type `Int`, only if the " "value matches exactly." -msgstr "`Int`型の値が正確に一致する場合にのみ適合する、整数直値パターン" +msgstr "`Int`型の値が正確に一致する場合にのみ照合する、整数直値パターン" #. type: Bullet: '- ' #: text/chapter5.md:61 @@ -19018,23 +19159,23 @@ msgstr "単純なパターンには他にも種類があります。" #. type: Bullet: '- ' #: text/chapter5.md:66 -msgid "`Number`, `String`, `Char` and `Boolean` literals" +msgid "`Number`, `String`, `Char`, and `Boolean` literals" msgstr "`Number`、`String`、`Char`、そして`Boolean`といった直値" #. type: Bullet: '- ' #: text/chapter5.md:66 msgid "" -"Wildcard patterns, indicated with an underscore (`_`), which match any " -"argument, and which do not bind any names." +"Wildcard patterns, indicated with an underscore (`_`), match any argument " +"and do not bind any names." msgstr "" -"どんな引数とも適合するが名前に束縛はしない、アンダースコア (`_`) で表されるワ" +"どんな引数とも照合するが名前に束縛はしない、アンダースコア (`_`) で表されるワ" "イルドカードパターン" #. type: Plain text #: text/chapter5.md:68 msgid "" -"Here are two more examples which demonstrate using these simple patterns:" -msgstr "ここではこれらの単純なパターンを使用して、もう2つ例を示します。" +"Here are two more examples that demonstrate using these simple patterns:" +msgstr "これらの単純なパターンを使用する実演として、もう2つの例が以下です。" #. type: Fenced code block (haskell) #: text/chapter5.md:69 @@ -19056,18 +19197,21 @@ msgstr "PSCiでこれらの関数を試してみてください。" #. type: Plain text #: text/chapter5.md:80 #, no-wrap -msgid "In the Euclidean algorithm example, we used an `if .. then .. else` expression to switch between the two alternatives when `m > n` and `m <= n`. Another option in this case would be to use a _guard_.\n" -msgstr "ユークリッドの互除法の例では、`m > n`のときと `m <= n`のときの2つに分岐するために `if .. then .. else`式を使っていました。こういうときには他に _ガード_ (guard) を使うという選択肢もあります。\n" +msgid "In the Euclidean algorithm example, we used an `if .. then .. else` expression to switch between the two alternatives when `m > n` and `m <= n`. Another option, in this case, would be to use a _guard_.\n" +msgstr "" +"ユークリッドの互除法の例では、`m > n`のときと`m <= n`のときの2つの選択肢の間を切り替えるために`if .. then .. else`式を使いました。\n" +"こういうときには*ガード*を使うという他の選択肢もあります。\n" #. type: Plain text #: text/chapter5.md:82 msgid "" -"A guard is a boolean-valued expression which must be satisfied in addition " -"to the constraints imposed by the patterns. Here is the Euclidean algorithm " +"A guard is a boolean-valued expression that must be satisfied in addition to " +"the constraints imposed by the patterns. Here is the Euclidean algorithm " "rewritten to use a guard:" msgstr "" -"ガードはパターンによる制約に加えて満たされなくてはいけない真偽値の式です。\n" -"ガードを使用してユークリッドの互除法を書き直すと、次のようになります。" +"ガードとは、パターンにより課された制約に加えて満たされなくてはいけない真偽値" +"の式です。\n" +"ガードを使用してユークリッドのアルゴリズムを書き直すと、次のようになります。" #. type: Fenced code block (haskell) #: text/chapter5.md:83 @@ -19080,12 +19224,14 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcdV2}}\n" msgid "" "In this case, the third line uses a guard to impose the extra condition that " "the first argument is strictly larger than the second. The guard in the " -"final line uses the expression `otherwise`, which might seem like a keyword, " -"but is in fact just a regular binding in `Prelude`:" +"final line uses the expression `otherwise`, which might seem like a keyword " +"but is, in fact, just a regular binding in `Prelude`:" msgstr "" "この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいと" -"いう条件を付け加えています。最後の行でのガードは式`otherwise`を使っており、" -"キーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。" +"いう条件を課しています。\n" +"最後の行でのガードは式`otherwise`を使っています。\n" +"これはキーワードのようにも見えますが、実際はただの`Prelude`にある普通の束縛で" +"す。" #. type: Fenced code block (text) #: text/chapter5.md:89 @@ -19106,7 +19252,7 @@ msgstr "" #. type: Plain text #: text/chapter5.md:98 msgid "" -"As this example demonstrates, guards appear on the left of the equals " +"This example demonstrates that guards appear on the left of the equals " "symbol, separated from the list of patterns by a pipe character (`|`)." msgstr "" "この例が示すように、ガードは等号の左側に現れ、パイプ文字 (`|`) でパターンのリ" @@ -19143,8 +19289,8 @@ msgstr "" "数式\\\\( n! / k! (n - k)! \\\\)を使ってください。\n" "ここで \\\\( ! \\\\) は前に書いた階乗関数です。\n" "*手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。\n" -"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、もっと使" -"用例を追加してみてください。" +"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、特殊な場" +"合を更に追加してみてください。" #. type: Bullet: '1. ' #: text/chapter5.md:104 @@ -19183,10 +19329,10 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}}\n" #. type: Plain text #: text/chapter5.md:114 msgid "" -"Here is another function which matches arrays of length five, binding each " -"of its five elements in a different way:" +"Here is another function that matches arrays of length five, binding each of " +"its five elements differently:" msgstr "" -"次の関数では、長さ5の配列と適合し、配列の5つの要素をそれぞれ違った方法で束縛" +"次の関数では、長さ5の配列と照合し、配列の5つの要素をそれぞれ違った方法で束縛" "しています。" #. type: Fenced code block (haskell) @@ -19199,12 +19345,12 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:takeFive}}\n" #: text/chapter5.md:120 msgid "" "The first pattern only matches arrays with five elements, whose first and " -"second elements are 0 and 1 respectively. In that case, the function returns " -"the product of the third and fourth elements. In every other case, the " -"function returns zero. For example, in PSCi:" +"second elements are 0 and 1, respectively. In that case, the function " +"returns the product of the third and fourth elements. In every other case, " +"the function returns zero. For example, in PSCi:" msgstr "" "最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にの" -"み適合します。\n" +"み照合します。\n" "その場合、関数は第3要素と第4要素の積を返します。\n" "それ以外の場合は、関数は0を返します。\n" "例えばPSCiで試してみると次のようになります。" @@ -19244,18 +19390,19 @@ msgstr "" #. type: Plain text #: text/chapter5.md:138 msgid "" -"Array literal patterns allow us to match arrays of a fixed length, but " +"Array literal patterns allow us to match arrays of a fixed length. Still, " "PureScript does _not_ provide any means of matching arrays of an unspecified " -"length, since destructuring immutable arrays in these sorts of ways can lead " -"to poor performance. If you need a data structure which supports this sort " -"of matching, the recommended approach is to use `Data.List`. Other data " +"length since destructuring immutable arrays in these sorts of ways can lead " +"to poor performance. If you need a data structure that supports this sort of " +"matching, the recommended approach is to use `Data.List`. Other data " "structures exist which provide improved asymptotic performance for different " "operations." msgstr "" -"配列の直値パターンでは、固定長の配列と一致させることはできますが、PureScript" -"は不特定の長さの配列を照合させる手段を提供していません。\n" -"そのような方法で不変な配列を分解すると、実行速度が低下する可能性があるためで" -"す。\n" +"配列の直値パターンでは、固定長の配列と一致させることはできます。\n" +"しかしPureScriptは不特定の長さの配列を照合させる手段は全く提供して*いません" +"*。\n" +"そのような類の方法で不変な配列を分解すると、実行速度が低下する可能性があるた" +"めです。\n" "このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めし" "ます。\n" "その他の操作について、より優れた漸近性能を提供するデータ構造も存在します。" @@ -19268,7 +19415,7 @@ msgstr "レコードパターンと行多相" #. type: Plain text #: text/chapter5.md:142 -msgid "_Record patterns_ are used to match - you guessed it - records." +msgid "_Record patterns_ are used to match – you guessed it – records." msgstr "*レコードパターン*は(ご想像の通り)レコードに照合します。" #. type: Plain text @@ -19283,8 +19430,8 @@ msgstr "" #. type: Plain text #: text/chapter5.md:146 msgid "" -"For example: this pattern matches any record which contains fields called " -"`first` and `last`, and binds their values to the names `x` and `y` " +"For example, this pattern matches any record which contains fields called " +"`first` and `last`, and binds their values to the names `x` and `y`, " "respectively:" msgstr "" "例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレ" @@ -19318,12 +19465,12 @@ msgid "" "> showPerson { first: x, last: y } = y <> \", \" <> x\n" "\n" "> :type showPerson\n" -"forall r. { first :: String, last :: String | r } -> String\n" +"forall (r :: Row Type). { first :: String, last :: String | r } -> String\n" msgstr "" "> showPerson { first: x, last: y } = y <> \", \" <> x\n" "\n" "> :type showPerson\n" -"forall r. { first :: String, last :: String | r } -> String\n" +"forall (r :: Row Type). { first :: String, last :: String | r } -> String\n" #. type: Plain text #: text/chapter5.md:161 @@ -19353,15 +19500,17 @@ msgstr "" #. type: Plain text #: text/chapter5.md:171 msgid "" -"We are able to append additional fields to the record, and the `showPerson` " -"function will still work. As long as the record contains the `first` and " -"`last` fields of type `String`, the function application is well-typed. " -"However, it is _not_ valid to call `showPerson` with too _few_ fields:" +"We can append additional fields to the record, and the `showPerson` function " +"will still work. As long as the record contains the `first` and `last` " +"fields of type `String`, the function application is well-typed. However, it " +"is _not_ valid to call `showPerson` with too _few_ fields:" msgstr "" "レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま" -"動作するのです。レコードに少なくとも型が`String`であるようなフィールド " -"`first`と `last`が含まれていれば、関数適用は正しく型付けされます。しかし、" -"フィールドが _不足_ していると、 `showPerson`の呼び出しは _不正_ となります。" +"動作するのです。\n" +"レコードに少なくとも型が`String`であるようなフィールド`first`と`last`が含まれ" +"ていれば、関数適用は正しく型付けされます。\n" +"しかし、フィールドが*不足*していると、`showPerson`の呼び出しは*不正*となりま" +"す。" #. type: Fenced code block (text) #: text/chapter5.md:172 @@ -19405,8 +19554,8 @@ msgstr "> showPerson p = p.last <> \", \" <> p.first\n" #. type: Plain text #: text/chapter5.md:187 -msgid "and PSCi would have inferred the same type." -msgstr "この場合も、 PSCiは先ほどと同じ型を推論するでしょう。" +msgid "And PSCi would have inferred the same type." +msgstr "そしてPSCiは同じ型を推論することでしょう。" #. type: Title ## #: text/chapter5.md:188 @@ -19419,12 +19568,13 @@ msgstr "レコード同名利用" msgid "" "Recall that the `showPerson` function matches a record inside its argument, " "binding the `first` and `last` fields to values named `x` and `y`. We could " -"alternatively just reuse the field names themselves, and simplify this sort " -"of pattern match as follows:" +"alternatively reuse the field names themselves and simplify this sort of " +"pattern match as follows:" msgstr "" -"`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と " -"`y`という名前の値に束縛していたのでした。別の方法として、フィールド名自体を再" -"利用するだけで、このようなパターン照合を次のように単純化できます。" +"`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と" +"`y`という名前の値に束縛していたのでした。\n" +"別の方法として、フィールド名自体を再利用してこのような類のパターン照合を次の" +"ように単純化できます。" #. type: Fenced code block (haskell) #: text/chapter5.md:192 @@ -19460,8 +19610,8 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:unknownPerson} #. type: Plain text #: text/chapter5.md:205 -msgid "This may improve readability of code in some circumstances." -msgstr "こうすると、状況によってはコードの可読性向上に役立ちます。" +msgid "This may improve the readability of code in some circumstances." +msgstr "こうすると、状況によってはコードの可読性が向上します。" #. type: Title ## #: text/chapter5.md:206 @@ -19474,16 +19624,16 @@ msgstr "入れ子になったパターン" msgid "" "Array patterns and record patterns both combine smaller patterns to build " "larger patterns. For the most part, the examples above have only used simple " -"patterns inside array patterns and record patterns, but it is important to " -"note that patterns can be arbitrarily _nested_, which allows functions to be " -"defined using conditions on potentially complex data types." +"patterns inside array patterns and record patterns. Still, it is important " +"to note that patterns can be arbitrarily _nested_, which allows functions to " +"be defined using conditions on potentially complex data types." msgstr "" "配列パターンとレコードパターンはどちらも小さなパターンを組み合わせることで大" -"きなパターンを構成しています。これまでの例ではほとんどの場合で配列パターンと" -"レコードパターンの内部に単純なパターンを使用していましたが、パターンを自由に*" -"入れ子*にできることも知っておくのが大切です。入れ子になったパターンを使うと、" -"潜在的に複雑なデータ型に対して条件分岐を用いて関数を定義できるようになりま" -"す。" +"きなパターンを構築しています。\n" +"これまでのほとんどの例では配列パターンとレコードパターンの内部で単純なパター" +"ンを使用していました。\n" +"しかし特筆すべきこととして、パターンは自由に*入れ子*にできます。\n" +"これにより潜在的に複雑なデータ型についての条件を使って関数を定義できます。" #. type: Plain text #: text/chapter5.md:211 @@ -19532,12 +19682,12 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}}\n" msgid "" "This way, we save ourselves from allocating a new array if the pair is " "already sorted. Note that if the input array does not contain _exactly_ two " -"elements, then this function simply returns it unchanged, even if it's " -"unsorted." +"elements, then this function returns it unchanged, even if it's unsorted." msgstr "" "このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みま" -"す。なおもし入力の配列が _厳密に_ 2つの要素を含んでいなければ、たとえ整列され" -"ていなかったとしても、この関数は単に元のまま変えずに返しています。" +"す。\n" +"なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されてい" +"なかったとしても、この関数は単に元のまま変えずに返します。" #. type: Bullet: '1. ' #: text/chapter5.md:233 @@ -19551,8 +19701,8 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:233 msgid "" -"(Medium) What is the most general type of the `sameCity` function, taking " -"into account row polymorphism? What about the `livesInLA` function defined " +"(Medium) What is the most general type of the `sameCity` function, " +"considering row polymorphism? What about the `livesInLA` function defined " "above? _Note_: There is no test for this exercise." msgstr "" "(普通)行多相を考慮すると、 `sameCity`関数の最も一般的な型は何でしょうか。\n" @@ -19562,42 +19712,42 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:233 msgid "" -"(Medium) Write a function `fromSingleton` which uses an array literal " -"pattern to extract the sole member of a singleton array. If the array is not " -"a singleton, your function should return a provided default value. Your " +"(Medium) Write a function `fromSingleton` that uses an array literal pattern " +"to extract the sole member of a singleton array. If the array is not a " +"singleton, your function should return a provided default value. Your " "function should have type `forall a. a -> Array a -> a`" msgstr "" "(普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数" -"`fromSingleton`を書いてみましょう。1要素だけを持つ配列でない場合、関数は指定" -"された既定値を返します。この関数は `forall a. a -> Array a -> a`という型を" -"持っています。" +"`fromSingleton`を書いてみましょう。\n" +"1要素だけを持つ配列でない場合、関数は与えられた既定値を返します。\n" +"この関数は`forall a. a -> Array a -> a`という型を持ちます。" #. type: Title ## #: text/chapter5.md:234 #, no-wrap msgid "Case Expressions" -msgstr "Case式" +msgstr "case式" #. type: Plain text #: text/chapter5.md:237 msgid "" "Patterns do not only appear in top-level function declarations. It is " -"possible to use patterns to match on an intermediate value in a computation, " +"possible to use patterns to match on an intermediate value in a computation " "using a `case` expression. Case expressions provide a similar type of " "utility to anonymous functions: it is not always desirable to give a name to " "a function, and a `case` expression allows us to avoid naming a function " "just because we want to use a pattern." msgstr "" -"パターンは最上位にある関数宣言だけに現れるわけではありません。`case`式を使っ" -"て計算の途中の値に対してパターン照合を使うことができます。case式には無名関数" -"に似たような便利さがあります。関数に名前を与えることがいつも望ましいわけでは" -"ないように、パターン照合を使いたいためだけに関数に名前をつけるようなことを避" -"けられるようになります。" +"パターンが現れるのは最上位にある関数宣言だけではありません。\n" +"`case`式を使う計算中の途中の値に対してパターン照合を使えます。\n" +"case式には無名関数に似た便利さがあります。\n" +"関数に名前を与えることがいつも望ましいわけではないように、パターンを使いたい" +"ためだけに関数に名前をつけるようなことを避けられるようになります。" #. type: Plain text #: text/chapter5.md:239 msgid "" -"Here is an example. This function computes \"longest zero suffix\" of an " +"Here is an example. This function computes the \"longest zero suffix\" of an " "array (the longest suffix which sums to zero):" msgstr "" "例を示しましょう。\n" @@ -19637,13 +19787,14 @@ msgstr "" msgid "" "This function works by case analysis. If the array is empty, our only option " "is to return an empty array. If the array is non-empty, we first use a " -"`case` expression to split into two cases. If the sum of the array is zero, " -"we return the whole array. If not, we recurse on the tail of the array." +"`case` expression to split it into two cases. If the sum of the array is " +"zero, we return the whole array. If not, we recurse on the tail of the array." msgstr "" -"この関数は場合ごとの分析によって動作します。もし配列が空なら、唯一の選択肢は" -"空の配列を返すことです。配列が空でない場合は、更に2つの場合に分けるためにま" -"ず `case`式を使用します。配列の合計がゼロであれば、配列全体を返します。そうで" -"なければ、配列の残りに対して再帰します。" +"この関数は場合毎の分析によって動作します。\n" +"もし配列が空なら、唯一の選択肢は空の配列を返すことです。\n" +"配列が空でない場合は、更に2つの場合に分けるためにまず`case`式を使用します。\n" +"配列の合計がゼロであれば、配列全体を返します。\n" +"そうでなければ、配列の残りに対して再帰します。" #. type: Title ## #: text/chapter5.md:258 @@ -19654,13 +19805,12 @@ msgstr "パターン照合の失敗と部分関数" #. type: Plain text #: text/chapter5.md:261 msgid "" -"If patterns in a case expression are tried in order, then what happens in " -"the case when none of the patterns in a case alternatives match their " -"inputs? In this case, the case expression will fail at runtime with a " -"_pattern match failure_." +"If patterns in a case expression are tried in order, what happens when none " +"of the patterns in a case alternatives match their inputs? In this case, the " +"case expression will fail at runtime with a _pattern match failure_." msgstr "" -"case式のパターンを順番に照合していって、もし選択肢の何れの場合も入力が適合し" -"なかった時は何が起こるのでしょうか。\n" +"case式のパターンを順番に照合していって、どの選択肢の場合も入力が照合しなかっ" +"た時はどうなるのでしょう。\n" "この場合、*パターン照合失敗*によって、case式は実行時に失敗します。" #. type: Plain text @@ -19684,12 +19834,13 @@ msgstr "" #: text/chapter5.md:271 msgid "" "This function contains only a single case, which only matches a single " -"input, `true`. If we compile this file, and test in PSCi with any other " +"input, `true`. If we compile this file and test in PSCi with any other " "argument, we will see an error at runtime:" msgstr "" -"この関数は単一の場合しか含んでおらず、単一の入力である`true`にのみ照合しま" -"す。このファイルをコンパイルしてPSCiでそれ以外の値を与えてテストすると、実行" -"時エラーが発生します。" +"この関数は単一の場合しか含んでいません。\n" +"そしてその場合は単一の入力である`true`にのみ照合します。\n" +"このファイルをコンパイルしてPSCiでそれ以外の値を与えて試すと実行時エラーが発" +"生します。" #. type: Fenced code block (text) #: text/chapter5.md:272 @@ -19706,11 +19857,11 @@ msgstr "" #. type: Plain text #: text/chapter5.md:279 msgid "" -"Functions which return a value for any combination of inputs are called " -"_total_ functions, and functions which do not are called _partial_." +"Functions that return a value for any combination of inputs are called " +"_total_ functions, and functions that do not are called _partial_." msgstr "" -"どんな入力の組み合わせに対しても値を返すような関数は _全関数_ (total " -"function) と呼ばれ、そうでない関数は _部分的_ (partial) であると呼ばれます。" +"どんな入力の組み合わせに対しても値を返すような関数は*全関数*と呼ばれ、そうで" +"ない関数は*部分的*であると呼ばれます。" #. type: Plain text #: text/chapter5.md:281 @@ -19735,16 +19886,16 @@ msgid "" "The PureScript compiler will generate an error if it can detect that your " "function is not total due to an incomplete pattern match. The " "`unsafePartial` function can be used to silence these errors (if you are " -"sure that your partial function is safe!) If we removed the call to the " +"sure your partial function is safe!) If we removed the call to the " "`unsafePartial` function above, then the compiler would generate the " "following error:" msgstr "" -"PureScriptコンパイラは、パターンマッチが不完全で関数が全関数ではないことを検" -"出するとエラーを生成します。\n" -"部分関数が安全である場合、`unsafePartial`関数を使ってこれらのエラーを抑制でき" -"ます(その部分関数が安全だと言い切れるなら)。\n" -"もし上記の `unsafePartial`関数の呼び出しを取り除くと、コンパイラは次のエラー" -"を生成します。" +"PureScriptコンパイラは、パターン照合が不完全であるために関数が全関数ではない" +"ことが検出されると、エラーを出します。\n" +"`unsafePartial`関数を使うとこうしたエラーを抑制できます(ただしその部分関数が" +"安全だと言い切れるなら)。\n" +"もし上記の`unsafePartial`関数の呼び出しを取り除くと、コンパイラは次のエラーを" +"出します。" #. type: Fenced code block (text) #: text/chapter5.md:284 @@ -19800,18 +19951,20 @@ msgstr "" #. type: Plain text #: text/chapter5.md:308 #, no-wrap -msgid "We will see more types which involve the `=>` symbol later on in the book (they are related to _type classes_), but for now, it suffices to observe that PureScript keeps track of partial functions using the type system, and that we must explicitly tell the type checker when they are safe.\n" -msgstr "本書ではのちに`=>`記号を含むいろいろな型を見ることになります(これらは*型クラス*に関連しています)。しかし、今のところは、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。\n" +msgid "We will see more types that involve the `=>` symbol later on in the book (they are related to _type classes_), but for now, it suffices to observe that PureScript keeps track of partial functions using the type system and that we must explicitly tell the type checker when they are safe.\n" +msgstr "" +"本書では以降、`=>`記号が絡む(*型クラス*に関連する)型をもっと見ていきます。\n" +"しかし現時点では、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。\n" #. type: Plain text #: text/chapter5.md:310 msgid "" "The compiler will also generate a warning in certain cases when it can " "detect that cases are _redundant_ (that is, a case only matches values which " -"would have been matched by a prior case):" +"a prior case would have matched):" msgstr "" -"コンパイラは、定義されたパターンが _冗長_ であることを検出した場合(前の方に" -"定義されたパターンのみに一致する場合)でも警告を生成します。" +"コンパイラは、*冗長*な場合を検出したとき(つまり、その場合より前の方に定義さ" +"れた場合にのみ一致するとき)などにも警告を出します。" #. type: Fenced code block (haskell) #: text/chapter5.md:311 @@ -19846,12 +19999,11 @@ msgstr "" #. type: Plain text #: text/chapter5.md:327 -msgid "" -"_Note_: PSCi does not show warnings, so to reproduce this example, you will " -"need to save this function as a file and compile it using `spago build`." +#, no-wrap +msgid "> _Note_: PSCi does not show warnings, so to reproduce this example, you will need to save this function as a file and compile it using `spago build`.\n" msgstr "" -"*補足*:PSCiは警告を表示しないので、この例を再現するには、この関数をファイル" -"として保存し、 `pulp build`を使ってコンパイルします。" +"> *補足*:PSCiは警告を表示しません。\n" +"> そのため、この例を再現するには、この関数をファイルとして保存し、`spago build`を使ってコンパイルします。\n" #. type: Title ## #: text/chapter5.md:328 @@ -19898,24 +20050,25 @@ msgstr "" msgid "" "However, this approach has one major drawback: to work with `Shape`s " "abstractly, it is necessary to identify all of the operations one might wish " -"to perform, and to define them on the `Shape` interface. It becomes " -"difficult to add new operations without breaking modularity." +"to perform and to define them on the `Shape` interface. It becomes difficult " +"to add new operations without breaking modularity." msgstr "" "しかし、この方針は大きな欠点を1つ抱えています。\n" "`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に" "把握し、`Shape`インターフェースに定義する必要があるのです。\n" -"このため、モジュール性を壊さずに新しい操作を追加することが難しくなります。" +"モジュール性を壊さずに新しい操作を追加することが難しくなります。" #. type: Plain text #: text/chapter5.md:339 msgid "" -"Algebraic data types provide a type-safe way to solve this sort of problem, " -"if the set of shapes is known in advance. It is possible to define new " -"operations on `Shape` in a modular way, and still maintain type-safety." +"Algebraic data types provide a type-safe way to solve this problem if the " +"set of shapes is known in advance. It is possible to define new operations " +"on `Shape` in a modular way and still maintain type-safety." msgstr "" "もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決す" -"る型安全な方法を提供します。モジュール性のある方法で `Shape`に新たな操作を定" -"義し、型安全性を維持できます。" +"る型安全な方法を提供します。\n" +"モジュール性のある方法で `Shape`に新たな操作を定義しつつ、型安全性を維持でき" +"ます。" #. type: Plain text #: text/chapter5.md:341 @@ -19938,8 +20091,8 @@ msgstr "" #: text/chapter5.md:349 msgid "" "This declaration defines `Shape` as a sum of different constructors, and for " -"each constructor identifies the data that is included. A `Shape` is either a " -"`Circle` which contains a center `Point` and a radius (a number), or a " +"each constructor identifies the included data. A `Shape` is either a " +"`Circle` that contains a center `Point` and a radius (a number), or a " "`Rectangle`, or a `Line`, or `Text`. There are no other ways to construct a " "value of type `Shape`." msgstr "" @@ -19949,21 +20102,23 @@ msgstr "" "`Line`、 `Text`の何れかです。\n" "他に`Shape`型の値を構築する方法はありません。" +# 頭字語のADTの意味が分かるような註釈は必要です。 #. type: Plain text #: text/chapter5.md:351 msgid "" "An algebraic data type is introduced using the `data` keyword, followed by " "the name of the new type and any type arguments. The type's constructors (i." -"e. its _data constructors_) are defined after the equals symbol, and are " +"e., its _data constructors_) are defined after the equals symbol and " "separated by pipe characters (`|`). The data carried by an ADT's " "constructors doesn't have to be restricted to primitive types: constructors " "can include records, arrays, or even other ADTs." msgstr "" -"代数的データ型の定義はキーワード `data`から始まり、それに新しい型の名前と任意" -"個の型引数が続きます。その型の構築子(あるいは _データ構築子_ (data " -"constructor))は等号の後に定義され、パイプ文字 (`|`) で区切られます。ADTの構" -"築子が持つデータは原始型に限りません。構築子にはレコード、配列、また他のADTさ" -"えも含むことができます。" +"代数的データ型 (algebraic data type; ADT) の定義はキーワード`data`から始ま" +"り、それに新しい型の名前と任意個の型引数が続きます。\n" +"その型の構築子(これを*データ構築子*と言います)は等号の後に定義され、パイプ" +"文字 (`|`) で区切られます。\n" +"ADTの構築子が持つデータは原始型に限りません。\n" +"構築子にはレコード、配列、また他のADTさえも含められます。" #. type: Plain text #: text/chapter5.md:353 @@ -19973,7 +20128,7 @@ msgid "" "Here is its definition from the `maybe` package:" msgstr "" "それではPureScriptの標準ライブラリから別の例を見てみましょう。\n" -"オプショナルな値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。\n" +"省略可能な値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。\n" "`maybe`パッケージでは `Maybe`を次のように定義しています。" #. type: Fenced code block (haskell) @@ -19997,10 +20152,10 @@ msgstr "" #: text/chapter5.md:361 msgid "" "Note that we don't use the syntax `forall a.` anywhere in our data " -"definition. `forall` syntax is necessary for functions, but is not used when " +"definition. `forall` syntax is necessary for functions but is not used when " "defining ADTs with `data` or type aliases with `type`." msgstr "" -"なおデータ定義のどこにも構文`forall a`を使っていません。\n" +"なお、データ定義のどこにも構文`forall a`を使っていません。\n" "`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義する" "ときは使われません。" @@ -20120,15 +20275,15 @@ msgstr "" "各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できま" "す。\n" "`showShape`の最初の場合を考えてみましょう。\n" -"もし `Shape`が `Circle`構築子に適合した場合、2つの変数パターン `c`と `r`を" -"使って`Circle`の引数(中心と半径)がスコープに導入されます。その他の場合も同" -"様です。" +"もし `Shape`が `Circle`構築子に照合した場合、2つの変数パターン `c`と `r`を" +"使って`Circle`の引数(中心と半径)がスコープに導入されます。\n" +"その他の場合も同様です。" #. type: Bullet: '1. ' #: text/chapter5.md:397 msgid "" "(Easy) Write a function `circleAtOrigin` which constructs a `Circle` (of " -"type `Shape`) centered at the origin with radius `10.0`." +"type `Shape`) centered at the origin with a radius `10.0`." msgstr "" "(簡単)`Circle`(型は`Shape`)を構築する関数`circleAtOrigin`を書いてくださ" "い。\n" @@ -20137,11 +20292,11 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:397 msgid "" -"(Medium) Write a function `doubleScaleAndCenter` which scales the size of a " +"(Medium) Write a function `doubleScaleAndCenter` that scales the size of a " "`Shape` by a factor of `2.0` and centers it at the origin." msgstr "" -"(普通)`Shape`を原点を中心として`2.0`倍に拡大する関数`doubleScaleAndCenter`" -"を書いてみましょう。" +"(普通)原点を中心として`Shape`の大きさを`2.0`倍に拡大する関数" +"`doubleScaleAndCenter`を書いてみましょう。" #. type: Bullet: '1. ' #: text/chapter5.md:397 @@ -20313,12 +20468,13 @@ msgstr "newtype CouldError err a = CouldError (Either err a)\n" #. type: Plain text #: text/chapter5.md:456 msgid "" -"Also note that the constructor of a newtype often has the same name as the " +"Also, note that the constructor of a newtype often has the same name as the " "newtype itself, but this is not a requirement. For example, unique names are " "also valid:" msgstr "" -"また、newtypeの構築子はよくnewtype自身と同じ名前を持つことがあります。ただこ" -"れは必須ではありません。例えば別個の名前であっても妥当です。" +"また、newtypeの構築子はよくnewtype自身と同じ名前を持つことがあります。\n" +"ただこれは必須ではありません。\n" +"例えば別個の名前であっても正しいものです。" #. type: Fenced code block (haskell) #: text/chapter5.md:457 @@ -20329,19 +20485,22 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:Coulomb}}\n" #. type: Plain text #: text/chapter5.md:462 msgid "" -"In this case, `Coulomb` is the _type constructor_ (of zero arguments) and " +"In this case, `Coulomb` is the _type constructor_ (of zero arguments), and " "`MakeCoulomb` is the _data constructor_. These constructors live in " "different namespaces, even when the names are identical, such as with the " "`Volt` example. This is true for all ADTs. Note that although the type " -"constructor and data constructor can have different names, in practice it is " -"idiomatic for them to share the same name. This is the case with `Amp` and " -"`Volt` types above." +"constructor and data constructor can have different names, in practice, it " +"is idiomatic for them to share the same name. This is the case with `Amp` " +"and `Volt` types above." msgstr "" -"この場合`Coulomb`は*型構築子*(引数はゼロ)で`MakeCoulomb`は _データ構築子_ " -"です。これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったよう" -"に、名前に一意性があります。これは全てのADTについて言えることです。なお、型構" -"築子とデータ構築子は異なる名前を持つことができますが、実際には同じ名前を共有" -"するのが普通です。前述の`Amp`と`Volt`の場合がこれです。" +"この場合`Coulomb`は(引数ゼロの)*型構築子*で、`MakeCoulomb`は*データ構築子*" +"です。\n" +"これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名" +"前には一意性があります。\n" +"これは全てのADTについて言えることです。\n" +"なお、型構築子とデータ構築子には異なる名前を付けられますが、実際には同じ名前" +"を共有するのが普通です。\n" +"前述の`Amp`と`Volt`の場合がこれです。" #. type: Plain text #: text/chapter5.md:464 @@ -20397,10 +20556,10 @@ msgstr "" #. type: Plain text #: text/chapter5.md:480 -msgid "Define a type synonym for a `Picture` - just an array of `Shape`s:" +msgid "Define a type synonym for a `Picture` – just an array of `Shape`s:" msgstr "" -"ただの `Shape`の配列であるような、 `Picture`という型同義語を定義しておきま" -"す。" +"`Picture`という型同義語を定義しておきます。\n" +"これはただの`Shape`の配列です。" #. type: Fenced code block (haskell) #: text/chapter5.md:481 @@ -20488,7 +20647,7 @@ msgid "" "array of `Shapes` in a `Picture`, and accumulate the smallest bounding " "rectangle:" msgstr "" -"`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累積するため、`bounds`に" +"`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累算するため、`bounds`に" "は `Data.Foldable`の `foldl`関数を使用しています。" #. type: Fenced code block (haskell) @@ -20516,10 +20675,12 @@ msgid "" "union of the two bounding rectangles. The `shapeBounds` function computes " "the bounds of a single shape using pattern matching." msgstr "" -"累積関数 `combine`は `where`ブロックで定義されています。`combine`は `foldl`の" -"再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`を引数にとり、ユーザ" -"定義の演算子 `union`を使って2つの外接矩形の和を計算しています。`shapeBounds`" -"関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。" +"累算関数`combine`は`where`ブロックで定義されています。\n" +"`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`" +"を引数に取り、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算してい" +"ます。\n" +"`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算しま" +"す。" #. type: Bullet: '1. ' #: text/chapter5.md:528 @@ -20566,21 +20727,22 @@ msgstr "" msgid "" "This chapter also introduced algebraic data types, which are closely related " "to pattern matching. We saw how algebraic data types allow concise " -"descriptions of data structures, and provide a modular way to extend data " +"descriptions of data structures and provide a modular way to extend data " "types with new operations." msgstr "" -"また、この章ではパターン照合に密接に関連する代数的データ型を紹介しました。代" -"数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張" -"する上でモジュール性のある方法がもたらされることを見てきました。" +"また、この章ではパターン照合に密接に関連する代数的データ型も紹介しました。\n" +"代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡" +"張する上で、モジュール性のある方法が齎されるのでした。" #. type: Plain text #: text/chapter5.md:536 msgid "" -"Finally, we covered _row polymorphism_, a powerful type of abstraction which " +"Finally, we covered _row polymorphism_, a powerful type of abstraction that " "allows many idiomatic JavaScript functions to be given a type." msgstr "" -"最後に強力な抽象化である _行多相_ を扱いました。これにより多くの既存の" -"JavaScript関数に型を与えられます。" +"最後に*行多相*を扱いました。\n" +"これは強力な抽象化をする型であり、これにより多くの既存のJavaScript関数に型を" +"与えられます。" #. type: Plain text #: text/chapter5.md:537 @@ -20604,23 +20766,24 @@ msgstr "型クラス" #. type: Plain text #: text/chapter6.md:6 msgid "" -"This chapter will introduce a powerful form of abstraction which is enabled " -"by PureScript's type system - type classes." +"This chapter will introduce a powerful form of abstraction enabled by " +"PureScript's type system – type classes." msgstr "" -"この章では、PureScriptの型システムによって可能になる強力な抽象化の手法であ" -"る、型クラスを導入します。" +"この章では、PureScriptの型システムにより可能になっている強力な抽象化の形式を" +"導入します。\n" +"そう、型クラスです。" #. type: Plain text #: text/chapter6.md:8 msgid "" "This motivating example for this chapter will be a library for hashing data " -"structures. We will see how the machinery of type classes allow us to hash " +"structures. We will see how the machinery of type classes allows us to hash " "complex data structures without having to think directly about the structure " "of the data itself." msgstr "" -"この章ではデータ構造をハッシュ化するためのライブラリを題材に説明していきま" -"す。データ自身の構造について直接考えることなく複雑な構造のデータのハッシュ値" -"を求める上で、型クラスの仕組みがどのようにして働くのかを見ていきます。" +"データ構造をハッシュ化するためのライブラリを本章の動機付けの例とします。\n" +"データ自体の構造について直接考えることなく複雑な構造のデータのハッシュ値を求" +"める上で、型クラスの仕組みがどのように働くかを見ていきます。" #. type: Plain text #: text/chapter6.md:10 @@ -20658,7 +20821,7 @@ msgstr "" msgid "" "`maybe`, which defines the `Maybe` data type, which represents optional " "values." -msgstr "`maybe`: オプショナルな値を表す `Maybe`データ型が定義されています。" +msgstr "`maybe`: 省略可能な値を表す `Maybe`データ型が定義されています。" #. type: Bullet: '- ' #: text/chapter6.md:24 @@ -20676,7 +20839,7 @@ msgstr "`either`: 非交和を表す `Either`データ型が定義されてい #. type: Bullet: '- ' #: text/chapter6.md:24 -msgid "`strings`, which defines functions which operate on strings." +msgid "`strings`, which defines functions that operate on strings." msgstr "`strings`: 文字列を操作する関数が定義されています。" #. type: Bullet: '- ' @@ -20738,8 +20901,8 @@ msgid "" "This code declares a new _type class_ called `Show`, which is parameterized " "by the type variable `a`." msgstr "" -"このコードでは、型変数 `a`でパラメータ化された、`Show`という新しい _型クラス" -"_ (type class) を宣言しています。" +"このコードでは、型変数`a`を引数に取る`Show`という新しい*型クラス*を宣言してい" +"ます。" #. type: Plain text #: text/chapter6.md:41 @@ -20774,15 +20937,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:51 msgid "" -"This code declares a type class instance called `showBoolean` - in " +"This code declares a type class instance called `showBoolean` – in " "PureScript, type class instances can be named to aid the readability of the " "generated JavaScript. We say that the `Boolean` type _belongs to the `Show` " "type class_." msgstr "" -"このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。 " +"このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。\n" "PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインス" -"タンスに名前をつけます。このとき、 _`Boolean`型は `Show`型クラスに属している" -"_ といいます。" +"タンスに名前を付けられます。\n" +"このとき、`Boolean`型は*`Show`型クラスに属している*といいます。" #. type: Plain text #: text/chapter6.md:53 @@ -20823,8 +20986,8 @@ msgid "" "These examples demonstrate how to `show` values of various primitive types, " "but we can also `show` values with more complicated types:" msgstr "" -"この例ではさまざまなプリミティブ型の値を `show`しましたが、もっと複雑な型を持" -"つ値も`show`できます。" +"この例では様々な原始型の値を `show`しましたが、もっと複雑な型を持つ値も`show`" +"できます。" #. type: Fenced code block (text) #: text/chapter6.md:69 @@ -20855,15 +21018,16 @@ msgstr "" msgid "" "The output of `show` should be a string that you can paste back into the " "repl (or `.purs` file) to recreate the item being shown. Here we'll use " -"`logShow`, which just calls `show` then `log`, to render the string without " -"quotes. Ignore the `unit` print - that will covered in Chapter 8 when we " -"examine `Effect`s, like `log`." +"`logShow`, which just calls `show` and then `log`, to render the string " +"without quotes. Ignore the `unit` print – that will be covered in Chapter 8 " +"when we examine `Effect`s, like `log`." msgstr "" -"`show`の出力は、REPLに(あるいは`.purs`ファイルに)もう一度貼り付ければ、表示" -"されたものを再作成できるような文字列であるべきです。以下では`logShow`を使って" -"いますが、これは単に`show`と`log`を順に呼び出して、引用符なしに文字列を表示す" -"るものです。`unit`の表示は無視してください。第8章で`Effect`を調べるときに押さ" -"えます。`Effect`を持つものには`log`などがあります。" +"`show`の出力は、REPLに(あるいは`.purs`ファイルに)貼り戻せば、表示されたもの" +"を再作成できるような文字列であるべきです。\n" +"以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出すもの" +"であり、引用符なしに文字列が表示されます。\n" +"`unit`の表示は無視してください。\n" +"第8章で`log`のような`Effect`を調べるときに押さえます。" #. type: Fenced code block (text) #: text/chapter6.md:83 @@ -20895,8 +21059,7 @@ msgid "" "If we try to show a value of type `Data.Either`, we get an interesting error " "message:" msgstr "" -"型 `Data.Either`の値を表示しようとすると、興味深いエラーメッセージが表示され" -"ます。" +"型 `Data.Either`の値を表示しようとすると、興味深いエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter6.md:97 @@ -20924,21 +21087,21 @@ msgstr "" #: text/chapter6.md:109 msgid "" "The problem here is not that there is no `Show` instance for the type we " -"intended to `show`, but rather that PSCi was unable to infer the type. This " -"is indicated by the _unknown type_ `a` in the inferred type." +"intended to `show`, but rather that PSCi could not infer the type. This is " +"indicated by the _unknown type_ `a` in the inferred type." msgstr "" "ここでの問題は `show`しようとしている型に対する `Show`インスタンスが存在しな" -"いということではなく、PSCiがこの型を推論できなかったということです。このエ" -"ラーメッセージで _未知の型_ `a`と表示されているのがそれです。" +"いということではなく、PSCiがこの型を推論できなかったということです。\n" +"これは推論された型で*未知の型*`a`とされていることが示しています。" #. type: Plain text #: text/chapter6.md:111 msgid "" -"We can annotate the expression with a type, using the `::` operator, so that " +"We can annotate the expression with a type using the `::` operator, so that " "PSCi can choose the correct type class instance:" msgstr "" -"`::`演算子を使って式に対して型注釈を加えると、PSCiが正しい型クラスインスタン" -"スを選ぶことができるようになります。" +"`::`演算子を使って式に註釈を付けてPSCiが正しい型クラスインスタンスを選べるよ" +"うにできます。" #. type: Fenced code block (text) #: text/chapter6.md:112 @@ -20957,7 +21120,7 @@ msgid "Some types do not have a `Show` instance defined at all. One example of t msgstr "" "`Show`インスタンスを全く持っていない型もあります。\n" "関数の型 `->`がその一例です。\n" -"`Int`から `Int`への関数を `show`しようとすると、型検証器によってその旨のエラーメッセージが表示されます。\n" +"`Int`から `Int`への関数を `show`しようとすると、型検証器によってその旨のエラー文言が表示されます。\n" #. type: Fenced code block (text) #: text/chapter6.md:119 @@ -21055,10 +21218,11 @@ msgstr "Eq" #: text/chapter6.md:145 msgid "" "The `Eq` type class defines the `eq` function, which tests two values for " -"equality. The `==` operator is actually just an alias for `eq`." +"equality. The `==` operator is actually an alias for `eq`." msgstr "" -"`Eq`型クラスは、2つの値が等しいかどうかを調べる`eq`関数を定義しています。\n" -"等値演算子 (`==`) は`eq`の別名にすぎません。" +"`Eq`型クラスは`eq`関数を定義しています。\n" +"この関数は2つの値について等値性を調べます。\n" +"実は`==`演算子は`eq`の別名です。" #. type: Fenced code block (haskell) #: text/chapter6.md:146 @@ -21073,11 +21237,11 @@ msgstr "" #. type: Plain text #: text/chapter6.md:152 msgid "" -"Note that in either case, the two arguments must have the same type: it does " -"not make sense to compare two values of different types for equality." +"In either case, the two arguments must have the same type: it does not make " +"sense to compare two values of different types for equality." msgstr "" -"なお、異なる型の2つの値を比較しても意味がありませんから、等しいにせよ等しくな" -"いにせよ2つの引数は同じ型を持つ必要があります。" +"何れにせよ、2つの引数は同じ型を持つ必要があります。\n" +"異なる型の2つの値を等値性に関して比較しても意味がありません。" #. type: Plain text #: text/chapter6.md:154 @@ -21109,8 +21273,11 @@ msgstr "Ord" #. type: Plain text #: text/chapter6.md:166 #, no-wrap -msgid "The `Ord` type class defines the `compare` function, which can be used to compare two values, for types which support ordering. The comparison operators `<` and `>` along with their non-strict companions `<=` and `>=`, can be defined in terms of `compare`.\n" -msgstr "`Ord`型クラスは順序付け可能な型に対して2つの値を比較する `compare`関数を定義します。比較演算子 `<`、 `>`と、その仲間の厳密な大小比較ではない`<=`、 `>=`も、`compare`を使って定義されます。\n" +msgid "The `Ord` type class defines the `compare` function, which can be used to compare two values, for types that support ordering. The comparison operators `<` and `>` along with their non-strict companions `<=` and `>=`, can be defined in terms of `compare`.\n" +msgstr "" +"`Ord`型クラスは`compare`関数を定義します。\n" +"この関数は2つの値を比較するのに使えるもので、その値の型は順序付けに対応したものです。\n" +"比較演算子`<`、`>`と厳密な大小比較ではない`<=`、`>=`は`compare`を用いて定義されます。\n" #. type: Plain text #: text/chapter6.md:168 @@ -21138,25 +21305,26 @@ msgstr "" #. type: Plain text #: text/chapter6.md:177 msgid "" -"The `compare` function compares two values, and returns an `Ordering`, which " +"The `compare` function compares two values and returns an `Ordering`, which " "has three alternatives:" msgstr "" -"`compare`関数は2つの値を比較して `Ordering`の3つの値のうち何れかを返します。" +"`compare`関数は2つの値を比較して`Ordering`を返します。\n" +"これには3つ選択肢があります。" #. type: Bullet: '- ' #: text/chapter6.md:181 -msgid "`LT` - if the first argument is less than the second." -msgstr "`LT`- 最初の引数が2番目の値より小さいとき" +msgid "`LT` – if the first argument is less than the second." +msgstr "`LT`- 最初の引数が2番目の値より小さいとき。" #. type: Bullet: '- ' #: text/chapter6.md:181 -msgid "`EQ` - if the first argument is equal to the second." -msgstr "`EQ`- 最初の引数が2番目の値と等しい(または比較できない)とき" +msgid "`EQ` – if the first argument is equal to the second." +msgstr "`EQ`- 最初の引数が2番目の値と等しいとき。" #. type: Bullet: '- ' #: text/chapter6.md:181 -msgid "`GT` - if the first argument is greater than the second." -msgstr "`GT`- 最初の引数が2番目の値より大きいとき" +msgid "`GT` – if the first argument is greater than the second." +msgstr "`GT`- 最初の引数が2番目の値より大きいとき。" #. type: Plain text #: text/chapter6.md:183 @@ -21189,25 +21357,22 @@ msgstr "Field" #: text/chapter6.md:195 msgid "" "The `Field` type class identifies those types which support numeric " -"operators such as addition, subtraction, multiplication and division. It is " +"operators such as addition, subtraction, multiplication, and division. It is " "provided to abstract over those operators, so that they can be reused where " "appropriate." msgstr "" -"`Field`型クラスは加算、減算、乗算、除算などの数値演算子が使える型を示します。" -"必要に応じて再利用できるように、これらの演算子を抽象化するわけです。" +"`Field`型クラスは加算、減算、乗算、除算などの数値演算子に対応した型を示しま" +"す。\n" +"これらの演算子を抽象化して提供されているので、適切な場合に再利用できるので" +"す。" #. type: Plain text #: text/chapter6.md:197 -msgid "" -"_Note_: Just like the `Eq` and `Ord` type classes, the `Field` type class " -"has special support in the PureScript compiler, so that simple expressions " -"such as `1 + 2 * 3` get translated into simple JavaScript, as opposed to " -"function calls which dispatch based on a type class implementation." +#, no-wrap +msgid "> _Note_: Just like the `Eq` and `Ord` type classes, the `Field` type class has special support in the PureScript compiler, so that simple expressions such as `1 + 2 * 3` get translated into simple JavaScript, as opposed to function calls which dispatch based on a type class implementation.\n" msgstr "" -"*補足*:型クラス `Eq`や `Ord`のクラスとちょうど同じように、`Field`型のクラス" -"はPureScriptコンパイラで特別に扱われ、`1 + 2 * 3`のような単純な式は単純な" -"JavaScriptへと変換されます。\n" -"型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。" +"> *補足*:型クラス`Eq`ないし`Ord`とちょうど同じように、`Field`型クラスはPureScriptコンパイラで特別に扱われ、`1 + 2 * 3`のような単純な式は単純なJavaScriptへと変換されます。\n" +"> 型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。\n" #. type: Fenced code block (haskell) #: text/chapter6.md:198 @@ -21219,18 +21384,18 @@ msgstr "class EuclideanRing a <= Field a\n" #: text/chapter6.md:203 msgid "" "The `Field` type class is composed from several more general _superclasses_. " -"This allows us to talk abstractly about types which support some but not all " +"This allows us to talk abstractly about types that support some but not all " "of the `Field` operations. For example, a type of natural numbers would be " "closed under addition and multiplication, but not necessarily under " "subtraction, so that type might have an instance of the `Semiring` class " "(which is a superclass of `Num`), but not an instance of `Ring` or `Field`." msgstr "" -"`Field`型クラスは、幾つかのより抽象的な*上位クラス* (Super Class) が組み合わ" -"さってできています。\n" -"これは、その型は`Field`型クラスの操作の全てを提供しているわけではないが、その" -"一部を提供する、というように抽象的に説明できます。\n" -"例えば、自然数の型は加算及び乗算については閉じていますが、減算については閉じ" -"ていません。\n" +"`Field`型クラスは、幾つかのより抽象的な*上位クラス*が組み合わさってできていま" +"す。\n" +"このため、`Field`の操作の全てを提供しているわけではないが、その一部を提供する" +"型について抽象的に説明できます。\n" +"例えば、自然数の型は加算及び乗算については閉じていますが、減算については必ず" +"しも閉じていません。\n" "そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタン" "スですが、`Ring`や`Field`のインスタンスではありません。" @@ -21281,11 +21446,10 @@ msgstr "" #: text/chapter6.md:216 msgid "" "Strings form a semigroup under regular string concatenation, and so do " -"arrays. Several other standard instances are provided by the `prelude` " -"package." +"arrays. The `prelude` package provides several other standard instances." msgstr "" -"文字列は普通の文字列連結について半群をなし、同様に配列も半群をなします。その" -"他の標準的なインスタンスの幾つかは、 `prelude`パッケージで提供されています。" +"文字列は普通の文字列連結について半群をなし、配列も同様です。\n" +"その他の標準的なインスタンスは`prelude`パッケージで提供されています。" #. type: Plain text #: text/chapter6.md:218 @@ -21321,15 +21485,15 @@ msgstr "ここでも文字列や配列はモノイドの簡単な例になって #: text/chapter6.md:229 msgid "" "A `Monoid` type class instance for a type describes how to _accumulate_ a " -"result with that type, by starting with an \"empty\" value, and combining " -"new results. For example, we can write a function which concatenates an " -"array of values in some monoid by using a fold. In PSCi:" +"result with that type by starting with an \"empty\" value and combining new " +"results. For example, we can write a function that concatenates an array of " +"values in some monoid using a fold. In PSCi:" msgstr "" -"`Monoid`型クラスインスタンスでは、「空」の値から始めて新たな値を合成してい" -"き、その型で*累積*した結果を返すにはどうするかを記述する型クラスです。\n" -"例えば、畳み込みを使って幾つかのモノイドの値の配列を連結する関数を書くことが" -"できます。\n" -"PSCiで試すと次のようになります。" +"ある型にとっての`Monoid`型クラスインスタンスとは、「空」の値から始めて新たな" +"結果に組み合わせ、その型を持つ結果を*累算*する方法を記述するものです。\n" +"例えば、畳み込みを使って何らかのモノイドの値の配列を連結する関数を書けま" +"す。\n" +"PSCiで以下の通りです。" #. type: Fenced code block (haskell) #: text/chapter6.md:230 @@ -21418,24 +21582,23 @@ msgstr "" msgid "" "It is instructive to specialize to the case where `f` is the array type " "constructor. In this case, we can replace `f a` with `Array a` for any a, " -"and we notice that the types of `foldl` and `foldr` become the types that we " -"saw when we first encountered folds over arrays." +"and we notice that the types of `foldl` and `foldr` become the types we saw " +"when we first encountered folds over arrays." msgstr "" -"この定義は `f`を配列の型構築子として特殊化して考えてみるとわかりやすくなりま" -"す。\n" -"この場合、全ての `a`について `f a`を `Array a`に置き換える事ができますが、" -"`foldl`と `foldr`の型が、最初に見た配列に対する畳み込みの型になるとわかりま" +"`f`を配列の型構築子として特殊化すると分かりやすいです。\n" +"この場合、任意の`a`について`f a`を`Array a`に置き換えられますが、そうすると" +"`foldl`と`foldr`の型が、最初に配列に対する畳み込みで見た型になると気付きま" "す。" #. type: Plain text #: text/chapter6.md:262 #, no-wrap -msgid "What about `foldMap`? Well, that becomes `forall a m. Monoid m => (a -> m) -> Array a -> m`. This type signature says that we can choose any type `m` for our result type, as long as that type is an instance of the `Monoid` type class. If we can provide a function which turns our array elements into values in that monoid, then we can accumulate over our array using the structure of the monoid, and return a single value.\n" +msgid "What about `foldMap`? Well, that becomes `forall a m. Monoid m => (a -> m) -> Array a -> m`. This type signature says that we can choose any type `m` for our result type, as long as that type is an instance of the `Monoid` type class. If we can provide a function that turns our array elements into values in that monoid, then we can accumulate over our array using the structure of the monoid and return a single value.\n" msgstr "" "`foldMap`についてはどうでしょうか。\n" "これは `forall a m. Monoid m => (a -> m) -> Array a -> m`になります。\n" -"この型シグネチャは、型 `m`が `Monoid`型クラスのインスタンスであればどんな型でも返り値の型として選ぶことができると言っています。\n" -"配列の要素をそのモノイドの値へと変換する関数を与えれば、そのモノイドの構造を利用して配列を畳み込み、1つの値にして返すことができます。\n" +"この型シグネチャでは、型`m`が`Monoid`型クラスのインスタンスであれば、返り値の型として任意に選べると書かれています。\n" +"配列の要素をそのモノイドの値へと変える関数を与えられれば、そのモノイドの構造を利用して配列上で累算し、1つの値にして返せます。\n" #. type: Plain text #: text/chapter6.md:264 @@ -21460,47 +21623,50 @@ msgstr "" #: text/chapter6.md:273 msgid "" "Here, we choose the monoid for strings, which concatenates strings together, " -"and the `show` function which renders an `Int` as a `String`. Then, passing " +"and the `show` function, which renders an `Int` as a `String`. Then, passing " "in an array of integers, we see that the results of `show`ing each integer " "have been concatenated into a single `String`." msgstr "" -"ここでは繋ぎ合わせるためのモノイドとして文字列を、そして`Int`を文字列として表" -"示する `show`関数を選びました。そうして数の配列を渡すと、それぞれの数を " -"`show`して1つの文字列へと連結した結果が出力されました。" +"ここでは文字列用のモノイドと`show`関数を選んでいます。\n" +"前者は文字列を連結するもので、後者は`Int`を文字列として書き出すものです。\n" +"そうして数の配列を渡すと、それぞれの数を`show`して1つの文字列へと連結した結果" +"を得ました。" #. type: Plain text #: text/chapter6.md:275 msgid "" -"But arrays are not the only types which are foldable. `foldable-traversable` " +"But arrays are not the only types that are foldable. `foldable-traversable` " "also defines `Foldable` instances for types like `Maybe` and `Tuple`, and " "other libraries like `lists` define `Foldable` instances for their own data " "types. `Foldable` captures the notion of an _ordered container_." msgstr "" -"しかし畳み込み可能な型は配列だけではありません。`foldable-traversable`では " -"`Maybe`や `Tuple`のような型の `Foldable`インスタンスが定義されており、`lists`" -"のような他のライブラリでは、そのライブラリのそれぞれのデータ型に対して " -"`Foldable`インスタンスが定義されています。`Foldable`は _順序付きコンテナ_ " -"(ordered container) の概念を見据えたものなのです。" +"しかし畳み込み可能な型は配列だけではありません。\n" +"`foldable-traversable`では`Maybe`や`Tuple`のような型にも`Foldable`インスタン" +"スが定義されており、`lists`のような他のライブラリでは、各々のデータ型に対して" +"`Foldable`インスタンスが定義されています。\n" +"`Foldable`は*順序付きコンテナ*の概念を見据えたものなのです。" #. type: Title ### #: text/chapter6.md:276 #, no-wrap -msgid "Functor, and Type Class Laws" +msgid "Functor and Type Class Laws" msgstr "関手と型クラス則" #. type: Plain text #: text/chapter6.md:279 msgid "" -"The Prelude also defines a collection of type classes which enable a " +"The Prelude also defines a collection of type classes that enable a " "functional style of programming with side-effects in PureScript: `Functor`, " -"`Applicative` and `Monad`. We will cover these abstractions later in the " +"`Applicative`, and `Monad`. We will cover these abstractions later in the " "book, but for now, let's look at the definition of the `Functor` type class, " "which we have seen already in the form of the `map` function:" msgstr "" -"PureScriptで副作用を伴う関数型プログラミングのスタイルを可能にするための" -"`Functor`と `Applicative`、 `Monad`といった型クラスがPreludeでは定義されてい" -"ます。これらの抽象化については後ほど本書で扱いますが、まずは`map`関数の形で既" -"に見てきた`Functor`型クラスの定義を見てみましょう。" +"PureScriptでは、副作用を伴う関数型プログラミングのスタイルを可能にするための" +"型クラスの集まりも定義されています。\n" +"`Functor`や`Applicative`、`Monad`といったものです。\n" +"これらの抽象化については後ほど本書で扱いますが、ここでは`Functor`型クラスの定" +"義を見てみましょう。\n" +"既に`map`関数の形で見たものです。" #. type: Fenced code block (haskell) #: text/chapter6.md:280 @@ -21602,11 +21768,12 @@ msgstr "" #: text/chapter6.md:312 msgid "" "The second law is the _composition law_. It states that mapping one function " -"over a structure, and then mapping a second, is the same thing as mapping " -"the composition of the two functions over the structure." +"over a structure and then mapping a second is the same as mapping the " +"composition of the two functions over the structure." msgstr "" -"第二の法則は _合成律_ (composition law) です。構造を1つの関数で写してから2つ" -"めの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。" +"第2の法則は*合成律*です。\n" +"構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写す" +"のと同じだ、と言っています。" #. type: Plain text #: text/chapter6.md:314 @@ -21693,9 +21860,10 @@ msgid "" "solution. If you do so, you will also need to import `class Newtype` from " "`Data.Newtype` and derive a `Newtype` instance for `Complex`." msgstr "" -"(普通)`Semiring`インタンスを`Complex`に定義してください。*補足*:[`Data." -"Newtype`](https://pursuit.purescript.org/packages/purescript-newtype/docs/" -"Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答をつくることができます。" +"(普通)`Semiring`インタンスを`Complex`に定義してください。\n" +"*補足*:[`Data.Newtype`](https://pursuit.purescript.org/packages/purescript-" +"newtype/docs/Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答を作れま" +"す。\n" "もしそうするのでしたら、`Data.Newtype`から`class Newtype`をインポートしたり、" "`Newtype`インスタンスを`Complex`に導出したりする必要も出てくるでしょう。" @@ -21758,13 +21926,13 @@ msgstr "型クラス制約" #: text/chapter6.md:348 msgid "" "Types of functions can be constrained by using type classes. Here is an " -"example: suppose we want to write a function which tests if three values are " +"example: suppose we want to write a function that tests if three values are " "equal, by using equality defined using an `Eq` type class instance." msgstr "" -"型クラスを使うと、関数の型に制約を加えることができます。\n" +"型クラスを使うと、関数の型に制約を加えられます。\n" "例を示しましょう。\n" -"`Eq`型クラスのインスタンスで定義された等値性を使って、3つの値が等しいかどうか" -"を調べる関数を書きたいとします。" +"`Eq`型クラスインスタンスを使って定義された等値性を使って、3つの値が等しいかど" +"うかを調べる関数を書きたいとします。" #. type: Fenced code block (haskell) #: text/chapter6.md:349 @@ -21877,18 +22045,21 @@ msgid "" "> import Prelude\n" "\n" "> :type \\x -> x + x\n" -"forall a. Semiring a => a -> a\n" +"forall (a :: Type). Semiring a => a -> a\n" msgstr "" "> import Prelude\n" "\n" "> :type \\x -> x + x\n" -"forall a. Semiring a => a -> a\n" +"forall (a :: Type). Semiring a => a -> a\n" #. type: Plain text #: text/chapter6.md:388 #, no-wrap -msgid "Here, we might have annotated this function as `Int -> Int`, or `Number -> Number`, but PSCi shows us that the most general type works for any `Semiring`, allowing us to use our function with both `Int`s and `Number`s.\n" -msgstr "ここで、この関数には`Int -> Int`または`Number -> Number`と注釈を付けることが考えられますが、最も一般的な型が`Semiring`で動作するため、PSCiでは`Int`と `Number`の両方で関数を実行させることができます。\n" +msgid "Here, we might have annotated this function as `Int -> Int` or `Number -> Number`, but PSCi shows us that the most general type works for any `Semiring`, allowing us to use our function with both `Int`s and `Number.\n" +msgstr "" +"ここで、この関数に`Int -> Int`または`Number -> Number`と註釈を付けることはできます。\n" +"しかし、PSCiでは最も一般的な型が`Semiring`で動作することが示されています。\n" +"こうすると`Int`と`Number`の両方で関数を使えます。\n" #. type: Title ## #: text/chapter6.md:389 @@ -21932,15 +22103,13 @@ msgstr "" " ...\n" #. type: Plain text -#: text/chapter6.md:402 +#: text/chapter6.md:401 #, no-wrap -msgid "" -"If a type class instance depends on multiple other instances, those instances should be grouped in parentheses and separated by\n" -"commas on the left hand side of the `=>` symbol:\n" -msgstr "型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置く必要があります。\n" +msgid "If a type class instance depends on multiple other instances, those instances should be grouped in parentheses and separated by commas on the left-hand side of the `=>` symbol:\n" +msgstr "型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置くことになります。\n" #. type: Fenced code block (haskell) -#: text/chapter6.md:403 +#: text/chapter6.md:402 #, no-wrap msgid "" "instance (Show a, Show b) => Show (Either a b) where\n" @@ -21950,12 +22119,12 @@ msgstr "" " ...\n" #. type: Plain text -#: text/chapter6.md:409 +#: text/chapter6.md:408 msgid "These two type class instances are provided in the `prelude` library." msgstr "これらの2つの型クラスインスタンスは `prelude`ライブラリにあります。" #. type: Plain text -#: text/chapter6.md:411 +#: text/chapter6.md:410 msgid "" "When the program is compiled, the correct type class instance for `Show` is " "chosen based on the inferred type of the argument to `show`. The selected " @@ -21968,14 +22137,14 @@ msgstr "" "れませんが、このあたりの複雑さに開発者が関与することはありません。" #. type: Bullet: '1. ' -#: text/chapter6.md:415 +#: text/chapter6.md:414 msgid "" "(Easy) The following declaration defines a type of non-empty arrays of " "elements of type `a`:" msgstr "(簡単)以下の宣言では型 `a`の要素の空でない配列の型を定義しています。" #. type: Plain text -#: text/chapter6.md:419 +#: text/chapter6.md:418 #, no-wrap msgid "" " ```haskell\n" @@ -21987,15 +22156,15 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:421 +#: text/chapter6.md:420 #, no-wrap -msgid " Write an `Eq` instance for the type `NonEmpty a` which reuses the instances for `Eq a` and `Eq (Array a)`. _Note:_ you may instead derive the `Eq` instance.\n" +msgid " Write an `Eq` instance for the type `NonEmpty a` that reuses the instances for `Eq a` and `Eq (Array a)`. _Note:_ you may instead derive the `Eq` instance.\n" msgstr "" " `Eq a`と`Eq (Array a)`のインスタンスを再利用し、型`NonEmpty`に`Eq`インスタンスを書いてください。\n" -" *補足*:代わりに`Eq`インスタンスも導出できます。\n" +" *補足*:代わりに`Eq`インスタンスを導出できます。\n" #. type: Bullet: '1. ' -#: text/chapter6.md:423 +#: text/chapter6.md:422 msgid "" "(Medium) Write a `Semigroup` instance for `NonEmpty a` by reusing the " "`Semigroup` instance for `Array`." @@ -22004,21 +22173,21 @@ msgstr "" "`Semigroup`インスタンスを書いてください。" #. type: Bullet: '1. ' -#: text/chapter6.md:425 +#: text/chapter6.md:424 msgid "(Medium) Write a `Functor` instance for `NonEmpty`." msgstr "(普通)`NonEmpty`に`Functor`インスタンスを書いてください。" #. type: Bullet: '1. ' -#: text/chapter6.md:427 +#: text/chapter6.md:426 msgid "" "(Medium) Given any type `a` with an instance of `Ord`, we can add a new " -"\"infinite\" value which is greater than any other value:" +"\"infinite\" value that is greater than any other value:" msgstr "" "(普通)`Ord`のインスタンス付きの任意の型`a`が与えられているとすると、新しく" "それ以外のどんな値よりも大きい「無限の」値を付け加えられます。" #. type: Plain text -#: text/chapter6.md:431 +#: text/chapter6.md:430 #, no-wrap msgid "" " ```haskell\n" @@ -22030,13 +22199,13 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:433 +#: text/chapter6.md:432 #, no-wrap -msgid " Write an `Ord` instance for `Extended a` which reuses the `Ord` instance for `a`.\n" +msgid " Write an `Ord` instance for `Extended a` that reuses the `Ord` instance for `a`.\n" msgstr " `a`への`Ord`インスタンスを再利用して、`Extended a`に`Ord`インスタンスを書いてください。\n" #. type: Bullet: '1. ' -#: text/chapter6.md:435 +#: text/chapter6.md:434 msgid "" "(Difficult) Write a `Foldable` instance for `NonEmpty`. _Hint_: reuse the " "`Foldable` instance for arrays." @@ -22045,18 +22214,18 @@ msgstr "" "*手掛かり*:配列への`Foldable`インスタンスを再利用してください。" #. type: Bullet: '1. ' -#: text/chapter6.md:437 +#: text/chapter6.md:436 msgid "" "(Difficult) Given a type constructor `f` which defines an ordered container " -"(and so has a `Foldable` instance), we can create a new container type which " +"(and so has a `Foldable` instance), we can create a new container type that " "includes an extra element at the front:" msgstr "" "(難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持って" -"いる)ような型構築子 `f`が与えられたとき、追加の要素を先頭に含めるような新た" -"なコンテナ型を作ることができます。" +"いる)ような型構築子 `f`が与えられたとき、追加の要素を先頭に含める新たなコン" +"テナ型を作れます。" #. type: Plain text -#: text/chapter6.md:441 +#: text/chapter6.md:440 #, no-wrap msgid "" " ```haskell\n" @@ -22068,7 +22237,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:443 +#: text/chapter6.md:442 #, no-wrap msgid " The container `OneMore f` also has an ordering, where the new element comes before any element of `f`. Write a `Foldable` instance for `OneMore f`:\n" msgstr "" @@ -22077,7 +22246,7 @@ msgstr "" " この `OneMore f`の `Foldable`インスタンスを書いてみましょう。\n" #. type: Plain text -#: text/chapter6.md:448 +#: text/chapter6.md:447 #, no-wrap msgid "" " ```haskell\n" @@ -22091,16 +22260,16 @@ msgstr "" " ```\n" #. type: Bullet: '1. ' -#: text/chapter6.md:450 +#: text/chapter6.md:449 msgid "" -"(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function which " +"(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function that " "removes duplicate `Shape`s from an array using the `nubEq` function." msgstr "" "(普通)`nubEq`関数を使い、配列から重複する`Shape`を削除する`dedupShapes :: " "Array Shape -> Array Shape`関数を書いてください。" #. type: Bullet: '1. ' -#: text/chapter6.md:452 +#: text/chapter6.md:451 msgid "" "(Medium) Write a `dedupShapesFast` function which is the same as " "`dedupShapes`, but uses the more efficient `nub` function." @@ -22109,29 +22278,28 @@ msgstr "" "`dedupShapes`とほぼ同じですが、より効率の良い`nub`関数を使います。" #. type: Title ## -#: text/chapter6.md:453 +#: text/chapter6.md:452 #, no-wrap -msgid "Multi Parameter Type Classes" +msgid "Multi-Parameter Type Classes" msgstr "多変数型クラス" #. type: Plain text -#: text/chapter6.md:456 +#: text/chapter6.md:455 msgid "" "It's not the case that a type class can only take a single type as an " -"argument. This is the most common case, but in fact, a type class can be " +"argument. This is the most common case, but a type class can be " "parameterized by _zero or more_ type arguments." msgstr "" -"型クラスは必ずしも1つの型だけを型変数としてとるわけではありません。型変数が1" -"つだけなのが最も一般的ですが、実際には型クラスは*ゼロ個以上の*型変数を持つこ" -"とができます。" +"型クラスが引数として1つの型だけを取れるのかというと、そうではありません。\n" +"その場合がほとんどですが、型クラスは*ゼロ個以上の*型変数を持てます。" #. type: Plain text -#: text/chapter6.md:458 +#: text/chapter6.md:457 msgid "Let's see an example of a type class with two type arguments." msgstr "それでは2つの型引数を持つ型クラスの例を見てみましょう。" #. type: Fenced code block (haskell) -#: text/chapter6.md:459 +#: text/chapter6.md:458 #, no-wrap msgid "" "module Stream where\n" @@ -22165,9 +22333,9 @@ msgstr "" " uncons = String.uncons\n" #. type: Plain text -#: text/chapter6.md:477 +#: text/chapter6.md:476 msgid "" -"The `Stream` module defines a class `Stream` which identifies types which " +"The `Stream` module defines a class `Stream` which identifies types that " "look like streams of elements, where elements can be pulled from the front " "of the stream using the `uncons` function." msgstr "" @@ -22176,7 +22344,7 @@ msgstr "" "`uncons`関数を使ってストリームの先頭から要素を取り出すことができます。" #. type: Plain text -#: text/chapter6.md:479 +#: text/chapter6.md:478 msgid "" "Note that the `Stream` type class is parameterized not only by the type of " "the stream itself, but also by its elements. This allows us to define type " @@ -22187,7 +22355,7 @@ msgstr "" "の型について異なる型クラスインスタンスを定義できます。" #. type: Plain text -#: text/chapter6.md:481 +#: text/chapter6.md:480 msgid "" "The module defines two type class instances: an instance for arrays, where " "`uncons` removes the head element of the array using pattern matching, and " @@ -22198,17 +22366,18 @@ msgstr "" "と、文字列から最初の文字を取り除くような文字列のインスタンスです。" #. type: Plain text -#: text/chapter6.md:483 +#: text/chapter6.md:482 msgid "" -"We can write functions which work over arbitrary streams. For example, here " -"is a function which accumulates a result in some `Monoid` based on the " +"We can write functions that work over arbitrary streams. For example, here " +"is a function that accumulates a result in some `Monoid` based on the " "elements of a stream:" msgstr "" -"任意のストリーム上で動作する関数を記述できます。例えば、ストリームの要素に基" -"づいて `Monoid`に結果を累積する関数は次のようになります。" +"任意のストリーム上で動作する関数を記述できます。\n" +"例えば、ストリームの要素に基づいて `Monoid`に結果を累算する関数は次のようにな" +"ります。" #. type: Fenced code block (haskell) -#: text/chapter6.md:484 +#: text/chapter6.md:483 #, no-wrap msgid "" "import Prelude\n" @@ -22230,7 +22399,7 @@ msgstr "" " Just cons -> f cons.head <> foldStream f cons.tail\n" #. type: Plain text -#: text/chapter6.md:496 +#: text/chapter6.md:495 msgid "" "Try using `foldStream` in PSCi for different types of `Stream` and different " "types of `Monoid`." @@ -22239,37 +22408,37 @@ msgstr "" "呼び出してみましょう。" #. type: Title ## -#: text/chapter6.md:497 +#: text/chapter6.md:496 #, no-wrap msgid "Functional Dependencies" msgstr "関数従属性" #. type: Plain text -#: text/chapter6.md:500 +#: text/chapter6.md:499 msgid "" -"Multi-parameter type classes can be very useful, but can easily lead to " +"Multi-parameter type classes can be very useful but can easily lead to " "confusing types and even issues with type inference. As a simple example, " "consider writing a generic `tail` function on streams using the `Stream` " "class given above:" msgstr "" -"多変数型クラスは非常に便利ですが、混乱しやすい型や型推論の問題にも繋がりま" +"多変数型クラスは非常に便利ですが、紛らわしい型や型推論の問題にも繋がりま" "す。\n" -"簡単な例として、上記の `Stream`クラスを使って汎用的な`tail`関数をストリームに" -"書くことを考えてみましょう。" +"単純な例として、上記で与えられた`Stream`クラスを使い、ストリームに対して汎用" +"的な`tail`関数を書くことを考えてみましょう。" #. type: Fenced code block (haskell) -#: text/chapter6.md:501 +#: text/chapter6.md:500 #, no-wrap msgid "genericTail xs = map _.tail (uncons xs)\n" msgstr "genericTail xs = map _.tail (uncons xs)\n" #. type: Plain text -#: text/chapter6.md:506 +#: text/chapter6.md:505 msgid "This gives a somewhat confusing error message:" -msgstr "これはやや複雑なエラーメッセージを出力します。" +msgstr "これはやや複雑なエラー文言を出力します。" #. type: Fenced code block (text) -#: text/chapter6.md:507 +#: text/chapter6.md:506 #, no-wrap msgid "" "The inferred type\n" @@ -22285,7 +22454,7 @@ msgstr "" "has type variables which are not mentioned in the body of the type. Consider adding a type annotation.\n" #. type: Plain text -#: text/chapter6.md:516 +#: text/chapter6.md:515 msgid "" "The problem is that the `genericTail` function does not use the `element` " "type mentioned in the definition of the `Stream` type class, so that type is " @@ -22295,7 +22464,7 @@ msgstr "" "を使用しないので、その型は未解決のままであることを指しています。" #. type: Plain text -#: text/chapter6.md:518 +#: text/chapter6.md:517 msgid "" "Worse still, we cannot even use `genericTail` by applying it to a specific " "type of stream:" @@ -22303,7 +22472,7 @@ msgstr "" "更に残念なことに、特定の型のストリームに`genericTail`を適用できません。" #. type: Fenced code block (text) -#: text/chapter6.md:519 +#: text/chapter6.md:518 #, no-wrap msgid "" "> map _.tail (uncons \"testing\")\n" @@ -22323,7 +22492,7 @@ msgstr "" "has type variables which are not mentioned in the body of the type. Consider adding a type annotation.\n" #. type: Plain text -#: text/chapter6.md:530 +#: text/chapter6.md:529 msgid "" "Here, we might expect the compiler to choose the `streamString` instance. " "After all, a `String` is a stream of `Char`s, and cannot be a stream of any " @@ -22335,19 +22504,18 @@ msgstr "" "てはなりません。" #. type: Plain text -#: text/chapter6.md:532 +#: text/chapter6.md:531 msgid "" -"The compiler is unable to make that deduction automatically, and cannot " -"commit to the `streamString` instance. However, we can help the compiler by " -"adding a hint to the type class definition:" +"The compiler cannot make that deduction automatically or commit to the " +"`streamString` instance. However, we can help the compiler by adding a hint " +"to the type class definition:" msgstr "" -"コンパイラは自動的にそう推論できず、`streamString`インスタンスを割り当てるこ" -"とができません。\n" -"しかし、型クラス定義に手掛かりを追加すると、コンパイラを助けることができま" -"す。" +"コンパイラは自動的にそう推論できず、`streamString`インスタンスに目が向きませ" +"ん。\n" +"しかし、型クラス定義に手掛かりを追加すると、コンパイラを補助できます。" #. type: Fenced code block (haskell) -#: text/chapter6.md:533 +#: text/chapter6.md:532 #, no-wrap msgid "" "class Stream stream element | stream -> element where\n" @@ -22357,13 +22525,13 @@ msgstr "" " uncons :: stream -> Maybe { head :: element, tail :: stream }\n" #. type: Plain text -#: text/chapter6.md:539 +#: text/chapter6.md:538 #, no-wrap msgid "Here, `stream -> element` is called a _functional dependency_. A functional dependency asserts a functional relationship between the type arguments of a multi-parameter type class. This functional dependency tells the compiler that there is a function from stream types to (unique) element types, so if the compiler knows the stream type, then it can commit to the element type.\n" msgstr "ここで、 `stream -> element`は _関数従属性_ (functional dependency) と呼ばれます。関数従属性は、多変数型クラスの型引数間の関数関係を宣言します。この関数の依存関係は、ストリーム型から(一意の)要素型への関数があることをコンパイラに伝えるので、コンパイラがストリーム型を知っていれば要素の型を割り当てられます。\n" #. type: Plain text -#: text/chapter6.md:541 +#: text/chapter6.md:540 msgid "" "This hint is enough for the compiler to infer the correct type for our " "generic tail function above:" @@ -22372,63 +22540,64 @@ msgstr "" "のに充分です。" #. type: Fenced code block (text) -#: text/chapter6.md:542 +#: text/chapter6.md:541 #, no-wrap msgid "" "> :type genericTail\n" -"forall stream element. Stream stream element => stream -> Maybe stream\n" +"forall (stream :: Type) (element :: Type). Stream stream element => stream -> Maybe stream\n" "\n" "> genericTail \"testing\"\n" "(Just \"esting\")\n" msgstr "" "> :type genericTail\n" -"forall stream element. Stream stream element => stream -> Maybe stream\n" +"forall (stream :: Type) (element :: Type). Stream stream element => stream -> Maybe stream\n" "\n" "> genericTail \"testing\"\n" "(Just \"esting\")\n" #. type: Plain text -#: text/chapter6.md:551 +#: text/chapter6.md:550 msgid "" -"Functional dependencies can be quite useful when using multi-parameter type " -"classes to design certain APIs." +"Functional dependencies can be useful when designing certain APIs using " +"multi-parameter type classes." msgstr "" -"多種の型のクラスを使用して何らかのAPIを設計する場合、関数従属性は非常に有用で" -"す。" +"多変数の型クラスを使用して何らかのAPIを設計する場合、関数従属性が便利なことが" +"あります。" #. type: Title ## -#: text/chapter6.md:552 +#: text/chapter6.md:551 #, no-wrap msgid "Nullary Type Classes" msgstr "型変数のない型クラス" #. type: Plain text -#: text/chapter6.md:555 +#: text/chapter6.md:554 msgid "" -"We can even define type classes with zero type arguments! These correspond " -"to compile-time assertions about our functions, allowing us to track global " -"properties of our code in the type system." +"We can even define type classes with zero-type arguments! These correspond " +"to compile-time assertions about our functions, allowing us to track the " +"global properties of our code in the type system." msgstr "" "ゼロ個の型変数を持つ型クラスさえも定義できます。\n" -"これらは関数に対するコンパイル時のアサーションに対応しており、型システム内の" -"コードの大域的な性質を把握できます。" +"これらは関数に対するコンパイル時の表明に対応しており、型システム内においてそ" +"のコードの大域的な性質を把握できます。" #. type: Plain text -#: text/chapter6.md:557 +#: text/chapter6.md:556 msgid "" -"An important example is the `Partial` class which we saw earlier when " -"discussing partial functions. Take for example the functions `head` and " -"`tail` defined in `Data.Array.Partial` that allow us to get the head or tail " -"of an array without wrapping them in a `Maybe`, so they can fail if the " -"array is empty:" +"An important example is the `Partial` class we saw earlier when discussing " +"partial functions. Take, for example, the functions `head` and `tail` " +"defined in `Data.Array.Partial` that allow us to get the head or tail of an " +"array without wrapping them in a `Maybe`, so they can fail if the array is " +"empty:" msgstr "" "重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあり" -"ます。`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょ" -"う。この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。なので配列" -"が空のときに失敗する可能性があります。" +"ます。\n" +"`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。\n" +"この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。\n" +"そのため配列が空のときに失敗する可能性があります。" #. type: Fenced code block (haskell) -#: text/chapter6.md:558 +#: text/chapter6.md:557 #, no-wrap msgid "" "head :: forall a. Partial => Array a -> a\n" @@ -22440,7 +22609,7 @@ msgstr "" "tail :: forall a. Partial => Array a -> Array a\n" #. type: Plain text -#: text/chapter6.md:565 +#: text/chapter6.md:564 msgid "" "Note that there is no instance defined for the `Partial` type class! Doing " "so would defeat its purpose: attempting to use the `head` function directly " @@ -22452,7 +22621,7 @@ msgstr "" "このままの定義では `head`関数を使用しようとすると型エラーになるのです。" #. type: Fenced code block (text) -#: text/chapter6.md:566 +#: text/chapter6.md:565 #, no-wrap msgid "" "> head [1, 2, 3]\n" @@ -22468,7 +22637,7 @@ msgstr "" " Prim.Partial\n" #. type: Plain text -#: text/chapter6.md:575 +#: text/chapter6.md:574 msgid "" "Instead, we can republish the `Partial` constraint for any functions making " "use of partial functions:" @@ -22477,7 +22646,7 @@ msgstr "" "す。" #. type: Fenced code block (haskell) -#: text/chapter6.md:576 +#: text/chapter6.md:575 #, no-wrap msgid "" "secondElement :: forall a. Partial => Array a -> a\n" @@ -22487,7 +22656,7 @@ msgstr "" "secondElement xs = head (tail xs)\n" #. type: Plain text -#: text/chapter6.md:582 +#: text/chapter6.md:581 msgid "" "We've already seen the `unsafePartial` function, which allows us to treat a " "partial function as a regular function (unsafely). This function is defined " @@ -22497,13 +22666,13 @@ msgstr "" "扱うことができます。この関数は `Partial.Unsafe`モジュールで定義されています。" #. type: Fenced code block (haskell) -#: text/chapter6.md:583 +#: text/chapter6.md:582 #, no-wrap msgid "unsafePartial :: forall a. (Partial => a) -> a\n" msgstr "unsafePartial :: forall a. (Partial => a) -> a\n" #. type: Plain text -#: text/chapter6.md:588 +#: text/chapter6.md:587 msgid "" "Note that the `Partial` constraint appears _inside the parentheses_ on the " "left of the function arrow, but not in the outer `forall`. That is, " @@ -22514,7 +22683,7 @@ msgstr "" "つまり、 `unsafePartial`は部分的な値から通常の値への関数です。" #. type: Fenced code block (text) -#: text/chapter6.md:589 +#: text/chapter6.md:588 #, no-wrap msgid "" "> unsafePartial head [1, 2, 3]\n" @@ -22530,13 +22699,13 @@ msgstr "" "2\n" #. type: Title ## -#: text/chapter6.md:597 +#: text/chapter6.md:596 #, no-wrap msgid "Superclasses" msgstr "上位クラス" #. type: Plain text -#: text/chapter6.md:600 +#: text/chapter6.md:599 msgid "" "Just as we can express relationships between type class instances by making " "an instance dependent on another instance, we can express relationships " @@ -22547,7 +22716,7 @@ msgstr "" "現できます。" #. type: Plain text -#: text/chapter6.md:602 +#: text/chapter6.md:601 #, no-wrap msgid "We say that one type class is a superclass of another if every instance of the second class is required to be an instance of the first, and we indicate a superclass relationship in the class definition by using a backwards facing double arrow ( `<=` ).\n" msgstr "" @@ -22555,77 +22724,82 @@ msgstr "" "そしてクラス定義で逆向きの太い矢印 (`<=`) を使って上位クラス関係を示します。\n" #. type: Plain text -#: text/chapter6.md:604 +#: text/chapter6.md:603 msgid "" "We've [already seen an example of superclass relationships](#ord): the `Eq` " "class is a superclass of `Ord`, and the `Semigroup` class is a superclass of " "`Monoid`. For every type class instance of the `Ord` class, there must be a " -"corresponding `Eq` instance for the same type. This makes sense, since in " +"corresponding `Eq` instance for the same type. This makes sense since, in " "many cases, when the `compare` function reports that two values are " "incomparable, we often want to use the `Eq` class to determine if they are " -"in fact equal." +"equal." msgstr "" "[既に上位クラスの関係の例を目にしました](#ord)。\n" -"`Eq`クラスは `Ord`の上位クラスですし、`Semigroup`クラスは`Monoid`の上位クラスです。\n" -"`Ord`クラスの全ての型クラスインスタンスについて、その同じ型に対応する `Eq`インスタンスが存在しなければなりません。\n" +"`Eq`クラスは`Ord`の上位クラスですし、`Semigroup`クラスは`Monoid`の上位クラス" +"です。\n" +"`Ord`クラスの全ての型クラスインスタンスについて、その同じ型に対応する `Eq`イ" +"ンスタンスが存在しなければなりません。\n" "これは理に適っています。\n" -"`compare`関数が2つの値の大小を付けられないと報告した時は、それらが実は同値であるかどうかを判定するために `Eq`クラスを使いたいことが多いでしょうから。" +"多くの場合、`compare`関数が2つの値の大小を付けられないと報告した時は、同値で" +"あるかを判定するために`Eq`クラスを使うことでしょう。" #. type: Plain text -#: text/chapter6.md:606 +#: text/chapter6.md:605 msgid "" "In general, it makes sense to define a superclass relationship when the laws " -"for the subclass mention the members of the superclass. For example, it is " -"reasonable to assume, for any pair of `Ord` and `Eq` instances, that if two " -"values are equal under the `Eq` instance, then the `compare` function should " -"return `EQ`. In other words, `a == b` should be true exactly when `compare a " -"b` evaluates to `EQ`. This relationship on the level of laws justifies the " +"for the subclass mention the superclass members. For example, for any pair " +"of Ord and Eq instances, it is reasonable to assume that if two values are " +"equal under the `Eq` instance, then the `compare` function should return " +"`EQ`. In other words, `a == b` should be true exactly when `compare a b` " +"evaluates to `EQ`. This relationship on the level of laws justifies the " "superclass relationship between `Eq` and `Ord`." msgstr "" -"一般に、下位クラスの法則が上位クラスのメンバに言及しているとき、上位クラス関" -"係を定義するのは筋が通っています。\n" +"一般に、下位クラスの法則が上位クラスの構成要素に言及しているとき、上位クラス" +"関係を定義するのは筋が通っています。\n" "例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インス" -"タンスの下で同値であるなら、`compare`関数は `EQ`を返すはずだと見做すのは理に" +"タンスの下で同値であるなら、`compare`関数は`EQ`を返すはずだと推定するのは理に" "適っています。\n" -"言い換えれば、`a == b`が真であるのはちょうど`compare a b`が`EQ`に評価されると" -"きなのです。\n" -"法則のレベルでのこの関係は`Eq`と`Ord`の間の上位クラス関係の正当性を示します。" +"言い換えれば、`a == b`が真であるのは`compare a b`が厳密に`EQ`に評価されるとき" +"なのです。\n" +"法則のレベルでのこの関係は、`Eq`と`Ord`の間の上位クラス関係の正当性を示しま" +"す。" #. type: Plain text -#: text/chapter6.md:608 +#: text/chapter6.md:607 msgid "" -"Another reason to define a superclass relationship is in the case where " -"there is a clear \"is-a\" relationship between the two classes. That is, " -"every member of the subclass _is a_ member of the superclass as well." +"Another reason to define a superclass relationship is when there is a clear " +"\"is-a\" relationship between the two classes. That is, every member of the " +"subclass _is a_ member of the superclass as well." msgstr "" -"上位クラス関係を定義する別の理由となるのは、この2つのクラスの間に明らかに " -"\"is-a\" の関係があることです。\n" -"下位クラスの全てのメンバは、上位クラスのメンバでもあるということです。" +"上位クラス関係を定義する別の理由となるのは、この2つのクラスの間に明白な \"is-" +"a\" の関係があることです。\n" +"下位クラスの全ての構成要素は、上位クラスの構成要素でもあるということです。" #. type: Bullet: '1. ' -#: text/chapter6.md:612 +#: text/chapter6.md:611 msgid "" "(Medium) Define a partial function `unsafeMaximum :: Partial => Array Int -> " -"Int` which finds the maximum of a non-empty array of integers. Test out your " +"Int` that finds the maximum of a non-empty array of integers. Test out your " "function in PSCi using `unsafePartial`. _Hint_: Use the `maximum` function " "from `Data.Foldable`." msgstr "" "(普通)部分関数`unsafeMaximum :: Partial => Array Int -> Int`を定義してくだ" -"さい。この関数は空でない整数の配列の最大値を求めます。`unsafePartial`を使って" -"PSCiで関数をテストしてください。*手掛かり*:`Data.Foldable`の `maximum`関数を" -"使います。" +"さい。\n" +"この関数は空でない整数の配列の最大値を求めます。\n" +"`unsafePartial`を使ってPSCiで関数を試してください。\n" +"*手掛かり*:`Data.Foldable`の`maximum`関数を使います。" #. type: Bullet: '1. ' -#: text/chapter6.md:614 +#: text/chapter6.md:613 msgid "" -"(Medium) The `Action` class is a multi-parameter type class which defines an " +"(Medium) The `Action` class is a multi-parameter type class that defines an " "action of one type on another:" msgstr "" -"(普通)次の `Action`クラスは、ある型の別の型での動作 (action) を定義する、多" -"変数型クラスです。" +"(普通)次の `Action`クラスは、ある型の別の型での動作を定義する、多変数型クラ" +"スです。" #. type: Plain text -#: text/chapter6.md:618 +#: text/chapter6.md:617 #, no-wrap msgid "" " ```haskell\n" @@ -22637,23 +22811,25 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:620 +#: text/chapter6.md:619 #, no-wrap -msgid " An _action_ is a function which describes how monoidal values are used to determine how to modify a value of another type. There are two laws for the `Action` type class:\n" -msgstr " *動作*はモノイドな値を使って他の型の値を変更する方法を決めるやり方を記述する関数です。`Action`型クラスには2つの法則があります。\n" +msgid " An _action_ is a function that describes how monoidal values are used to determine how to modify a value of another type. There are two laws for the `Action` type class:\n" +msgstr "" +" *動作*とは、他の型の値を変更する方法を決めるために使われるモノイドな値を記述する関数です。\n" +" `Action`型クラスには2つの法則があります。\n" #. type: Bullet: ' - ' -#: text/chapter6.md:623 +#: text/chapter6.md:622 msgid "`act mempty a = a`" msgstr "`act mempty a = a`" #. type: Bullet: ' - ' -#: text/chapter6.md:623 +#: text/chapter6.md:622 msgid "`act (m1 <> m2) a = act m1 (act m2 a)`" msgstr "`act (m1 <> m2) a = act m1 (act m2 a)`" #. type: Plain text -#: text/chapter6.md:625 +#: text/chapter6.md:624 #, no-wrap msgid " Applying an empty action is a no-op. And applying two actions in sequence is the same as applying the actions combined. That is, actions respect the operations defined by the `Monoid` class.\n" msgstr "" @@ -22662,13 +22838,13 @@ msgstr "" " つまり、動作は`Monoid`クラスで定義される操作に倣っています。\n" #. type: Plain text -#: text/chapter6.md:627 +#: text/chapter6.md:626 #, no-wrap msgid " For example, the natural numbers form a monoid under multiplication:\n" msgstr " 例えば自然数は乗算のもとでモノイドを形成します。\n" #. type: Plain text -#: text/chapter6.md:630 +#: text/chapter6.md:629 #, no-wrap msgid "" " ```haskell\n" @@ -22678,13 +22854,13 @@ msgstr "" " {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Multiply}}\n" #. type: Plain text -#: text/chapter6.md:632 +#: text/chapter6.md:631 #, no-wrap msgid " {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:semigroupMultiply}}\n" msgstr " {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:semigroupMultiply}}\n" #. type: Plain text -#: text/chapter6.md:635 +#: text/chapter6.md:634 #, no-wrap msgid "" " {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:monoidMultiply}}\n" @@ -22694,13 +22870,13 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:637 +#: text/chapter6.md:636 #, no-wrap -msgid " Write an instance which implements this action:\n" +msgid " Write an instance that implements this action:\n" msgstr " この動作を実装するインスタンスを書いてください。\n" #. type: Plain text -#: text/chapter6.md:642 +#: text/chapter6.md:641 #, no-wrap msgid "" " ```haskell\n" @@ -22714,36 +22890,37 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:644 +#: text/chapter6.md:643 #, no-wrap msgid " Remember, your instance must satisfy the laws listed above.\n" msgstr " インスタンスが上で挙げた法則を見たさなくてはならないことを思い出してください。\n" +# FIXME: PureScriptではなくPurescriptになっています。 #. type: Bullet: '1. ' -#: text/chapter6.md:646 +#: text/chapter6.md:645 msgid "" -"(Difficult) There are actually multiple ways to implement an instance of " -"`Action Multiply Int`. How many can you think of? Purescript does not allow " -"multiple implementations of a same instance, so you will have to replace " -"your original implementation. _Note_: the tests cover 4 implementations." +"(Difficult) There are multiple ways to implement an instance of `Action " +"Multiply Int`. How many can you think of? Purescript does not allow multiple " +"implementations of the same instance, so you will have to replace your " +"original implementation. _Note_: the tests cover 4 implementations." msgstr "" -"(難しい)実は`Action Multiply Int`のインスタンスを実装するには複数の方法があ" -"ります。\n" +"(難しい)`Action Multiply Int`のインスタンスを実装するには複数の方法がありま" +"す。\n" "どれだけ思い付きますか。\n" "PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える" -"必要があります。\n" +"必要があるでしょう。\n" "*補足*:テストでは4つの実装を押さえています。" #. type: Bullet: '1. ' -#: text/chapter6.md:648 +#: text/chapter6.md:647 msgid "" -"(Medium) Write an `Action` instance which repeats an input string some " -"number of times:" +"(Medium) Write an `Action` instance that repeats an input string some number " +"of times:" msgstr "" "(普通)入力の文字列を何回か繰り返す`Action`インスタンスを書いてください。" #. type: Plain text -#: text/chapter6.md:653 +#: text/chapter6.md:652 #, no-wrap msgid "" " ```haskell\n" @@ -22757,21 +22934,21 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:655 +#: text/chapter6.md:654 #, no-wrap msgid " _Hint_: Search Pursuit for a helper-function with the signature [`String -> Int -> String`](https://pursuit.purescript.org/search?q=String%20-%3E%20Int%20-%3E%20String). Note that `String` might appear as a more generic type (such as `Monoid`).\n" msgstr "" " *手掛かり*:Pursuitでシグネチャが[`String -> Int -> String`](https://pursuit.purescript.org/search?q=String%20-%3E%20Int%20-%3E%20String)の補助関数を検索してください。\n" -" なお`String`は(`Monoid`のような)より汎用的な型として現れます。\n" +" なお、`String`は(`Monoid`のような)より汎用的な型として現れます。\n" #. type: Plain text -#: text/chapter6.md:657 +#: text/chapter6.md:656 #, no-wrap msgid " Does this instance satisfy the laws listed above?\n" msgstr " このインスタンスは上に挙げた法則を満たすでしょうか。\n" #. type: Bullet: '1. ' -#: text/chapter6.md:659 +#: text/chapter6.md:658 msgid "" "(Medium) Write an instance `Action m a => Action m (Array a)`, where the " "action on arrays is defined by acting on each array element independently." @@ -22780,7 +22957,7 @@ msgstr "" "ここで、 配列上の動作はそれぞれの要素を独立に実行するものとして定義されます。" #. type: Bullet: '1. ' -#: text/chapter6.md:661 +#: text/chapter6.md:660 msgid "" "(Difficult) Given the following newtype, write an instance for `Action m " "(Self m)`, where the monoid `m` acts on itself using `append`:" @@ -22790,7 +22967,7 @@ msgstr "" "ここでモノイド`m`はそれ自体が持つ`append`を用いて動作します。" #. type: Plain text -#: text/chapter6.md:665 +#: text/chapter6.md:664 #, no-wrap msgid "" " ```haskell\n" @@ -22802,7 +22979,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:667 +#: text/chapter6.md:666 #, no-wrap msgid " _Note_: The testing framework requires `Show` and `Eq` instances for the `Self` and `Multiply` types. You may either write these instances manually, or let the compiler handle this for you with [`derive newtype instance`](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#derive-from-newtype) shorthand.\n" msgstr "" @@ -22810,7 +22987,7 @@ msgstr "" " 手作業でこれらのインスタンスを書いてもよいですし、[`derive newtype instance`](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#derive-from-newtype)と書くだけでコンパイラに取り仕切ってもらうこともできます。\n" #. type: Bullet: '1. ' -#: text/chapter6.md:669 +#: text/chapter6.md:668 msgid "" "(Difficult) Should the arguments of the multi-parameter type class `Action` " "be related by some functional dependency? Why or why not? _Note_: There is " @@ -22822,13 +22999,13 @@ msgstr "" "*補足*:この演習にはテストがありません。" #. type: Title ## -#: text/chapter6.md:670 +#: text/chapter6.md:669 #, no-wrap msgid "A Type Class for Hashes" msgstr "ハッシュの型クラス" #. type: Plain text -#: text/chapter6.md:673 +#: text/chapter6.md:672 msgid "" "In the last section of this chapter, we will use the lessons from the rest " "of the chapter to create a library for hashing data structures." @@ -22837,30 +23014,27 @@ msgstr "" "ます。" #. type: Plain text -#: text/chapter6.md:675 -msgid "" -"Note that this library is for demonstration purposes only, and is not " -"intended to provide a robust hashing mechanism." -msgstr "" -"なお、このライブラリの説明だけを目的としており、堅牢なハッシュ化の仕組みの提" -"供は目的としていません。" +#: text/chapter6.md:674 +#, no-wrap +msgid "> Note that this library is for demonstration purposes only and is not intended to provide a robust hashing mechanism.\n" +msgstr "> なお、このライブラリは説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は意図していません。\n" #. type: Plain text -#: text/chapter6.md:677 +#: text/chapter6.md:676 msgid "What properties might we expect of a hash function?" msgstr "ハッシュ関数に期待される性質とはどのようなものでしょうか。" #. type: Bullet: '- ' -#: text/chapter6.md:680 +#: text/chapter6.md:679 msgid "" -"A hash function should be deterministic, and map equal values to equal hash " +"A hash function should be deterministic and map equal values to equal hash " "codes." msgstr "" "ハッシュ関数は決定的でなくてはなりません。\n" -"つまり、同じ値には同じハッシュ値を対応させなければなりません。" +"つまり、同じ値は同じハッシュコードに写さなければなりません。" #. type: Bullet: '- ' -#: text/chapter6.md:680 +#: text/chapter6.md:679 msgid "" "A hash function should distribute its results approximately uniformly over " "some set of hash codes." @@ -22869,33 +23043,33 @@ msgstr "" "ん。" #. type: Plain text -#: text/chapter6.md:682 +#: text/chapter6.md:681 msgid "" "The first property looks a lot like a law for a type class, whereas the " -"second property is more along the lines of an informal contract, and " +"second property is more along the lines of an informal contract and " "certainly would not be enforceable by PureScript's type system. However, " "this should provide the intuition for the following type class:" msgstr "" -"最初の性質はまさに型クラスの法則のように見える一方で、2番目の性質はよりくだけ" -"た規約の条項のようなもので、PureScriptの型システムによって確実に強制できるよ" -"うなものではなさそうです。\n" -"しかし、これは型クラスについて次のような直感的理解を与えるはずです。" +"最初の性質はちゃんとした型クラスの法則のように見えます。\n" +"その一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型" +"システムによって確実に強制できるようなものではなさそうです。\n" +"しかし、これは型クラスから次のような直感が得られるでしょう。" #. type: Fenced code block (haskell) -#: text/chapter6.md:683 +#: text/chapter6.md:682 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:Hashable}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:Hashable}}\n" #. type: Plain text -#: text/chapter6.md:688 +#: text/chapter6.md:687 msgid "with the associated law that `a == b` implies `hash a == hash b`." msgstr "" "これに、 `a == b`ならば `hash a == hash b`を示唆するという関係性の法則が付随" "しています。" #. type: Plain text -#: text/chapter6.md:690 +#: text/chapter6.md:689 msgid "" "We'll spend the rest of this section building a library of instances and " "functions associated with the `Hashable` type class." @@ -22904,18 +23078,18 @@ msgstr "" "ンスと関数のライブラリを構築していきます。" #. type: Plain text -#: text/chapter6.md:692 +#: text/chapter6.md:691 msgid "We will need a way to combine hash codes in a deterministic way:" msgstr "決定的な方法でハッシュ値を結合する方法が必要になります。" #. type: Fenced code block (haskell) -#: text/chapter6.md:693 +#: text/chapter6.md:692 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:combineHashes}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:combineHashes}}\n" #. type: Plain text -#: text/chapter6.md:698 +#: text/chapter6.md:697 msgid "" "The `combineHashes` function will mix two hash codes and redistribute the " "result over the interval 0-65535." @@ -22923,31 +23097,32 @@ msgstr "" "`combineHashes`関数は2つのハッシュ値を混ぜて結果を0-65535の間に分布します。" #. type: Plain text -#: text/chapter6.md:700 +#: text/chapter6.md:699 msgid "" -"Let's write a function which uses the `Hashable` constraint to restrict the " +"Let's write a function that uses the `Hashable` constraint to restrict the " "types of its inputs. One common task which requires a hashing function is to " "determine if two values hash to the same hash code. The `hashEqual` relation " "provides such a capability:" msgstr "" -"それでは、入力の種類を制限する `Hashable`制約を使う関数を書いてみましょう。\n" -"ハッシュ関数を必要とするよくある目的としては、2つの値が同じハッシュ値にハッ" -"シュ化されるかどうかを決定することです。\n" +"それでは、`Hashable`制約を使って入力の種類を制限する関数を書いてみましょ" +"う。\n" +"ハッシュ関数を必要とするよくある目的としては、2つの値が同じハッシュコードに" +"ハッシュ化されるかどうかを判定することです。\n" "`hashEqual`関係はそのような機能を提供します。" #. type: Fenced code block (haskell) -#: text/chapter6.md:701 +#: text/chapter6.md:700 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashEqual}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashEqual}}\n" #. type: Plain text -#: text/chapter6.md:706 +#: text/chapter6.md:705 msgid "" "This function uses the `on` function from `Data.Function` to define hash-" "equality in terms of equality of hash codes, and should read like a " "declarative definition of hash-equality: two values are \"hash-equal\" if " -"they are equal after each value has been passed through the `hash` function." +"they are equal after each value passed through the `hash` function." msgstr "" "この関数はハッシュコードの等値性を利用したハッシュ同値性を定義するために" "`Data.Function`の `on`関数を使っていますが、これはハッシュ同値性の宣言的な定" @@ -22956,38 +23131,38 @@ msgstr "" "の値は「ハッシュ同値」です。" #. type: Plain text -#: text/chapter6.md:708 +#: text/chapter6.md:707 msgid "" "Let's write some `Hashable` instances for some primitive types. Let's start " "with an instance for integers. Since a `HashCode` is really just a wrapped " -"integer, this is simple - we can use the `hashCode` helper function:" +"integer, this is simple – we can use the `hashCode` helper function:" msgstr "" "原始型の `Hashable`インスタンスを幾つか書いてみましょう。\n" "まずは整数のインスタンスです。\n" -"`HashCode`は実際には単なる梱包された整数なので、これは簡単です。\n" -"`hashCode`補助関数を使うことができます。" +"`HashCode`は実際には単なる梱包された整数なので、単純です。\n" +"`hashCode`補助関数を使えます。" #. type: Fenced code block (haskell) -#: text/chapter6.md:709 +#: text/chapter6.md:708 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashInt}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashInt}}\n" #. type: Plain text -#: text/chapter6.md:714 +#: text/chapter6.md:713 msgid "" "We can also define a simple instance for `Boolean` values using pattern " "matching:" msgstr "パターン照合を使うと、`Boolean`値の単純なインスタンスも定義できます。" #. type: Fenced code block (haskell) -#: text/chapter6.md:715 +#: text/chapter6.md:714 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashBoolean}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashBoolean}}\n" #. type: Plain text -#: text/chapter6.md:720 +#: text/chapter6.md:719 msgid "" "With an instance for hashing integers, we can create an instance for hashing " "`Char`s by using the `toCharCode` function from `Data.Char`:" @@ -22996,13 +23171,13 @@ msgstr "" "シュ化するインスタンスを作成できます。" #. type: Fenced code block (haskell) -#: text/chapter6.md:721 +#: text/chapter6.md:720 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashChar}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashChar}}\n" #. type: Plain text -#: text/chapter6.md:726 +#: text/chapter6.md:725 msgid "" "To define an instance for arrays, we can `map` the `hash` function over the " "elements of the array (if the element type is also an instance of " @@ -23014,13 +23189,13 @@ msgstr "" "で、配列のインスタンスを定義します。" #. type: Fenced code block (haskell) -#: text/chapter6.md:727 +#: text/chapter6.md:726 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashArray}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashArray}}\n" #. type: Plain text -#: text/chapter6.md:732 +#: text/chapter6.md:731 msgid "" "Notice how we build up instances using the simpler instances we have already " "written. Let's use our new `Array` instance to define an instance for " @@ -23032,32 +23207,33 @@ msgstr "" "のインスタンスを定義しましょう。" #. type: Fenced code block (haskell) -#: text/chapter6.md:733 +#: text/chapter6.md:732 #, no-wrap msgid "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashString}}\n" msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashString}}\n" #. type: Plain text -#: text/chapter6.md:738 +#: text/chapter6.md:737 msgid "" "How can we prove that these `Hashable` instances satisfy the type class law " "that we stated above? We need to make sure that equal values have equal hash " -"codes. In cases like `Int`, `Char`, `String` and `Boolean`, this is simple " -"because there are no values of those types which are equal in the sense of " +"codes. In cases like `Int`, `Char`, `String`, and `Boolean`, this is simple " +"because there are no values of those types that are equal in the sense of " "`Eq` but not equal identically." msgstr "" "これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証" "明するにはどうしたらいいでしょうか。\n" -"同じ値が等しいハッシュ値を持っていることを確認する必要があります。\n" -"`Int`、 `Char`、 `String`、 `Boolean`の場合は、`Eq`の意味では同じ値でも厳密に" -"は同じではない、というような型の値は存在しないので簡単です。" +"同じ値が等しいハッシュコードを持っていることを確認する必要があります。\n" +"`Int`、`Char`、`String`、`Boolean`のような場合は単純です。\n" +"`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しない" +"からです。" #. type: Plain text -#: text/chapter6.md:740 +#: text/chapter6.md:739 msgid "" "What about some more interesting types? To prove the type class law for the " "`Array` instance, we can use induction on the length of the array. The only " -"array with length zero is `[]`. Any two non-empty arrays are equal only if " +"array with a length zero is `[]`. Any two non-empty arrays are equal only if " "they have equal head elements and equal tails, by the definition of `Eq` on " "arrays. By the inductive hypothesis, the tails have equal hashes, and we " "know that the head elements have equal hashes if the `Hashable a` instance " @@ -23065,18 +23241,19 @@ msgid "" "the `Hashable (Array a)` obeys the type class law as well." msgstr "" "もっと面白い型についてはどうでしょうか。\n" -"この場合、配列の長さに関する帰納を使うと、型クラスの法則を証明できます。\n" +"`Array`インスタンスの型クラスの法則を証明するにあたっては、配列の長さに関する" +"帰納を使えます。\n" "長さゼロの唯一の配列は `[]`です。\n" "配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じ" "で配列の残りの部分が等しいとき、またその時に限り等しくなります。\n" "この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし " "`Hashable a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を" -"もつことがわかります。\n" +"持つことがわかります。\n" "したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型ク" -"ラス法則を満たしています。" +"ラス法則に従います。" #. type: Plain text -#: text/chapter6.md:742 +#: text/chapter6.md:741 msgid "" "The source code for this chapter includes several other examples of " "`Hashable` instances, such as instances for the `Maybe` and `Tuple` type." @@ -23085,7 +23262,7 @@ msgstr "" "`Hashable`インスタンスの例が含まれています。" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 +#: text/chapter6.md:747 msgid "" "(Easy) Use PSCi to test the hash functions for each of the defined " "instances. _Note_: There is no provided unit test for this exercise." @@ -23095,23 +23272,24 @@ msgstr "" "*補足*:この演習には単体試験がありません。" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 +#: text/chapter6.md:747 msgid "" -"(Medium) Write a function `arrayHasDuplicates` which tests if an array has " -"any duplicate elements based on both hash and value equality. First check " +"(Medium) Write a function `arrayHasDuplicates`, which tests if an array has " +"any duplicate elements based on both hash and value equality. First, check " "for hash equality with the `hashEqual` function, then check for value " "equality with `==` if a duplicate pair of hashes is found. _Hint_: the " "`nubByEq` function in `Data.Array` should make this task much simpler." msgstr "" -"(普通)ハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうか" -"を調べる関数`arrayHasDuplicates`を書いてください。\n" +"(普通)関数`arrayHasDuplicates`を書いてください。\n" +"この関数はハッシュと値の同値性に基づいて配列が重複する要素を持っているかどう" +"かを調べます。\n" "まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対" "が見付かったら`==`で値の同値性を確認してください。\n" "*手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるで" "しょう。" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 +#: text/chapter6.md:747 msgid "" "(Medium) Write a `Hashable` instance for the following newtype which " "satisfies the type class law:" @@ -23120,7 +23298,7 @@ msgstr "" "ください。" #. type: Plain text -#: text/chapter6.md:751 +#: text/chapter6.md:750 #, no-wrap msgid "" " ```haskell\n" @@ -23130,7 +23308,7 @@ msgstr "" " {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Hour}}\n" #. type: Plain text -#: text/chapter6.md:754 +#: text/chapter6.md:753 #, no-wrap msgid "" " {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:eqHour}}\n" @@ -23140,7 +23318,7 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:757 +#: text/chapter6.md:756 #, no-wrap msgid "" " The newtype `Hour` and its `Eq` instance represent the type of integers modulo 12, so that 1 and 13 are identified as equal, for example. Prove that the type class law holds for your instance.\n" @@ -23153,33 +23331,35 @@ msgstr "" " *補足*:この演習にテストはありません。\n" #. type: Plain text -#: text/chapter6.md:761 +#: text/chapter6.md:760 msgid "" "In this chapter, we've been introduced to _type classes_, a type-oriented " -"form of abstraction which enables powerful forms of code reuse. We've seen a " -"collection of standard type classes from the PureScript standard libraries, " +"form of abstraction that enables powerful forms of code reuse. We've seen a " +"collection of standard type classes from the PureScript standard libraries " "and defined our own library based on a type class for computing hash codes." msgstr "" -"この章では、型に基づく抽象化で、コードの再利用のための強力な形式化を可能にす" -"る _型クラス_ を導入しました。PureScriptの標準ライブラリから標準の型クラスを" -"幾つか見てきました。また、ハッシュ値を計算する型クラスに基づく独自のライブラ" -"リを定義しました。" +"この章では*型クラス*を導入しました。\n" +"型クラスは型に基づく抽象化で、コードの再利用のために強力な形式化ができま" +"す。\n" +"PureScriptの標準ライブラリから標準の型クラスを幾つか見てきました。\n" +"また、ハッシュ値を計算するための型クラスに基づく独自のライブラリを定義しまし" +"た。" #. type: Plain text -#: text/chapter6.md:762 +#: text/chapter6.md:761 msgid "" -"This chapter also gave an introduction to the notion of type class laws, a " -"technique for proving properties about code which uses type classes for " -"abstraction. Type class laws are part of a larger subject called _equational " -"reasoning_, in which the properties of a programming language and its type " -"system are used to enable logical reasoning about its programs. This is an " -"important idea, and will be a theme which we will return to throughout the " -"rest of the book." -msgstr "" -"この章では型クラス法則の考え方も導入しましたが、これは抽象化に型クラスを使う" -"コードについての性質を証明する手法でした。\n" -"型クラス法則は*等式推論*と呼ばれる大きな分野の一部であり、プログラミング言語" -"の性質と型システムがプログラムを論理的に推論するために使われています。\n" +"This chapter also introduced type class laws, a technique for proving " +"properties about code that uses type classes for abstraction. Type class " +"laws are part of a larger subject called _equational reasoning_, in which " +"the properties of a programming language and its type system are used to " +"enable logical reasoning about its programs. This is an important idea and a " +"theme that we will return to throughout the rest of the book." +msgstr "" +"この章では型クラス法則も導入しましたが、これは抽象化に型クラスを使うコードに" +"ついての性質を証明する手法でした。\n" +"型クラス法則は*等式推論*と呼ばれるより大きな分野の一部です。\n" +"そちらではプログラミング言語の性質と型システムがプログラムを論理的に追究する" +"ために使われています。\n" "これは重要な考え方で、本書では今後あらゆる箇所で立ち返る話題となるでしょう。" #. type: Title ## @@ -23191,19 +23371,19 @@ msgstr "アプリカティブによる検証" #. type: Plain text #: text/chapter7.md:6 msgid "" -"In this chapter, we will meet an important new abstraction - the " +"In this chapter, we will meet an important new abstraction – the " "_applicative functor_, described by the `Applicative` type class. Don't " -"worry if the name sounds confusing - we will motivate the concept with a " -"practical example - validating form data. This technique allows us to " +"worry if the name sounds confusing – we will motivate the concept with a " +"practical example – validating form data. This technique allows us to " "convert code which usually involves a lot of boilerplate checking into a " "simple, declarative description of our form." msgstr "" -"この章では、`Applicative`型クラスによって表現される _アプリカティブ関手_ " -"(applicative functor) という重要な抽象化と新たに出会うことになります。名前が" -"難しそうに思えても心配しないでください。フォームデータの検証という実用的な例" -"を使ってこの概念の動機付けをします。アプリカティブ関手を使うと、通常であれば" -"大量の決まり文句を伴うようなコードを、簡潔で宣言的な記述へと変えることができ" -"るようになります。" +"この章では重要な抽象化と新たに出会うことになります。\n" +"`Applicative`型クラスによって表現される*アプリカティブ関手*です。\n" +"名前が難しそうに思えても心配しないでください。\n" +"フォームデータの検証という実用的な例を使ってこの概念の動機付けをします。\n" +"アプリカティブ関手の技法があることにより、通常であれば大量の決まり文句の検証" +"を伴うようなコードを、簡潔で宣言的なフォームの記述へと変えられます。" #. type: Plain text #: text/chapter7.md:8 @@ -23219,15 +23399,15 @@ msgstr "" #: text/chapter7.md:10 msgid "" "The example code for this chapter will be a continuation of the address book " -"example from chapter 3. This time, we will extend our address book data " -"types, and write functions to validate values for those types. The " -"understanding is that these functions could be used, for example in a web " +"example from Chapter 3. This time, we will extend our address book data " +"types and write functions to validate values for those types. The " +"understanding is that these functions could be used, for example, in a web " "user interface, to display errors to the user as part of a data entry form." msgstr "" -"この章では第3章に引き続き住所録を例として扱います。\n" +"この章のコードでは第3章に引き続き住所録を例とします。\n" "今回は住所録のデータ型を拡張し、これらの型の値を検証する関数を書きます。\n" -"これらの関数は、例えばデータ入力フォームの一部で、使用者へエラーを表示するweb" -"ユーザインターフェースで使われると考えてください。" +"これらの関数は、例えばwebユーザインターフェースで使えることが分かります。\n" +"データ入力フォームの一部として、使用者へエラーを表示するのに使われます。" #. type: Plain text #: text/chapter7.md:14 @@ -23270,12 +23450,13 @@ msgstr "" #: text/chapter7.md:21 msgid "" "The `Data.AddressBook` module defines data types and `Show` instances for " -"the types in our project, and the `Data.AddressBook.Validation` module " +"the types in our project and the `Data.AddressBook.Validation` module " "contains validation rules for those types." msgstr "" -"`Data.AddressBook`モジュールには、このプロジェクトのデータ型とそれらの型に対" -"する`Show`インスタンスが定義されており、`Data.AddressBook.Validation`モジュー" -"ルにはそれらの型の検証規則が含まれています。" +"`Data.AddressBook`モジュールにはこのプロジェクトのデータ型とそれらの型に対す" +"る`Show`インスタンスが定義されています。\n" +"また、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれ" +"ています。" #. type: Title ## #: text/chapter7.md:22 @@ -23295,11 +23476,11 @@ msgstr "" #. type: Plain text #: text/chapter7.md:27 msgid "" -"The source code for this module defines a function `address` which has the " +"The source code for this module defines a function `address` that has the " "following type:" msgstr "" -"このモジュールのソースコードでは、次のような型を持つ`address`関数が定義されて" -"います。" +"このモジュールのソースコードでは、次の型を持つ`address`関数が定義されていま" +"す。" #. type: Fenced code block (haskell) #: text/chapter7.md:28 @@ -23383,11 +23564,11 @@ msgstr "" #. type: Plain text #: text/chapter7.md:61 msgid "" -"Of course, this is an expected type error - `address` takes strings as " +"Of course, this is an expected type error – `address` takes strings as " "arguments, not values of type `Maybe String`." msgstr "" -"`address`は`Maybe String`型ではなく文字列型の引数を取るので、もちろんこれは期" -"待通り型エラーになります。" +"勿論、これは期待通り型エラーになります。\n" +"`address`は`Maybe String`型の値ではなく、文字列を引数として取るためです。" #. type: Plain text #: text/chapter7.md:63 @@ -23476,10 +23657,10 @@ msgstr "`lift3`の型を見てみるとわかりやすいでしょう。" #, no-wrap msgid "" "> :type lift3\n" -"forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d\n" +"forall (a :: Type) (b :: Type) (c :: Type) (d :: Type) (f :: Type -> Type). Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d\n" msgstr "" "> :type lift3\n" -"forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d\n" +"forall (a :: Type) (b :: Type) (c :: Type) (d :: Type) (f :: Type -> Type). Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d\n" #. type: Plain text #: text/chapter7.md:93 @@ -23499,12 +23680,12 @@ msgstr "forall a b c d. (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> M #. type: Plain text #: text/chapter7.md:99 msgid "" -"This type says that we can take any function with three arguments, and lift " +"This type says that we can take any function with three arguments and lift " "it to give a new function whose argument and result types are wrapped with " "`Maybe`." msgstr "" -"この型が言っているのは、3引数の任意の関数を取り、その関数を引数と返り値が" -"`Maybe`で包まれた新しい関数へと持ち上げる、ということです。" +"この型で書かれているのは、3引数の任意の関数を取り、その関数を引数と返り値が" +"`Maybe`で包まれた新しい関数へと持ち上げられる、ということです。" #. type: Plain text #: text/chapter7.md:101 @@ -23514,8 +23695,8 @@ msgid "" "the type above, we removed a type class constraint on `f` from the `Apply` " "type class. `Apply` is defined in the Prelude as follows:" msgstr "" -"もちろんどんな型構築子`f`についても持ち上げができるわけではないのですが、それ" -"では`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。\n" +"勿論、どんな型構築子`f`についても持ち上げができるわけではないのですが、それで" +"は`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。\n" "さて、先ほどの型の特殊化では、`f`に対する型クラス制約から`Apply`型クラスを取" "り除いていました。\n" "`Apply`はPreludeで次のように定義されています。" @@ -23552,11 +23733,12 @@ msgid "" "almost always used for the latter, so you don't need to worry about name " "collisions." msgstr "" -"なおこの[`apply`](https://pursuit.purescript.org/packages/purescript-prelude/" -"docs/Control.Apply#v:apply)は`Data.Function`の[`apply`](https://pursuit." -"purescript.org/packages/purescript-prelude/docs/Data.Function#v:apply)(中置" -"で`$`)とは異なります。幸いにも後者はほぼ常に中置記法として使われるので、名前" -"の衝突については心配ご無用です。" +"なお、この[`apply`](https://pursuit.purescript.org/packages/purescript-" +"prelude/docs/Control.Apply#v:apply)は`Data.Function`の[`apply`](https://" +"pursuit.purescript.org/packages/purescript-prelude/docs/Data.Function#v:" +"apply)(中置で`$`)とは異なります。\n" +"幸いにも後者はほぼ常に中置記法として使われるので、名前の衝突については心配ご" +"無用です。" #. type: Plain text #: text/chapter7.md:115 @@ -23599,22 +23781,22 @@ msgid "" "This type class instance says that we can apply an optional function to an " "optional value, and the result is defined only if both are defined." msgstr "" -"この型クラスのインスタンスで書かれているのは、任意のオプショナルな値にオプ" -"ショナルな関数を適用でき、その両方が定義されている時に限り結果も定義される、" -"ということです。" +"この型クラスのインスタンスで書かれているのは、任意の省略可能な値に省略可能な" +"関数を適用でき、その両方が定義されている時に限り結果も定義される、ということ" +"です。" #. type: Plain text #: text/chapter7.md:129 msgid "" "Now we'll see how `map` and `apply` can be used together to lift functions " -"of arbitrary number of arguments." +"of an arbitrary number of arguments." msgstr "" "それでは、`map`と`apply`を一緒に使い、引数が任意個の関数を持ち上げる方法を見" "ていきましょう。" #. type: Plain text #: text/chapter7.md:131 -msgid "For functions of one argument, we can just use `map` directly." +msgid "For functions of one argument, we can use `map` directly." msgstr "1引数の関数については、`map`をそのまま使うだけです。" #. type: Plain text @@ -23659,12 +23841,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:150 -msgid "" -"It is left as an exercise for the reader to verify the types involved in " -"this expression." -msgstr "" -"この式の型がちゃんと整合しているかの確認は、読者への演習として残しておきま" -"す。" +#, no-wrap +msgid "> It is left as an exercise for the reader to verify the types involved in this expression.\n" +msgstr "> この式に関する型の検証は、読者への演習として残しておきます。\n" #. type: Plain text #: text/chapter7.md:152 @@ -23700,15 +23879,16 @@ msgstr "" #. type: Plain text #: text/chapter7.md:164 msgid "" -"Alternatively _applicative do notation_ can be used for the same purpose in " +"Alternatively, _applicative do notation_ can be used for the same purpose in " "a way that looks similar to the familiar _do notation_. Here is `lift3` " "using _applicative do notation_. Note `ado` is used instead of `do`, and " "`in` is used on the final line to denote the yielded value:" msgstr "" -"この代わりにお馴染の _do記法_ に似た見た目の _アプリカティブdo記法_ が同じ目" -"的で使えます。以下では`lift3`に _アプリカティブdo記法_ を使っています。なお、" -"`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で`in`が" -"使われています。" +"この代わりに、お馴染の*do記法*に似た見た目の*アプリカティブdo記法*が同じ目的" +"で使えます。\n" +"以下では`lift3`に*アプリカティブdo記法*を使っています。\n" +"なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で" +"`in`が使われています。" #. type: Fenced code block (haskell) #: text/chapter7.md:165 @@ -23791,12 +23971,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:199 msgid "" -"If we think of applicative functors as functors which allow lifting of " +"If we think of applicative functors as functors that allow lifting of " "functions, then `pure` can be thought of as lifting functions of zero " "arguments." msgstr "" "アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、" -"`pure`は引数のない関数の持ち上げだというように考えることができます。" +"`pure`は引数のない関数の持ち上げだというように考えられます。" #. type: Title ## #: text/chapter7.md:200 @@ -23818,9 +23998,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:205 #, no-wrap -msgid "As an example, the functor `Maybe` represents the side effect of possibly-missing values. Some other examples include `Either err`, which represents the side effect of possible errors of type `err`, and the arrow functor `r ->` which represents the side-effect of reading from a global configuration. For now, we'll only consider the `Maybe` functor.\n" +msgid "As an example, the functor `Maybe` represents the side effect of possibly-missing values. Some other examples include `Either err`, which represents the side effect of possible errors of type `err`, and the arrow functor `r ->`, which represents the side-effect of reading from a global configuration. For now, we'll only consider the `Maybe` functor.\n" msgstr "" -"例えば関手`Maybe`はオプショナルな値の副作用を表現しています。\n" +"例えば関手`Maybe`は欠けている可能性がある値の副作用を表現しています。\n" "その他の例としては、型`err`のエラーの可能性の副作用を表す`Either err`や、大域的な構成を読み取る副作用を表すArrow関手 (arrow functor) `r ->`があります。\n" "ここでは`Maybe`関手についてのみ考えることにします。\n" @@ -23839,11 +24019,11 @@ msgstr "" #. type: Plain text #: text/chapter7.md:209 msgid "" -"`pure` lifts pure (side-effect free) values into the larger language, and " -"for functions, we can use `map` and `apply` as described above." +"`pure` lifts pure (side-effect free) values into the larger language; for " +"functions, we can use `map` and `apply` as described above." msgstr "" "`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数につ" -"いては上で述べた通り`map`と`apply`を使うことができます。" +"いては上で述べた通り`map`と`apply`を使えます。" #. type: Plain text #: text/chapter7.md:211 @@ -23916,22 +24096,23 @@ msgstr "" "> fullName \"Phillip\" \"A\" \"Freeman\"\n" "Freeman, Phillip A\n" +# XXX: Maybeを行中コードとしてマークアップしたいです。 #. type: Plain text #: text/chapter7.md:230 msgid "" -"Now suppose that this function forms the implementation of a (very simple!) " -"web service with the three arguments provided as query parameters. We want " -"to make sure that the user provided each of the three parameters, so we " -"might use the `Maybe` type to indicate the presence or otherwise absence of " -"a parameter. We can lift `fullName` over `Maybe` to create an implementation " -"of the web service which checks for missing parameters:" +"Suppose that this function forms the implementation of a (very simple!) web " +"service with the three arguments provided as query parameters. We want to " +"ensure that the user provided each of the three parameters, so we might use " +"the Maybe type to indicate the presence or absence of a parameter. We can " +"lift `fullName` over `Maybe` to create an implementation of the web service " +"which checks for missing parameters:" msgstr "" -"この関数は、クエリパラメータとして与えられた3つの引数を持つ、(とっても簡単" -"な)webサービスの実装であるとしましょう。\n" -"使用者が3つの引数全てを与えたことを確かめたいので、引数が存在するかどうかを表" -"す`Maybe`型を使うことになるでしょう。\n" -"`fullName`を`Maybe`の上へ持ち上げると、省略された引数を確認するwebサービスを" -"実装できます。" +"この関数が、クエリ引数として与えられた3つの引数を持つ、(とっても簡単な)web" +"サービスの実装を形成しているとしましょう。\n" +"使用者が3つの各引数を与えたことを確かめたいので、引数が存在するかどうかを表す" +"`Maybe`型を使うことになるでしょう。\n" +"`fullName`を`Maybe`の上へ持ち上げると、欠けている引数を検査するwebサービスの" +"実装を作成できます。" #. type: Fenced code block (text) #: text/chapter7.md:231 @@ -23955,8 +24136,8 @@ msgstr "" #. type: Plain text #: text/chapter7.md:242 text/chapter7.md:292 text/chapter7.md:444 -#: text/chapter7.md:479 text/chapter7.md:525 text/chapter7.md:557 -msgid "or with _applicative do_" +#: text/chapter7.md:479 text/chapter7.md:525 +msgid "Or with _applicative do_:" msgstr "または*アプリカティブdo*で次のようにします。" #. type: Fenced code block (text) @@ -24013,14 +24194,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:267 msgid "" -"This is good, because now we can send an error response back from our web " +"This is good because now we can send an error response back from our web " "service if the parameters are invalid. However, it would be better if we " "could indicate which field was incorrect in the response." msgstr "" -"これで、もし引数が不正ならWebサービスからエラー応答を送信できるので、なかなか" -"いい感じです。\n" -"しかし、どのフィールドが間違っていたのかを応答で示せると、もっと良くなるで" -"しょう。" +"引数が不正のときにwebサービスからエラー応答を送り返せるのは良いことです。\n" +"しかし、どのフィールドが不正確なのかを応答で示せると、もっと良くなるでしょ" +"う。" #. type: Plain text #: text/chapter7.md:269 @@ -24031,9 +24211,9 @@ msgid "" "`Either String`:" msgstr "" "`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エ" -"ラーメッセージを返すことができるようになります。\n" -"まずは`Either String`を使ってオプショナルな入力をエラーを発信できる計算に変換" -"する演算子を書きましょう。" +"ラー文言を返せるようになります。\n" +"まずは`Either String`を使い、省略可能な入力からエラーを発信できる計算に変換す" +"る演算子を書きましょう。" #. type: Fenced code block (text) #: text/chapter7.md:270 @@ -24067,7 +24247,7 @@ msgid "" "for each parameter:" msgstr "" "これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー" -"メッセージを提供できるようになります。" +"文言を提供できるようになります。" #. type: Fenced code block (text) #: text/chapter7.md:282 @@ -24113,14 +24293,15 @@ msgstr "" "> :type fullNameEither\n" "Maybe String -> Maybe String -> Maybe String -> Either String String\n" +# FIXME: Maybeの行中コードのマークアップが崩れている気がします。 #. type: Plain text #: text/chapter7.md:307 msgid "" -"Now our function takes three optional arguments using `Maybe`, and returns " -"either a `String` error message or a `String` result." +"Now our function takes three optional arguments using `Maybe, and returns " +"either a`String` error message or a `String` result." msgstr "" -"これでこの関数は`Maybe`の3つの省略可能な引数を取り、`String`のエラーメッセー" -"ジか`String`の結果のどちらかを返します。" +"これでこの関数は`Maybe`を使う3つの省略可能な引数を取り、`String`のエラー文言" +"か`String`の結果のどちらかを返します。" #. type: Plain text #: text/chapter7.md:309 @@ -24153,14 +24334,12 @@ msgstr "" #: text/chapter7.md:322 msgid "" "In this case, we see the error message corresponding to the first missing " -"field, or a successful result if every field was provided. However, if we " -"are missing multiple inputs, we still only see the first error:" +"field or a successful result if every field was provided. However, if we are " +"missing multiple inputs, we still only see the first error:" msgstr "" "このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省" -"略されたフィールドのうち最初のものに対応するエラーメッセージが表示されま" -"す。\n" -"しかし、もし複数の入力が省略されているとき、最初のエラーしか見ることができま" -"せん。" +"略されたフィールドのうち最初のものに対応するエラー文言が表示されます。\n" +"しかし、もし複数の入力が省略されているとき、最初のエラーしか見られません。" #. type: Fenced code block (text) #: text/chapter7.md:323 @@ -24193,11 +24372,11 @@ msgstr "作用の結合" #: text/chapter7.md:333 msgid "" "As an example of working with applicative functors abstractly, this section " -"will show how to write a function which will generically combine side-" -"effects encoded by an applicative functor `f`." +"will show how to write a function that generically combines side-effects " +"encoded by an applicative functor `f`." msgstr "" -"抽象的にアプリカティブ関手を扱う例として、アプリカティブ関手`f`によって表現さ" -"れた副作用を一般的に組み合わせる関数を書く方法をこの節では示します。" +"抽象的にアプリカティブ関手を扱う例として、この節ではアプリカティブ関手`f`に" +"よって表現された副作用を一般的に組み合わせる関数を書く方法を示します。" #. type: Plain text #: text/chapter7.md:335 @@ -24225,12 +24404,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:337 #, no-wrap -msgid "For any fixed list size `n`, there is a function of `n` arguments which builds a list of size `n` out of those arguments. For example, if `n` is `3`, the function is `\\x y z -> x : y : z : Nil`. This function has type `a -> a -> a -> List a`. We can use the `Applicative` instance for `List` to lift this function over `f`, to get a function of type `f a -> f a -> f a -> f (List a)`. But, since we can do this for any `n`, it makes sense that we should be able to perform the same lifting for any _list_ of arguments.\n" +msgid "For any fixed list size `n`, there is a function of `n` arguments that builds a list of size `n` out of those arguments. For example, if `n` is `3`, the function is `\\x y z -> x : y : z : Nil`. This function has type `a -> a -> a -> List a`. We can use the `Applicative` instance for `List` to lift this function over `f`, to get a function of type `f a -> f a -> f a -> f (List a)`. But, since we can do this for any `n`, it makes sense that we should be able to perform the same lifting for any _list_ of arguments.\n" msgstr "" -"任意の固定長リストの長さ`n`について、その引数を要素に持った長さ`n`のリストを構築するような`n`引数の関数が存在します。\n" +"任意の固定長リストの長さ`n`について、`n`引数からその引数を要素に持つ長さ`n`のリストを構築する関数が存在します。\n" "例えばもし`n`が`3`なら、関数は`\\x y z -> x : y : z : Nil`です。\n" -"この関数の型は`a -> a -> a -> List a`です。\n" -"`Applicative`インスタンスを使うと、この関数を`f`の上へ持ち上げて関数型`f a -> f a -> f a -> f (List a)`を得ることができます。\n" +"この関数は型`a -> a -> a -> List a`を持ちます。\n" +"`Applicative`インスタンスを使うと、この関数を`f`の上へ持ち上げられ、関数型`f a -> f a -> f a -> f (List a)`が得られます。\n" "しかし、いかなる`n`についてもこれが可能なので、いかなる引数の*リスト*についても同じように持ち上げられることが確かめられます。\n" #. type: Plain text @@ -24331,30 +24510,30 @@ msgstr "" #: text/chapter7.md:376 msgid "" "When specialized to `Maybe`, our function returns a `Just` only if every " -"list element was `Just`, otherwise it returns `Nothing`. This is consistent " +"list element is `Just`; otherwise, it returns `Nothing`. This is consistent " "with our intuition of working in a larger language supporting optional " -"values - a list of computations which return optional results only has a " +"values – a list of computations that produce optional results only has a " "result itself if every computation contained a result." msgstr "" -"`Meybe`へ特殊化して考えると、リストの全ての要素が`Just`であるときに限りこの関" -"数は`Just`を返しますし、そうでなければ`Nothing`を返します。\n" -"これはオプショナルな値に対応する、より大きな言語に取り組む上での直感から一貫" -"しています。\n" -"オプショナルな結果を返す計算のリストは、全ての計算が結果を持っているならばそ" -"れ自身の結果のみを持つのです。" +"`Meybe`へ特殊化すると、リストの全ての要素が`Just`であるときに限りこの関数は" +"`Just`を返しますし、そうでなければ`Nothing`を返します。\n" +"これは省略可能な値に対応する、より大きな言語に取り組む上での直感と一貫してい" +"ます。\n" +"省略可能な結果を生む計算のリストは、全ての計算が結果を持っているならばそれ自" +"身の結果のみを持つのです。" #. type: Plain text #: text/chapter7.md:378 #, no-wrap -msgid "But the `combineList` function works for any `Applicative`! We can use it to combine computations which possibly signal an error using `Either err`, or which read from a global configuration using `r ->`.\n" +msgid "But the `combineList` function works for any `Applicative`! We can use it to combine computations that possibly signal an error using `Either err`, or which read from a global configuration using `r ->`.\n" msgstr "" -"しかし、`combineList`関数はどんな`Applicative`に対しても機能します。\n" -"`Either err`を使ってエラーを発信する可能性を持たせたり、`r ->`を使って大域的な状態を読み取る計算を連鎖させるときにも使えるのです。\n" +"ところが`combineList`関数はどんな`Applicative`に対しても機能するのです。\n" +"`Either err`を使ってエラーを発信する可能性を持たせたり、`r ->`を使って大域的な構成を読み取る計算を組み合わせるためにも使えます。\n" #. type: Plain text #: text/chapter7.md:380 msgid "" -"We will see the `combineList` function again later, when we consider " +"We will see the `combineList` function again later when we consider " "`Traversable` functors." msgstr "" "`combineList`関数については、後ほど`Traversable`関手について考えるときに再訪" @@ -24363,15 +24542,16 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:386 msgid "" -"(Medium) Write versions of the numeric operators `+`, `-`, `*` and `/` which " -"work with optional arguments (i.e. arguments wrapped in `Maybe`) and return " -"a value wrapped in `Maybe`. Name these functions `addMaybe`, `subMaybe`, " -"`mulMaybe`, and `divMaybe`. _Hint_: Use `lift2`." +"(Medium) Write versions of the numeric operators `+`, `-`, `*`, and `/` " +"which work with optional arguments (i.e., arguments wrapped in `Maybe`) and " +"return a value wrapped in `Maybe`. Name these functions `addMaybe`, " +"`subMaybe`, `mulMaybe`, and `divMaybe`. _Hint_: Use `lift2`." msgstr "" -"(普通)数値演算子`+`、`-`、`*`、`/`のオプショナル引数(つまり`Maybe`に包まれ" -"た引数)を扱って`Maybe`に包まれた値を返す版を書いてください。\n" -"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けま" -"す。\n" +"(普通)数値演算子`+`、`-`、`*`、`/`の別のバージョンを書いてください。\n" +"ただし省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた" +"値を返します。\n" +"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けて" +"ください。\n" "*手掛かり*:`lift2`を使ってください。" #. type: Bullet: ' 1. ' @@ -24391,27 +24571,26 @@ msgstr "" msgid "" "(Difficult) Write a function `combineMaybe` which has type `forall a f. " "Applicative f => Maybe (f a) -> f (Maybe a)`. This function takes an " -"optional computation with side-effects, and returns a side-effecting " -"computation which has an optional result." +"optional computation with side-effects and returns a side-effecting " +"computation with an optional result." msgstr "" -"(難しい)型`combineMaybe : forall a f. (Applicative f) => Maybe (f a) -> f " -"(Maybe a)`\n" -"を持つ関数`combineMaybe`を書いてください。\n" -"この関数は副作用をもつオプショナルな計算をとり、オプショナルな結果をもつ副作" -"用のある計算を返します。" +"(難しい)型`forall a f. Applicative f => Maybe (f a) -> f (Maybe a)`を持つ関" +"数`combineMaybe`を書いてください。\n" +"この関数は副作用を持つ省略可能な計算を取り、省略可能な結果を持つ副作用のある" +"計算を返します。" #. type: Plain text #: text/chapter7.md:390 msgid "" "The source code for this chapter defines several data types which might be " "used in an address book application. The details are omitted here, but the " -"key functions which are exported by the `Data.AddressBook` module have the " -"following types:" +"key functions exported by the `Data.AddressBook` module have the following " +"types:" msgstr "" -"この章のソースコードでは住所録アプリケーションで使うことのできるいろいろな" -"データ型が定義されています。\n" +"この章のソースコードでは住所録アプリケーションで使うであろう幾つかのデータ型" +"が定義されています。\n" "詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされ" -"る重要な関数は次のような型を持っています。" +"る鍵となる関数は次のような型を持ちます。" #. type: Fenced code block (haskell) #: text/chapter7.md:391 @@ -24431,7 +24610,7 @@ msgstr "" #. type: Plain text #: text/chapter7.md:400 -msgid "where `PhoneType` is defined as an algebraic data type:" +msgid "Where `PhoneType` is defined as an algebraic data type:" msgstr "ここで、`PhoneType`は次のような代数的データ型として定義されています。" #. type: Fenced code block (haskell) @@ -24443,12 +24622,11 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook.purs:PhoneType}}\n #. type: Plain text #: text/chapter7.md:406 msgid "" -"These functions can be used to construct a `Person` representing an address " -"book entry. For example, the following value is defined in `Data." -"AddressBook`:" +"These functions can construct a `Person` representing an address book entry. " +"For example, the following value is defined in `Data.AddressBook`:" msgstr "" -"これらの関数は住所録の項目を表す`Person`を構築するのに使えます。\n" -"例えば、`Data.AddressBook`には次のような値が定義されています。" +"これらの関数は住所録の項目を表す`Person`を構築できます。\n" +"例えば、`Data.AddressBook`では以下の値が定義されています。" #. type: Fenced code block (haskell) #: text/chapter7.md:407 @@ -24540,12 +24718,12 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va msgid "" "In the first two lines, we use the `nonEmpty1` function to validate a non-" "empty string. `nonEmpty1` returns an error indicated with the `Left` " -"constructor if its input is empty, otherwise it returns the value wrapped " +"constructor if its input is empty. Otherwise, it returns the value wrapped " "with the `Right` constructor." msgstr "" -"最初の2行では`nonEmpty`関数を使って空文字列でないことを検証しています。\n" -"もし入力が空なら`nonEMpty`はエラーを返し(`Left`構築子で示されています)、そ" -"うでなければ`Right`構築子を使って値を包んで返します。" +"最初の2行では`nonEmpty1`関数を使って空文字列でないことを検証しています。\n" +"もし入力が空なら`nonEmpty1`は`Left`構築子で示されるエラーを返します。\n" +"そうでなければ`Right`構築子で包まれた値を返します。" #. type: Plain text #: text/chapter7.md:452 @@ -24560,7 +24738,7 @@ msgstr "" #. type: Plain text #: text/chapter7.md:454 msgid "" -"This function can be seen to work in PSCi, but has a limitation which we " +"This function can be seen to work in PSCi, but it has a limitation that we " "have seen before:" msgstr "" "この関数はPSCiでうまく動作するように見えますが、以前見たような制限がありま" @@ -24580,26 +24758,25 @@ msgstr "" #: text/chapter7.md:461 msgid "" "The `Either String` applicative functor only provides the first error " -"encountered. Given the input here, we would prefer to see two errors - one " -"for the missing first name, and a second for the missing last name." +"encountered. Given the input here, we would prefer to see two errors – one " +"for the missing first name and a second for the missing last name." msgstr "" -"`Either String`アプリカティブ関手は遭遇した最初のエラーだけを返します。\n" -"でもこの入力では、名前の不足と姓の不足という2つのエラーがわかるようにしたくな" -"るでしょう。" +"`Either String`アプリカティブ関手は最初に遭遇したエラーだけを返します。\n" +"仮にこの入力だったとすると、2つのエラーが分かったほうが良いでしょう。\n" +"1つは名前の不足で、2つ目は姓の不足です。" #. type: Plain text #: text/chapter7.md:463 msgid "" -"There is another applicative functor which is provided by the `validation` " -"library. This functor is called `V`, and it provides the ability to return " -"errors in any _semigroup_. For example, we can use `V (Array String)` to " -"return an array of `String`s as errors, concatenating new errors onto the " -"end of the array." +"There is another applicative functor that the `validation` library provides. " +"This functor is called `V`, and it can return errors in any _semigroup_. For " +"example, we can use `V (Array String)` to return an array of `String`s as " +"errors, concatenating new errors onto the end of the array." msgstr "" "`validation`ライブラリでは別のアプリカティブ関手も提供されています。\n" -"これは単に`V`と呼ばれていて、何らかの*半群*でエラーを返す機能があります。\n" +"これは`V`という名前で、何らかの*半群*でエラーを返せます。\n" "例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、" -"`String`の配列をエラーとして返すことができます。" +"`String`の配列をエラーとして返せます。" #. type: Plain text #: text/chapter7.md:465 @@ -24650,8 +24827,8 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #: text/chapter7.md:485 msgid "" "`validateAddress` validates an `Address` structure. It checks that the " -"`street` and `city` fields are non-empty, and checks that the string in the " -"`state` field has length 2." +"`street` and `city` fields are non-empty and that the string in the `state` " +"field has length 2." msgstr "" "`validateAddress`は`Address`の構造を検証します。\n" "`street`と`city`が空でないかどうか、`state`の文字列の長さが2であるかどうかを" @@ -24806,7 +24983,7 @@ msgstr "" msgid "" "(Medium) Write a regular expression `nonEmptyRegex :: Regex` to check that a " "string is not entirely whitespace. _Hint_: If you need help developing this " -"regex expression, check out [RegExr](https://regexr.com) which has a great " +"regex expression, check out [RegExr](https://regexr.com), which has a great " "cheatsheet and interactive test environment." msgstr "" "(普通)文字列全体が空白でないことを検査する正規表現`nonEmptyRegex :: Regex`" @@ -24859,6 +25036,11 @@ msgstr "" "\n" "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson}}\n" +#. type: Plain text +#: text/chapter7.md:557 +msgid "or with _applicative do_" +msgstr "または*アプリカティブdo*で次のようにします。" + #. type: Fenced code block (haskell) #: text/chapter7.md:558 #, no-wrap @@ -24868,11 +25050,11 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:563 msgid "" -"`validatePhoneNumbers` uses a new function we haven't seen before - " +"`validatePhoneNumbers` uses a new function we haven't seen before – " "`traverse`." msgstr "" -"`validatePhoneNumbers`はこれまでに見たことのない新しい関数、`traverse`を使い" -"ます。" +"`validatePhoneNumbers`はこれまでに見たことのない新しい関数である`traverse`を" +"使っています。" #. type: Plain text #: text/chapter7.md:565 @@ -24910,16 +25092,15 @@ msgstr "" #: text/chapter7.md:575 msgid "" "Every traversable functor is both a `Functor` and `Foldable` (recall that a " -"_foldable functor_ was a type constructor which supported a fold operation, " +"_foldable functor_ was a type constructor that supported a fold operation, " "reducing a structure to a single value). In addition, a traversable functor " -"provides the ability to combine a collection of side-effects which depend on " -"its structure." +"can combine a collection of side-effects that depend on its structure." msgstr "" "全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能" -"関手*は、構造を1つの値へと纏める畳み込み操作を提供する型構築子であったことを" -"思い出してください)。\n" -"それに加えて、`Traversable`関手はその構造に依存した副作用の集まりを連結する機" -"能を提供します。" +"関手*は畳み込み操作に対応する型構築子であったことを思い出してください。\n" +"畳み込みとは構造を1つの値へと簡約するものでした)。\n" +"それに加えて、巡回可能関手はその構造に依存した副作用の集まりを組み合わせられ" +"ます。" #. type: Plain text #: text/chapter7.md:577 @@ -24975,15 +25156,15 @@ msgid "" "type `a`, then `traverse m` is a validation function for arrays of type " "`Array a`. But that's exactly what we need to be able to validate the " "`phones` field of the `Person` data structure! We pass `validatePhoneNumber` " -"to `traverse` to create a validation function which validates each element " +"to `traverse` to create a validation function that validates each element " "successively." msgstr "" -"この型シグネチャは、型`a`についての検証関数`m`があれば、`traverse m`は型" -"`Array a`の配列についての検証関数であるということを言っています。\n" -"これはまさに、今必要になっている`Person`データ構造体の`phones`フィールドを検" -"証する検証器そのものです。\n" -"それぞれの要素が成功するかどうかを検証する検証関数を作るために、" -"`validatePhoneNumber`を`traverse`へ渡しています。" +"この型シグネチャでは、型`a`についての検証関数`m`があれば、`traverse m`は型" +"`Array a`の配列についての検証関数であると書かれています。\n" +"ところがこれは正に`Person`データ構造体の`phones`フィールドを検証できるように" +"するのに必要なものです。\n" +"各要素が成功するかを検証する検証関数を作るために、`validatePhoneNumber`を" +"`traverse`へ渡しています。" #. type: Plain text #: text/chapter7.md:593 @@ -24992,7 +25173,7 @@ msgid "" "performing computations with side-effects and accumulating a result." msgstr "" "一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算" -"し、結果を累積します。" +"し、結果を累算します。" #. type: Plain text #: text/chapter7.md:595 @@ -25027,13 +25208,15 @@ msgid "" "Traversable functors capture the idea of traversing a data structure, " "collecting a set of effectful computations, and combining their effects. In " "fact, `sequence` and `traverse` are equally important to the definition of " -"`Traversable` - each can be implemented in terms of each other. This is left " +"`Traversable` – each can be implemented in terms of the other. This is left " "as an exercise for the interested reader." msgstr "" -"巡回可能関手は、作用のある計算を集めてその作用を結合するという、データ構造走" -"査の考え方を見据えたものです。実際、`sequence`と`traversable`は`Traversable`" -"を定義する上でどちらも同じくらい重要です。これらはお互いがお互いを利用して実" -"装できます。これについては興味ある読者への演習として残しておきます。" +"巡回可能関手はデータ構造走査の考え方を見据えたものです。\n" +"これにより作用のある計算の集合を集めてその作用を結合します。\n" +"実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくら" +"い重要です。\n" +"これらはお互いがお互いを利用して実装できます。\n" +"これについては興味ある読者への演習として残しておきます。" #. type: Plain text #: text/chapter7.md:609 @@ -25070,17 +25253,18 @@ msgstr "" #. type: Plain text #: text/chapter7.md:620 msgid "" -"In the case of an empty list, we can simply return an empty list using " -"`pure`. If the list is non-empty, we can use the function `f` to create a " -"computation of type `f b` from the head element. We can also call `traverse` " -"recursively on the tail. Finally, we can lift the `Cons` constructor over " -"the applicative functor `m` to combine the two results." +"In the case of an empty list, we can return an empty list using `pure`. If " +"the list is non-empty, we can use the function `f` to create a computation " +"of type `f b` from the head element. We can also call `traverse` recursively " +"on the tail. Finally, we can lift the `Cons` constructor over the " +"applicative functor `m` to combine the two results." msgstr "" -"入力が空のリストのときには、単に`pure`を使って空の配列を返すことができます。" -"配列が空でないときは、関数`f`を使うと先頭の要素から型`f b`の計算を作成できま" -"す。また、配列の残りに対して`traverse`を再帰的に呼び出すことができます。最後" -"に、アプリカティブ関手`m`まで`Cons`構築子を持ち上げて、2つの結果を組み合わせ" -"ます。" +"入力が空のリストのときには、`pure`を使って空のリストを返せます。\n" +"リストが空でないときは、関数`f`を使うと先頭の要素から型`f b`の計算を作成でき" +"ます。\n" +"また、尾鰭に対して`traverse`を再帰的に呼び出せます。\n" +"最後に、アプリカティブ関手`m`まで`Cons`構築子を持ち上げて、2つの結果を組み合" +"わせられます。" #. type: Plain text #: text/chapter7.md:622 @@ -25129,26 +25313,29 @@ msgid "" "These examples show that traversing the `Nothing` value returns `Nothing` " "with no validation, and traversing `Just x` uses the validation function to " "validate `x`. That is, `traverse` takes a validation function for type `a` " -"and returns a validation function for `Maybe a`, i.e. a validation function " +"and returns a validation function for `Maybe a`, i.e., a validation function " "for optional values of type `a`." msgstr "" "これらの例では、`Nothing`の値の走査は検証なしで`Nothing`の値を返し、`Just x`" "を走査すると`x`を検証するのに検証関数が使われるということを示しています。\n" -"要は、`traverse`は型`a`についての検証関数をとり、`Maybe a`についての検証関" -"数、つまり型`a`のオプショナルな値についての検証関数を返すのです。" +"要は、`traverse`は型`a`についての検証関数を取り、`Maybe a`についての検証関" +"数、つまり型`a`の省略可能な値についての検証関数を返すのです。" +# FIXME: Arrayに型変数を入れた方が種として分かりやすそうです。 #. type: Plain text #: text/chapter7.md:641 msgid "" -"Other traversable functors include `Array`, and `Tuple a` and `Either a` for " +"Other traversable functors include `Array`, `Tuple a`, and `Either a` for " "any type `a`. Generally, most \"container\" data type constructors have " "`Traversable` instances. As an example, the exercises will include writing a " "`Traversable` instance for a type of binary trees." msgstr "" -"他の巡回可能関手には`Array`、また任意の型`a`について`Tuple a`、`Either a`が含" -"まれます。一般的に、「容器」のようなデータの型構築子は大抵`Traversable`インス" -"タンスを持っています。例として、演習では二分木の型の`Traversable`インスタンス" -"を書くことになります。" +"他の巡回可能関手には、任意の型`a`についての`Array a`、`Tuple a`、`Either a`が" +"含まれます。\n" +"一般に、「容器」のようなほとんどのデータ型構築子は`Traversable`インスタンスを" +"持っています。\n" +"一例として、演習には二分木の型の`Traversable`インスタンスを書くことが含まれま" +"す。" #. type: Bullet: ' 1. ' #: text/chapter7.md:645 @@ -25174,17 +25361,17 @@ msgstr "" #. type: Plain text #: text/chapter7.md:651 #, no-wrap -msgid " Recall from the previous chapter that you may either write these instances manually or let the compiler derive them for you.\n" +msgid " Recall from the previous chapter that you may either write these instances manually or let the compiler derive them.\n" msgstr " これらのインスタンスを手作業で書くこともできますし、コンパイラに導出してもらうこともできることを前の章から思い起こしてください。\n" #. type: Plain text #: text/chapter7.md:653 #, no-wrap -msgid " There are many \"correct\" formatting options for `Show` output. The test for this exercise expects the following whitespace style. This happens to match the default formatting of generic show, so you only need to make note of this if you're planning on writing this instance manually.\n" +msgid " There are many \"correct\" formatting options for `Show` output. The test for this exercise expects the following whitespace style. This matches the default formatting of the generic show, so you only need to note this if you're planning on writing this instance manually.\n" msgstr "" " `Show`の出力には多くの「正しい」書式の選択肢があります。\n" " この演習のテストでは以下の空白スタイルを期待しています。\n" -" これはたまたま一般化されたshowの既定の書式と合致しているため、このインスタンスを手作業で書くつもりのときだけ、このことを念頭に置いておいてください。\n" +" これは一般化されたshowの既定の書式と合致しているため、このインスタンスを手作業で書くつもりのときだけ、このことを念頭に置いておいてください。\n" #. type: Plain text #: text/chapter7.md:657 @@ -25202,7 +25389,7 @@ msgstr "" #: text/chapter7.md:659 msgid "" "(Medium) Write a `Traversable` instance for `Tree a`, which combines side-" -"effects from left-to-right. _Hint_: There are some additional instance " +"effects left-to-right. _Hint_: There are some additional instance " "dependencies that need to be defined for `Traversable`." msgstr "" "(普通)`Traversable`インスタンスを`Tree a`に対して書いてください。\n" @@ -25218,8 +25405,8 @@ msgid "" "of the tree. This means the order of effect execution is root-left-right, " "instead of left-root-right as was done for the previous in-order traverse " "exercise. _Hint_: No additional instances need to be defined, and you don't " -"need to call any of the the functions defined earlier. Applicative do " -"notation (`ado`) is the easiest way to write this function." +"need to call any of the functions defined earlier. Applicative do notation " +"(`ado`) is the easiest way to write this function." msgstr "" "(普通)行き掛け順に木を巡回する関数`traversePreOrder :: forall a m b. " "Applicative m => (a -> m b) -> Tree a -> m (Tree b)`を書いてください。\n" @@ -25247,7 +25434,7 @@ msgid "" "this new `Person`. _Hint_: Use `traverse` to validate a field of type `Maybe " "a`." msgstr "" -"(普通)`homeAddress`フィールドがオプショナル(`Maybe`を使用)な新しい版の" +"(普通)`homeAddress`フィールドが省略可能(`Maybe`を使用)な新しい版の" "`Person`型をつくってください。\n" "それからこの新しい`Person`を検証する新しい版の`validatePerson`" "(`validatePersonOptionalAddress`と改名します)を書いてください。\n" @@ -25301,14 +25488,13 @@ msgstr "" msgid "" "However, in general, applicative functors are more general than this. The " "applicative functor laws do not impose any ordering on the side-effects that " -"their computations perform. In fact, it would be valid for an applicative " -"functor to perform its side-effects in parallel." +"their computations perform. It would be valid for an applicative functor to " +"perform its side-effects in parallel." msgstr "" "しかし一般には、アプリカティブ関手はこれよりももっと一般的です。\n" "アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しませ" "ん。\n" -"実際、並列に副作用を実行するためのアプリカティブ関手というものは妥当になりえ" -"ます。" +"実際、並列に副作用を実行するアプリカティブ関手は妥当でしょう。" #. type: Plain text #: text/chapter7.md:677 @@ -25319,8 +25505,8 @@ msgid "" "run them in parallel over the data structure!" msgstr "" "例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだ" -"としてもやはり正常に動き、このときどんな順序でそれぞれの検証器を実行しても問" -"題はありません。\n" +"としてもやはり正常に動き、このときどんな順序で各検証器を実行しても問題はあり" +"ません。\n" "データ構造に対して並列にこれの実行さえできるのです。" #. type: Plain text @@ -25328,13 +25514,13 @@ msgstr "" msgid "" "As a second example, the `parallel` package provides a type class `Parallel` " "which supports _parallel computations_. `Parallel` provides a function " -"`parallel` which uses some `Applicative` functor to compute the result of " -"its input computation _in parallel_:" +"`parallel` that uses some `Applicative` functor to compute the result of its " +"input computation _in parallel_:" msgstr "" -"別の例として、`parallel`パッケージは、*並列計算*に対応する`Parallel`型クラス" -"を与えます。\n" +"2つ目の例として、`parallel`パッケージは*並列計算*に対応する`Parallel`型クラス" +"を提供します。\n" "`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入" -"力の計算を*並列に*計算できます。" +"力の計算の結果を*並列に*計算します。" #. type: Fenced code block (haskell) #: text/chapter7.md:680 @@ -25369,10 +25555,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:690 msgid "" -"Applicative functors are a natural way to capture side-effects which can be " +"Applicative functors are a natural way to capture side-effects that can be " "combined in parallel." -msgstr "" -"アプリカティブ関手は並列に結合できる副作用を一纏めにする自然な方法です。" +msgstr "アプリカティブ関手は並列に結合できる副作用を捉える自然な方法です。" #. type: Plain text #: text/chapter7.md:694 @@ -25383,23 +25568,25 @@ msgstr "この章では新しい考え方を沢山扱いました。" #: text/chapter7.md:698 msgid "" "We introduced the concept of an _applicative functor_ which generalizes the " -"idea of function application to type constructors which capture some notion " +"idea of function application to type constructors that captures some notion " "of side-effect." msgstr "" -"関数適用の概念を副作用の観念を捉えた型構築子へと一般化する、 _アプリカティブ" -"関手_ の概念を導入しました。" +"*アプリカティブ関手*の概念を導入しました。\n" +"これは、関数適用の概念から副作用の観念を捉えた型構築子へと一般化するもので" +"す。" #. type: Bullet: '- ' #: text/chapter7.md:698 msgid "" -"We saw how applicative functors gave a solution to the problem of validating " -"data structures, and how by switching the applicative functor we could " -"change from reporting a single error to reporting all errors across a data " +"We saw how applicative functors solved the problem of validating data " +"structures and how by switching the applicative functor, we could change " +"from reporting a single error to reporting all errors across a data " "structure." msgstr "" -"データ構造の検証という課題にアプリカティブ関手がどのような解決策を与えるか、" -"どうすれば単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変換" -"できるのかを見てきました。" +"データ構造の検証という課題をアプリカティブ関手やその切り替えで解く方法を見て" +"きました。\n" +"単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変更できまし" +"た。" #. type: Bullet: '- ' #: text/chapter7.md:698 @@ -25411,25 +25598,26 @@ msgstr "" "`Traversable`型クラスに出会いました。*巡回可能関手*の考え方を内包するものであ" "り、要素が副作用を持つ値の結合に使うことができる容れ物でした。" +# FIXME: DSLの行中強調が欠けています。 #. type: Plain text #: text/chapter7.md:700 msgid "" -"Applicative functors are an interesting abstraction which provide neat " +"Applicative functors are an interesting abstraction that provides neat " "solutions to a number of problems. We will see them a few more times " "throughout the book. In this case, the validation applicative functor " "provided a way to write validators in a declarative style, allowing us to " "define _what_ our validators should validate and not _how_ they should " "perform that validation. In general, we will see that applicative functors " -"are a useful tool for the design of _domain specific languages_." +"are a useful tool for the design of _domain specific languages." msgstr "" "アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化で" "す。\n" "本書を通じて何度も見ることになるでしょう。\n" "今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、" -"これにより検証器が*どうやって*検証するかではなく、*何を*検証すべきなのかを定" -"義できました。\n" -"一般に、アプリカティブ関手は*領域特化言語*を設計する上で便利な道具になりま" -"す。" +"これにより検証器が*どうやって*検証を実施するかではなく、*何を*検証すべきなの" +"かを定義できました。\n" +"一般にアプリカティブ関手が*領域特化言語*を設計する上で便利な道具になることを" +"見ていきます。" #. type: Plain text #: text/chapter7.md:701 @@ -25449,23 +25637,25 @@ msgstr "作用モナド" #. type: Plain text #: text/chapter8.md:6 msgid "" -"In the last chapter, we introduced applicative functors, an abstraction " -"which we used to deal with _side-effects_: optional values, error messages " -"and validation. This chapter will introduce another abstraction for dealing " -"with side-effects in a more expressive way: _monads_." +"In the last chapter, we introduced applicative functors, an abstraction we " +"used to deal with _side-effects_: optional values, error messages, and " +"validation. This chapter will introduce another abstraction for dealing with " +"side-effects more expressively: _monads_." msgstr "" -"前章では、オプショナルな型やエラーメッセージ、データの検証など、 _副作用_ を" -"扱いを抽象化するアプリカティブ関手を導入しました。この章では、より表現力の高" -"い方法で副作用を扱うための別の抽象化、 _モナド_ を導入します。" +"前章では、*副作用*を扱うのに使う抽象化であるアプリカティブ関手を導入しまし" +"た。\n" +"副作用とは省略可能な値、エラー文言、検証などです。\n" +"この章では、副作用を扱うためのより表現力の高い別の抽象化である*モナド*を導入" +"します。" #. type: Plain text #: text/chapter8.md:8 msgid "" -"The goal of this chapter is to explain why monads are a useful abstraction, " +"The goal of this chapter is to explain why monads are a useful abstraction " "and their connection with _do notation_." msgstr "" -"この章の目的は、なぜモナドが便利な抽象化なのかということと、 _do記法_ との関" -"係を説明することです。" +"この章の目的は、なぜモナドが便利な抽象化なのかということと、*do記法*との関係" +"を説明することです。" #. type: Plain text #: text/chapter8.md:12 @@ -25475,21 +25665,21 @@ msgstr "このプロジェクトでは、以下の依存関係が追加されて #. type: Bullet: '- ' #: text/chapter8.md:15 msgid "" -"`effect` - defines the `Effect` monad, the subject of the second half of the " +"`effect` – defines the `Effect` monad, the subject of the second half of the " "chapter. This dependency is often listed in every starter project (it's been " -"a dependency of every chapter so far), so you'll rarely have to explicitly " -"install it." +"a dependency of every chapter so far), so you'll rarely have to install it " +"explicitly." msgstr "" -"`effect`: 章の後半の主題である`Effect`モナドを定義しています。この依存関係は" -"全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存" -"関係にありました)、明示的にインストールしなければいけないことは稀です。" +"`effect`: 章の後半の主題である`Effect`モナドを定義しています。\n" +"この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全" +"ての章でも依存関係にありました)、明示的にインストールしなければいけないこと" +"は稀です。" #. type: Bullet: '- ' #: text/chapter8.md:15 msgid "" -"`react-basic-hooks` - a web framework that we will use for our Address Book " -"app." -msgstr "`react-basic-hooks`: アドレス帳アプリに使うWebフレームワークです。" +"`react-basic-hooks` – a web framework we will use for our Address Book app." +msgstr "`react-basic-hooks`: アドレス帳アプリに使うwebフレームワークです。" #. type: Title ## #: text/chapter8.md:16 @@ -25531,18 +25721,15 @@ msgstr "2回目の投擲で値 `y`を _選択_ します。" #. type: Bullet: '- ' #: text/chapter8.md:25 -msgid "" -"If the sum of `x` and `y` is `n` then return the pair `[x, y]`, else fail." -msgstr "" -"もし `x`と `y`の和が `n`なら組 `[x, y]`を返し、そうでなければ失敗します。" +msgid "If the sum of `x` and `y` is `n`, return the pair `[x, y]`, else fail." +msgstr "もし`x`と`y`の和が`n`なら組`[x, y]`を返し、そうでなければ失敗します。" #. type: Plain text #: text/chapter8.md:27 msgid "" -"Array comprehensions allow us to write this non-deterministic algorithm in a " -"natural way:" -msgstr "" -"配列内包表記を使うと、この非決定的アルゴリズムを自然に書くことができます。" +"Array comprehensions allow us to write this non-deterministic algorithm " +"naturally:" +msgstr "配列内包表記を使うと、この非決定的アルゴリズムを自然に書けます。" #. type: Fenced code block (hs) #: text/chapter8.md:28 @@ -25596,7 +25783,7 @@ msgid "" "the _array monad_, embedding PureScript functions into a larger programming " "language supporting _non-deterministic choice_." msgstr "" -"前の章では、*オプショナルな値*に対応したより大きなプログラミング言語へと" +"前の章では、*省略可能な値*に対応したより大きなプログラミング言語へと" "PureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養" "いました。\n" "同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング" @@ -25606,24 +25793,23 @@ msgstr "" #. type: Plain text #: text/chapter8.md:52 msgid "" -"In general, a _monad_ for some type constructor `m` provides a way to use do " +"Generally, a _monad_ for some type constructor `m` provides a way to use do " "notation with values of type `m a`. Note that in the array comprehension " "above, every line contains a computation of type `Array a` for some type " "`a`. In general, every line of a do notation block will contain a " "computation of type `m a` for some type `a` and our monad `m`. The monad `m` " -"must be the same on every line (i.e. we fix the side-effect), but the types " -"`a` can differ (i.e. individual computations can have different result " +"must be the same on every line (i.e., we fix the side-effect), but the types " +"`a` can differ (i.e., individual computations can have different result " "types)." msgstr "" -"一般に、ある型構築子 `m`のモナドは、型 `m a`の値を持つdo記法を使う手段を提供" -"します。\n" -"上の配列内包表記では、全ての行に何らかの型 `a`についての型 `Array a`の計算が" -"含まれていることに注目してください。\n" -"一般に、do記法ブロックの全ての行は、何らかの型 `a`とモナド `m`について、型 " -"`m a`の計算を含んでいます。\n" -"モナド `m`は全ての行で同じでなければなりません(つまり、副作用の種類は固定さ" -"れます)が、型 `a`は異なることもあります(言い換えると、個々の計算は異なる型" -"の結果を持つことができます)。" +"一般に、ある型構築子`m`のモナドは、型`m a`の値を持つdo記法を使う手段を提供し" +"ます。\n" +"上の配列内包表記に注意すると、何らかの型`a`について全行に型`Array a`の計算が" +"含まれています。\n" +"一般に、do記法ブロックの全行は、何らかの型`a`とモナド`m`について、型`m a`の計" +"算を含みます。\n" +"モナド`m`は全行で同じでなければなりません(つまり副作用は固定)が、型`a`は異" +"なることもあります(つまり個々の計算は異なる型の結果にできる)。" #. type: Plain text #: text/chapter8.md:54 @@ -25645,7 +25831,7 @@ msgstr "child :: XML -> String -> Maybe XML\n" #. type: Plain text #: text/chapter8.md:60 msgid "" -"which looks for a child element of a node, and returns `Nothing` if no such " +"Which looks for a child element of a node and returns `Nothing` if no such " "element exists." msgstr "" "この関数はノードの子の要素を探し、もしそのような要素が存在しなければ " @@ -25654,8 +25840,8 @@ msgstr "" #. type: Plain text #: text/chapter8.md:62 msgid "" -"In this case, we can look for a deeply-nested element by using do notation. " -"Suppose we wanted to read a user's city from a user profile which had been " +"In this case, we can look for a deeply-nested element using do notation. " +"Suppose we wanted to read a user's city from a user profile that had been " "encoded as an XML document:" msgstr "" "この場合、do記法を使うと深い入れ子になった要素を検索できます。\n" @@ -25684,15 +25870,15 @@ msgstr "" #: text/chapter8.md:73 msgid "" "The `userCity` function looks for a child element `profile`, an element " -"`address` inside the `profile` element, and finally an element `city` inside " -"the `address` element. If any of these elements are missing, the return " -"value will be `Nothing`. Otherwise, the return value is constructed using " -"`Just` from the `city` node." +"`address` inside the `profile` element, and finally, an element `city` " +"inside the `address` element. If any of these elements are missing, the " +"return value will be `Nothing`. Otherwise, the return value is constructed " +"using `Just` from the `city` node." msgstr "" -"`userCity`関数は子の要素である `profile`を探し、 `profile`要素の中にある " -"`address`要素、最後に `address`要素から `city`要素を探します。\n" -"これらの要素の何れかが欠落している場合は、返り値は `Nothing`になります。\n" -"そうでなければ、返り値は `city`ノードから `Just`を使って構築されています。" +"`userCity`関数は子の`profile`要素、`profile`要素の中にある`address`要素、最後" +"に`address`要素の中にある`city`要素を探します。\n" +"これらの要素の何れかが欠落している場合、返り値は`Nothing`になります。\n" +"そうでなければ、返り値は`city`ノードから`Just`を使って構築されます。" #. type: Plain text #: text/chapter8.md:75 @@ -25742,10 +25928,10 @@ msgstr "ここで鍵となる関数は `Bind`型クラスで定義されてい #: text/chapter8.md:90 msgid "" "The `Monad` type class extends `Bind` with the operations of the " -"`Applicative` type class that we have already seen." +"`Applicative` type class we've already seen." msgstr "" -"`Monad`型クラスは、既に見てきた `Applicative`型クラスの操作で `Bind`を拡張し" -"ます。" +"`Monad`型クラスは、既に見てきた`Applicative`型クラスの操作で`Bind`を拡張しま" +"す。" #. type: Plain text #: text/chapter8.md:92 @@ -25805,12 +25991,12 @@ msgstr "" #: text/chapter8.md:111 msgid "" "Let's see how the `Bind` type class is related to do notation. Consider a " -"simple do notation block which starts by binding a value from the result of " +"simple do notation block that starts by binding a value from the result of " "some computation:" msgstr "" -"`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。最初に何" -"らかの計算結果からの値の束縛から始まる簡単なdo記法ブロックについて考えてみま" -"しょう。" +"`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。\n" +"最初に、何らかの計算結果からの値の束縛から始まる、単純なdo記法ブロックについ" +"て考えてみましょう。" #. type: Fenced code block (hs) #: text/chapter8.md:112 @@ -25884,8 +26070,11 @@ msgstr "" #. type: Plain text #: text/chapter8.md:143 #, no-wrap -msgid "It is worth noting that code expressed using do notation is often much clearer than the equivalent code using the `>>=` operator. However, writing binds explicitly using `>>=` can often lead to opportunities to write code in _point-free_ form - but the usual warnings about readability apply.\n" -msgstr "do記法を使って表現されたコードは、`>>=`演算子を使って書かれた同じ意味のコードよりしばしば読みやすくなることも特筆すべき点です。一方で、明示的に `>>=`を使って束縛を書くと、しばしば*ポイントフリー*形式でコードが書けるようになります。ただし、読みやすさにはやはり注意がいります。\n" +msgid "Notably, code expressed using do notation is often much clearer than the equivalent code using the `>>=` operator. However, writing binds explicitly using `>>=` can often lead to opportunities to write code in _point-free_ form – but the usual warnings about readability apply.\n" +msgstr "" +"do記法を使って表現されたコードは、`>>=`演算子を使う等価なコードより遥かに読みやすくなることがよくあることも特筆すべき点です。\n" +"しかしながら、明示的に`>>=`を使って束縛を書くと、*ポイントフリー*形式でコードが書けるようになることがよくあります。\n" +"ただし、読みやすさにはやはり注意が要ります。\n" #. type: Title ## #: text/chapter8.md:144 @@ -26017,13 +26206,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:192 msgid "" -"Each of these computations involves three monadic expression `m1`, `m2` and " -"`m3`. In each case, the result of `m1` is eventually bound to the name `x`, " -"and the result of `m2` is bound to the name `y`." +"Each of these computations involves three monadic expressions `m1`, `m2`, " +"and `m3`. In each case, the result of `m1` is eventually bound to the name " +"`x`, and the result of `m2` is bound to the name `y`." msgstr "" -"これらの計算にはそれぞれ、3つのモナドの式`m1`、`m2`、`m3`が含まれています。\n" -"どちらの場合でも`m1`の結果は名前`x`に束縛され、`m2`の結果は名前`y`に束縛され" -"ます。" +"これらの各計算には3つのモナドの式`m1`、`m2`、`m3`が含まれています。\n" +"どちらの場合でも`m1`の結果は結局は名前`x`に束縛され、`m2`の結果は名前`y`に束" +"縛されます。" #. type: Plain text #: text/chapter8.md:194 @@ -26031,13 +26220,12 @@ msgid "" "In `c1`, the two expressions `m1` and `m2` are grouped into their own do " "notation block." msgstr "" -"`c1`では2つの式 `m1`と `m2`がそれぞれのdo記法ブロック内にグループ化されていま" -"す。" +"`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグループ化されています。" #. type: Plain text #: text/chapter8.md:196 msgid "" -"In `c2`, all three expressions `m1`, `m2` and `m3` appear in the same do " +"In `c2`, all three expressions `m1`, `m2`, and `m3` appear in the same do " "notation block." msgstr "" "`c2`では`m1`、`m2`、`m3`の3つ全ての式が同じdo記法ブロックに現れています。" @@ -26086,26 +26274,26 @@ msgstr "モナドで畳み込む" #: text/chapter8.md:212 msgid "" "As an example of working with monads abstractly, this section will present a " -"function which works with any type constructor in the `Monad` type class. " -"This should serve to solidify the intuition that monadic code corresponds to " +"function that works with any type constructor in the `Monad` type class. " +"This should solidify the intuition that monadic code corresponds to " "programming \"in a larger language\" with side-effects, and also illustrate " "the generality which programming with monads brings." msgstr "" "抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で" "機能する関数を紹介していきます。\n" "これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと" -"対応しているという直感的理解を補強しますし、モナドによるプログラミングがもた" -"らす一般性も示しています。" +"対応しているという直感的理解を補強しますし、モナドによるプログラミングが齎す" +"一般性も示しています。" #. type: Plain text #: text/chapter8.md:214 msgid "" "The function we will write is called `foldM`. It generalizes the `foldl` " -"function that we met earlier to a monadic context. Here is its type " -"signature:" +"function we met earlier to a monadic context. Here is its type signature:" msgstr "" -"これから `foldM`と呼ばれる関数を書いてみます。これは以前扱った `foldl`関数を" -"モナドの文脈へと一般化します。型シグネチャは次のようになっています。" +"これから書いていく関数は`foldM`という名前です。\n" +"以前見た`foldl`関数をモナドの文脈へと一般化するものです。\n" +"型シグネチャは以下です。" #. type: Fenced code block (hs) #: text/chapter8.md:215 @@ -26132,36 +26320,35 @@ msgid "" "Intuitively, `foldM` performs a fold over a list in some context supporting " "some set of side-effects." msgstr "" -"直感的には、 `foldM`はさまざまな副作用の組み合わせに対応した文脈での配列の畳" -"み込みを行うと捉えることができます。" +"直感的には、`foldM`は様々な副作用の組み合わせに対応した文脈で配列を畳み込むも" +"のと捉えられます。" #. type: Plain text #: text/chapter8.md:225 msgid "" "For example, if we picked `m` to be `Maybe`, then our fold would be allowed " -"to fail by returning `Nothing` at any stage - every step returns an optional " +"to fail by returning `Nothing` at any stage – every step returns an optional " "result, and the result of the fold is therefore also optional." msgstr "" -"例として `m`が `Maybe`であるとすると、この畳み込みはそれぞれの段階で " -"`Nothing`を返すことで失敗させられます。\n" -"それぞれの段階ではオプショナルな結果を返しますから、それゆえ畳み込みの結果も" -"オプショナルになります。" +"例として`m`として`Maybe`を選ぶとすると、各段階で`Nothing`を返すことでこの畳み" +"込みを失敗させられます。\n" +"各段階では省略可能な結果を返しますから、それ故畳み込みの結果も省略可能になり" +"ます。" #. type: Plain text #: text/chapter8.md:227 msgid "" "If we picked `m` to be the `Array` type constructor, then every step of the " "fold would be allowed to return zero or more results, and the fold would " -"proceed to the next step independently for each result. At the end, the set " +"proceed to the next step independently for each result. In the end, the set " "of results would consist of all folds over all possible paths. This " "corresponds to a traversal of a graph!" msgstr "" -"もし `m`として配列の型構築子 `Array`を選ぶとすると、畳み込みのそれぞれの段階" -"で複数の結果を返すことができ、畳み込みは結果それぞれに対して次の手順を継続し" -"ます。\n" -"最後に、結果の集まりは、可能な経路全ての畳み込みから構成されることになりま" +"もし`m`として型構築子`Array`を選ぶとすると、畳み込みの各段階で0以上の結果を返" +"せるため、畳み込みは各結果に対して独立に次の手順を継続します。\n" +"最後に、結果の集まりは可能な経路の全ての畳み込みから構成されることになりま" "す。\n" -"これはグラフの走査と対応しています。" +"これはグラフの走査と対応していますね。" #. type: Plain text #: text/chapter8.md:229 @@ -26187,7 +26374,7 @@ msgstr "foldM _ a Nil = pure a\n" #: text/chapter8.md:237 msgid "Note that we have to use `pure` to lift `a` into the monad `m`." msgstr "" -"なお`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。" +"なお、`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。" #. type: Plain text #: text/chapter8.md:239 @@ -26222,21 +26409,22 @@ msgstr "" #: text/chapter8.md:249 msgid "" "Note that this implementation is almost identical to that of `foldl` on " -"lists, with the exception of do notation." +"lists, except for do notation." msgstr "" -"なお、do記法を除けば、この実装は配列に対する `foldl`の実装とほとんど同じで" -"す。" +"なお、この実装はリストに対する`foldl`の実装とほとんど同じです。\n" +"ただしdo記法である点を除きます。" #. type: Plain text #: text/chapter8.md:251 msgid "" -"We can define and test this function in PSCi. Here is an example - suppose " +"We can define and test this function in PSCi. Here is an example – suppose " "we defined a \"safe division\" function on integers, which tested for " "division by zero and used the `Maybe` type constructor to indicate failure:" msgstr "" -"PSCiでこれを定義し、試してみましょう。\n" -"以下では例として、除算可能かどうかを調べて、失敗を示すために `Maybe`型構築子" -"を使う、整数の「安全な除算」関数を定義するとしましょう。" +"PSCiでこの関数を定義して試せます。\n" +"以下は一例です。\n" +"整数の「安全な除算」関数を定義するとします。\n" +"0による除算かを確認し、失敗を示すために `Maybe`型構築子を使うのです。" #. type: Fenced code block (hs) #: text/chapter8.md:252 @@ -26275,12 +26463,12 @@ msgstr "" #: text/chapter8.md:270 msgid "" "The `foldM safeDivide` function returns `Nothing` if a division by zero was " -"attempted at any point. Otherwise it returns the result of repeatedly " +"attempted at any point. Otherwise, it returns the result of repeatedly " "dividing the accumulator, wrapped in the `Just` constructor." msgstr "" -"もし何れかの時点で整数にならない除算が行われようとしたら、`foldM safeDivide`" -"関数は `Nothing`を返します。\n" -"そうでなければ、除算を繰り返した累積の結果を`Just`構築子に包んで返します。" +"もし何れかの時点で0による除算が試みられたら、`foldM safeDivide`関数は" +"`Nothing`を返します。\n" +"そうでなければ、累算値を繰り返し除算した結果を`Just`構築子に包んで返します。" #. type: Title ## #: text/chapter8.md:271 @@ -26335,10 +26523,11 @@ msgstr "" #: text/chapter8.md:288 msgid "" "The interested reader can check that `ap` agrees with `apply` for the monads " -"we have already encountered: `Array`, `Maybe` and `Either e`." +"we have already encountered: `Array`, `Maybe`, and `Either e`." msgstr "" -"興味のある読者は、これまで登場した `Array`、 `Maybe`、 `Either e`といったモナ" -"ドについて、この `ap`が `apply`と一致することを確かめてみてください。" +"興味のある読者はこれまで登場したモナドについてこの`ap`が`apply`として充足する" +"ことを確かめてみてください。\n" +"モナドは`Array`、`Maybe`、`Either e`といったものです。" #. type: Plain text #: text/chapter8.md:290 @@ -26363,12 +26552,12 @@ msgid "" "But monads allow us to do more than we could do with just applicative " "functors, and the key difference is highlighted by the syntax of do " "notation. Consider the `userCity` example again, in which we looked for a " -"user's city in an XML document which encoded their user profile:" +"user's city in an XML document that encoded their user profile:" msgstr "" -"しかし、モナドはアプリカティブ関手でできること以上を行うことができ、重要な違" -"いはdo記法の構文で強調されています。\n" -"利用者情報をエンコードしたXML文書から利用者の都市を検索する、`userCity`の例に" -"ついてもう一度考えてみましょう。" +"しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法" +"の構文で強調されています。\n" +"`userCity`の例についてもう一度考えてみましょう。\n" +"利用者情報をエンコードしたXML文書から利用者の市町村を検索するものでした。" #. type: Plain text #: text/chapter8.md:303 @@ -26404,19 +26593,19 @@ msgid "" "express parallelism. This was precisely because the function arguments being " "lifted were independent of one another. Since the `Monad` type class allows " "computations to depend on the results of previous computations, the same " -"does not apply - a monad has to combine its side-effects in sequence." +"does not apply – a monad has to combine its side-effects in sequence." msgstr "" -"前の章では `Applicative`型クラスは並列処理を表現できることを見ました。\n" +"前の章では`Applicative`型クラスは並列処理を表現できることを見ました。\n" "持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りで" "す。\n" -"`Monad`型クラスは計算が前の計算の結果に依存できるようにしますから、同じように" +"`Monad`型クラスは計算が前の計算の結果に依存できるようになっており、同じように" "はなりません。\n" -"モナドは副作用を順番に組み合わせなければいけません。" +"つまりモナドは副作用を順番に組み合わせなければならないのです。" #. type: Bullet: ' 1. ' #: text/chapter8.md:312 msgid "" -"(Easy) Write a function `third` which returns the third element of an array " +"(Easy) Write a function `third` that returns the third element of an array " "with three or more elements. Your function should return an appropriate " "`Maybe` type. _Hint:_ Look up the types of the `head` and `tail` functions " "from the `Data.Array` module in the `arrays` package. Use do notation with " @@ -26427,7 +26616,7 @@ msgstr "" "関数は適切な`Maybe`型で返します。\n" "*手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数" "の型を見つけ出してください。\n" -"これらの関数を繋げるには`Maybe`モナドと共にdo記法を使ってください。" +"これらの関数を組み合わせるには`Maybe`モナドと共にdo記法を使ってください。" #. type: Bullet: ' 1. ' #: text/chapter8.md:312 @@ -26470,18 +26659,19 @@ msgstr "" #: text/chapter8.md:325 #, no-wrap msgid "" -" _Hint_: This function can be written as a one-liner using `foldM`. You might want to use the `nub` and `sort` functions to remove duplicates and sort the result respectively.\n" +" _Hint_: This function can be written as a one-liner using `foldM`. You might want to use the `nub` and `sort` functions to remove duplicates and sort the result.\n" " 1. (Medium) Confirm that the `ap` function and the `apply` operator agree for the `Maybe` monad. _Note:_ There are no tests for this exercise.\n" " 1. (Medium) Verify that the monad laws hold for the `Monad` instance for the `Maybe` type, as defined in the `maybe` package. _Note:_ There are no tests for this exercise.\n" " 1. (Medium) Write a function `filterM` which generalizes the `filter` function on lists. Your function should have the following type signature:\n" msgstr "" -" *手掛かり*:`foldM`を使うと1行でこの関数を書くことが可能です。\n" -" 重複を取り除いたり、結果を並び替えたりするのに、`nub`関数や `sort`関数を使いたくなるかもしれません。\n" -"1. (普通)`Maybe`型構築子について、 `ap`関数と `apply`演算子が一致することを確認してください。\n" +" *手掛かり*:`foldM`を使うと1行でこの関数を書けます。\n" +" 重複を取り除いたり、結果を並び替えたりするのに、`nub`関数や`sort`関数を使うことでしょう。\n" +"1. (普通)`ap`関数と`apply`演算子が`Maybe`モナドを充足することを確かめてください。\n" " *補足*:この演習にはテストがありません。\n" -"1. (普通)`maybe`パッケージで定義されている`Maybe`型についての `Monad`インスタンスが、モナド則を満たしていることを検証してください。\n" +"1. (普通)`Maybe`型についての`Monad`インスタンスが、モナド則を満たしていることを検証してください。\n" +" このインスタンスは`maybe`パッケージで定義されています。\n" " *補足*:この演習にはテストがありません。\n" -"1. (普通)配列上の `filter`の関数を一般化した関数`filterM`を書いてください。\n" +"1. (普通)リスト上の`filter`の関数を一般化した関数`filterM`を書いてください。\n" " この関数は次の型シグネチャを持ちます。\n" #. type: Plain text @@ -26540,9 +26730,9 @@ msgstr "" #. type: Plain text #: text/chapter8.md:345 #, no-wrap -msgid " where the `Apply` instance uses the `ap` function defined above. Recall that `lift2` was defined as follows:\n" +msgid " Where the `Apply` instance uses the `ap` function defined above. Recall that `lift2` was defined as follows:\n" msgstr "" -" ここで、 `Applly`インスタンスは上で定義された `ap`関数を使用しています。\n" +" ここで、`Applly`インスタンスは上で定義された`ap`関数を使用しています。\n" " `lift2`が次のように定義されていたことを思い出してください。\n" #. type: Plain text @@ -26574,11 +26764,11 @@ msgstr "ネイティブな作用" #. type: Plain text #: text/chapter8.md:356 msgid "" -"We will now look at one particular monad which is of central importance in " -"PureScript - the `Effect` monad." +"We will now look at one particular monad of central importance in PureScript " +"– the `Effect` monad." msgstr "" -"ここではPureScriptの中核となる重要なモナド、 `Effect`モナドについて見ていきま" -"す。" +"ここではPureScriptで中心的な重要性のあるモナドの1つ、`Effect`モナドについて見" +"ていきます。" #. type: Plain text #: text/chapter8.md:358 @@ -26594,12 +26784,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:360 msgid "" -"What are native side-effects? They are the side-effects which distinguish " +"What are native side-effects? They are the side-effects that distinguish " "JavaScript expressions from idiomatic PureScript expressions, which " "typically are free from side-effects. Some examples of native effects are:" msgstr "" "ネイティブな副作用とは何でしょうか。\n" -"この副作用はPureScript特有の式からJavaScriptの式を区別するものです。\n" +"この副作用はPureScript特有の式とJavaScriptの式とを2分するものです。\n" "PureScriptの式は概して副作用とは無縁なのです。\n" "ネイティブな作用の例を以下に示します。" @@ -26667,21 +26857,21 @@ msgstr "配列やリストで表現される多値関数" #: text/chapter8.md:380 msgid "" "Note that the distinction is subtle. It is true, for example, that an error " -"message is a possible side-effect of a JavaScript expression, in the form of " +"message is a possible side-effect of a JavaScript expression in the form of " "an exception. In that sense, exceptions do represent native side-effects, " "and it is possible to represent them using `Effect`. However, error messages " "implemented using `Either` are not a side-effect of the JavaScript runtime, " "and so it is not appropriate to implement error messages in that style using " -"`Effect`. So it is not the effect itself which is native, but rather how it " +"`Effect`. So it is not the effect itself, which is native, but rather how it " "is implemented at runtime." msgstr "" "これらの区別はわかりにくいので注意してください。\n" -"エラーメッセージは例外の形でJavaScriptの式の副作用となることがあります。\n" -"その意味では例外はネイティブな副作用を表していて、 `Effect`を使用して表現でき" +"例えば、エラー文言は例外の形でJavaScriptの式の副作用となることがあると言えま" +"す。\n" +"その意味では例外はネイティブな副作用を表していて、`Effect`を使用して表現でき" "ます。\n" -"しかし、 `Either`を使用して実装されたエラーメッセージはJavaScriptランタイムの" -"副作用ではなく、 `Effect`を使うスタイルでエラーメッセージを実装するのは適切で" -"はありません。\n" +"しかし、`Either`を使用して実装されたエラー文言はJavaScript実行時の副作用では" +"なく、`Effect`を使うスタイルでエラー文言を実装するのは不適切です。\n" "そのため、ネイティブなのは作用自体というより、実行時にどのように実装されてい" "るかです。" @@ -26694,55 +26884,56 @@ msgstr "副作用と純粋性" #. type: Plain text #: text/chapter8.md:384 msgid "" -"In a pure language like PureScript, one question which presents itself is: " -"without side-effects, how can one write useful real-world code?" +"In a pure language like PureScript, one question presents itself: without " +"side-effects, how can one write useful real-world code?" msgstr "" -"PureScriptのような言語が純粋であるとすると、疑問が浮かんできます。副作用がな" -"いなら、どうやって役に立つ実際のコードを書くことができるというのでしょうか。" +"PureScriptのような純粋な言語では、ある疑問が浮かんできます。\n" +"副作用がないなら、どうやって役に立つ実際のコードを書くことができるのでしょう" +"か。" #. type: Plain text #: text/chapter8.md:386 msgid "" -"The answer is that PureScript does not aim to eliminate side-effects. It " -"aims to represent side-effects in such a way that pure computations can be " -"distinguished from computations with side-effects in the type system. In " -"this sense, the language is still pure." +"The answer is that PureScript does not aim to eliminate side-effects but to " +"represent them in such a way that pure computations can be distinguished " +"from computations with side-effects in the type system. In this sense, the " +"language is still pure." msgstr "" -"その答えはPureScriptの目的は副作用を排除することではないということです。これ" -"は、純粋な計算と副作用のある計算とを型システムにおいて区別できるような方法" -"で、副作用を表現することを目的としているのです。この意味で、言語はあくまで純" -"粋だということです。" +"その答えはPureScriptの目的は副作用を排除することではないということです。\n" +"純粋な計算と副作用のある計算とを、型システムにおいて区別できるような方法で表" +"現します。\n" +"この意味で、言語はあくまで純粋なのです。" #. type: Plain text #: text/chapter8.md:388 msgid "" "Values with side-effects have different types from pure values. As such, it " -"is not possible to pass a side-effecting argument to a function, for " -"example, and have side-effects performed unexpectedly." +"is impossible to pass a side-effecting argument to a function, for example, " +"and have side-effects performed unexpectedly." msgstr "" -"副作用のある値は、純粋な値とは異なる型を持っています。そういうわけで、例えば" -"副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起" -"こらなくなります。" +"副作用のある値は、純粋な値とは異なる型を持っています。\n" +"そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作" +"用を持つようなことが起こらなくなります。" #. type: Plain text #: text/chapter8.md:390 msgid "" -"The only way in which side-effects managed by the `Effect` monad will be " -"presented is to run a computation of type `Effect a` from JavaScript." +"The only way side-effects managed by the `Effect` monad will be presented is " +"to run a computation of type `Effect a` from JavaScript." msgstr "" -"`Effect`モナドで管理された副作用を実行する唯一の方法は、型 `Effect a`の計算を" -"JavaScriptから実行することです。" +"`Effect`モナドで管理された副作用を現す手段は、型`Effect a`の計算をJavaScript" +"から実行することです。" #. type: Plain text #: text/chapter8.md:392 msgid "" -"The Spago build tool (and other tools) provide a shortcut, by generating " +"The Spago build tool (and other tools) provide a shortcut by generating " "additional JavaScript to invoke the `main` computation when the application " "starts. `main` is required to be a computation in the `Effect` monad." msgstr "" "Spagoビルドツール(や他のツール)は早道を用意しており、アプリケーションの起動" "時に`main`計算を呼び出すための追加のJavaScriptコードを生成します。\n" -"`main`は `Effect`モナドでの計算であることが要求されます。" +"`main`は`Effect`モナドでの計算であることが要求されます。" #. type: Plain text #: text/chapter8.md:396 @@ -26754,29 +26945,34 @@ msgstr "" "JavaScriptを生成します。" #. type: Plain text -#: text/chapter8.md:399 +#: text/chapter8.md:398 msgid "" -"Let's take a closer look at the return type of the familiar `log` function. " -"`Effect` indicates that this function produces a native effect, console IO " -"in this case. `Unit` indicates that no _meaningful_ data is returned. You " -"can think of `Unit` as being analogous to the `void` keyword in other " -"languages, such as C, Java, etc." +"Let's look at the return type of the familiar `log` function. `Effect` " +"indicates that this function produces a native effect, console IO in this " +"case." msgstr "" -"馴染みのある`log`関数から返る型をもう少し見てみましょう。\n" +"馴染みのある`log`関数から返る型を見てみましょう。\n" "`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコ" -"ンソールIOです。\n" +"ンソールIOです。" + +#. type: Plain text +#: text/chapter8.md:400 +msgid "" +"`Unit` indicates that no _meaningful_ data is returned. You can think of " +"`Unit` as analogous to the `void` keyword in other languages, such as C, " +"Java, etc." +msgstr "" "`Unit`はいかなる*意味のある*データも返らないことを示しています。\n" -"`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられ" -"ます。" +"`Unit`はC、Javaなど他の言語での`void`キーワードと似たものとして考えられます。" #. type: Fenced code block (hs) -#: text/chapter8.md:400 +#: text/chapter8.md:401 #, no-wrap msgid "log :: String -> Effect Unit\n" msgstr "log :: String -> Effect Unit\n" #. type: Plain text -#: text/chapter8.md:409 +#: text/chapter8.md:410 #, no-wrap msgid "" "> _Aside:_ You may encounter IDE suggestions for the more general (and more elaborately typed) `log` function from `Effect.Class.Console`. This is interchangeable with the one from `Effect.Console` when dealing with the basic `Effect` monad. Reasons for the more general version will become clearer after reading about \"Monad Transformers\" in the \"Monadic Adventures\" chapter. For the curious (and impatient), this works because there's a `MonadEffect` instance for `Effect`.\n" @@ -26795,7 +26991,7 @@ msgstr "" "> ```\n" #. type: Plain text -#: text/chapter8.md:411 +#: text/chapter8.md:412 msgid "" "Now let's consider an `Effect` that returns meaningful data. The `random` " "function from `Effect.Random` produces a random `Number`." @@ -26804,13 +27000,13 @@ msgstr "" "`Effect.Random`の`random`関数は乱択された`Number`を生み出します。" #. type: Fenced code block (hs) -#: text/chapter8.md:412 +#: text/chapter8.md:413 #, no-wrap msgid "random :: Effect Number\n" msgstr "random :: Effect Number\n" #. type: Plain text -#: text/chapter8.md:417 +#: text/chapter8.md:418 msgid "" "Here's a full example program (found in `test/Random.purs` of this chapter's " "exercises folder)." @@ -26819,13 +27015,13 @@ msgstr "" "ります)。" #. type: Fenced code block (hs) -#: text/chapter8.md:418 +#: text/chapter8.md:419 #, no-wrap msgid "{{#include ../exercises/chapter8/test/Random.purs}}\n" msgstr "{{#include ../exercises/chapter8/test/Random.purs}}\n" #. type: Plain text -#: text/chapter8.md:423 +#: text/chapter8.md:424 msgid "" "Because `Effect` is a monad, we use do notation to _unwrap_ the data it " "contains before passing this data on to the effectful `logShow` function. As " @@ -26836,7 +27032,7 @@ msgstr "" "気分転換に、以下は`bind`演算子を使って書かれた同等なコードです。" #. type: Fenced code block (hs) -#: text/chapter8.md:424 +#: text/chapter8.md:425 #, no-wrap msgid "" "main :: Effect Unit\n" @@ -26846,18 +27042,18 @@ msgstr "" "main = random >>= logShow\n" #. type: Plain text -#: text/chapter8.md:430 +#: text/chapter8.md:431 msgid "Try running this yourself with:" msgstr "これを手元で走らせてみてください。" #. type: Fenced code block (shell) -#: text/chapter8.md:431 +#: text/chapter8.md:432 #, no-wrap msgid "spago run --main Test.Random\n" msgstr "spago run --main Test.Random\n" #. type: Plain text -#: text/chapter8.md:436 +#: text/chapter8.md:437 msgid "" "You should see a randomly chosen number between `0.0` and `1.0` printed to " "the console." @@ -26865,16 +27061,16 @@ msgstr "" "コンソールに出力 `0.0`と `1.0`の間で無作為に選ばれた数が表示されるでしょう。" #. type: Plain text -#: text/chapter8.md:438 +#: text/chapter8.md:439 #, no-wrap -msgid "> _Aside:_ `spago run` defaults to searching in the `Main` module for a `main` function. You may also specify an alternate module as an entry point with the `--main` flag, as is done in the above example. Just be sure that this alternate module also contains a `main` function.\n" +msgid "> _Aside:_ `spago run` defaults to searching in the `Main` module for a `main` function. You may also specify an alternate module as an entry point with the `--main` flag, as in the above example. Just be sure that this alternate module also contains a `main` function.\n" msgstr "" -"> 余談:`spago run`は既定で`Main`モジュールとその中の`main`関数を探索します。\n" -"`--main`フラグで代替のモジュールを入口として指定でき、上の例ではそうしています。\n" -"この代替のモジュールもまた`main`関数を含んでいることに注目してください。\n" +"> 余談:`spago run`は既定で`main`関数を`Main`モジュールの中から探索します。\n" +"> `--main`フラグで代替のモジュールを入口として指定することも可能で、上の例ではそうしています。\n" +"> この代替のモジュールにも`main`関数が含まれているようにはしてください。\n" #. type: Plain text -#: text/chapter8.md:440 +#: text/chapter8.md:441 msgid "" "Note that it's also possible to generate \"random\" (technically " "pseudorandom) data without resorting to impure effectful code. We'll cover " @@ -26885,51 +27081,52 @@ msgstr "" "この技法は「テストを生成する」章で押さえます。" #. type: Plain text -#: text/chapter8.md:442 +#: text/chapter8.md:443 msgid "" "As mentioned previously, the `Effect` monad is of central importance to " -"PureScript. The reason why it's central is because it is the conventional " -"way to interoperate with PureScript's `Foreign Function Interface`, which " +"PureScript. The reason why it's central is that it is the conventional way " +"to interoperate with PureScript's `Foreign Function Interface`, which " "provides the mechanism to execute a program and perform side effects. While " -"it's desireable to avoid using the `Foreign Function Interface`, it's fairly " +"it's desirable to avoid using the `Foreign Function Interface`, it's fairly " "critical to understand how it works and how to use it, so I recommend " "reading that chapter before doing any serious PureScript work. That said, " -"the `Effect` monad is fairly simple. It has a few helper functions, but " -"aside from that it doesn't do much except encapsulate side effects." +"the `Effect` monad is fairly simple. It has a few helper functions but " +"doesn't do much except encapsulate side effects." msgstr "" "以前言及したように`Effect`モナドはPureScriptで核心的な重要さがあります。\n" -"なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやりとりす" +"なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りす" "る上での常套手段だからです。\n" "`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕" "組みを提供します。\n" "`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように" "動作しどう使うのか理解することもまた極めて大事なことですので、実際に" "PureScriptで何か動かす前にその章を読まれることをお勧めします。\n" -"要は`Effect`モナドは結構単純なのです。幾つかの補助関数がありますが、それを差" -"し置いても副作用を内包すること以外には大したことはしません。" +"要は`Effect`モナドは結構単純なのです。\n" +"幾つかの補助関数がありますが、副作用を内包すること以外には大したことはしませ" +"ん。" #. type: Plain text -#: text/chapter8.md:446 +#: text/chapter8.md:447 msgid "" "Let's examine a function from the `node-fs` package that involves two " -"_native_ side effects: reading mutable state, and exceptions:" +"_native_ side effects: reading mutable state and exceptions:" msgstr "" -"2つの _ネイティブな_ 副作用が絡む`node-fs`パッケージの関数を調べましょう。こ" -"こでの副作用は可変状態の読み取りと例外です。" +"2つの*ネイティブな*副作用が絡む`node-fs`パッケージの関数を調べましょう。\n" +"ここでの副作用は可変状態の読み取りと例外です。" #. type: Fenced code block (hs) -#: text/chapter8.md:447 +#: text/chapter8.md:448 #, no-wrap msgid "readTextFile :: Encoding -> String -> Effect String\n" msgstr "readTextFile :: Encoding -> String -> Effect String\n" #. type: Plain text -#: text/chapter8.md:452 +#: text/chapter8.md:453 msgid "If we attempt to read a file that does not exist:" msgstr "もし存在しないファイルを読もうとすると……" #. type: Fenced code block (hs) -#: text/chapter8.md:453 +#: text/chapter8.md:454 #, no-wrap msgid "" "import Node.Encoding (Encoding(..))\n" @@ -26949,12 +27146,12 @@ msgstr "" " log lines\n" #. type: Plain text -#: text/chapter8.md:464 +#: text/chapter8.md:465 msgid "We encounter the following exception:" msgstr "以下の例外に遭遇します。" #. type: Fenced code block (text) -#: text/chapter8.md:465 +#: text/chapter8.md:466 #, no-wrap msgid "" " throw err;\n" @@ -26976,7 +27173,7 @@ msgstr "" " path: 'iDoNotExist.md'\n" #. type: Plain text -#: text/chapter8.md:477 +#: text/chapter8.md:478 msgid "" "To manage this exception gracefully, we can wrap the potentially problematic " "code in `try` to handle either outcome:" @@ -26985,7 +27182,7 @@ msgstr "" "な出力でも制御できます。" #. type: Fenced code block (hs) -#: text/chapter8.md:478 +#: text/chapter8.md:479 #, no-wrap msgid "" "main :: Effect Unit\n" @@ -27003,7 +27200,7 @@ msgstr "" " Left error -> log $ \"Couldn't open file. Error was: \" <> message error\n" #. type: Plain text -#: text/chapter8.md:488 +#: text/chapter8.md:489 msgid "" "`try` runs an `Effect` and returns eventual exceptions as a `Left` value. If " "the computation succeeds, the result gets wrapped in a `Right`:" @@ -27012,24 +27209,24 @@ msgstr "" "もし計算が成功すれば結果は`Right`に包まれます。" #. type: Fenced code block (hs) -#: text/chapter8.md:489 +#: text/chapter8.md:490 #, no-wrap msgid "try :: forall a. Effect a -> Effect (Either Error a)\n" msgstr "try :: forall a. Effect a -> Effect (Either Error a)\n" #. type: Plain text -#: text/chapter8.md:494 +#: text/chapter8.md:495 msgid "" "We can also generate our own exceptions. Here is an alternative " -"implementation of `Data.List.head` which throws an exception if the list is " -"empty, rather than returning a `Maybe` value of `Nothing`." +"implementation of `Data.List.head` that throws an exception if the list is " +"empty rather than returning a `Maybe` value of `Nothing`." msgstr "" "独自の例外も生成できます。\n" "以下は`Data.List.head`の代替実装で、`Maybe`の値の`Nothing`を返す代わりにリス" "トが空のとき例外を投げます。" #. type: Fenced code block (hs) -#: text/chapter8.md:495 +#: text/chapter8.md:496 #, no-wrap msgid "" "exceptionHead :: List Int -> Effect Int\n" @@ -27043,7 +27240,7 @@ msgstr "" " Nil -> throwException $ error \"empty list\"\n" #. type: Plain text -#: text/chapter8.md:503 +#: text/chapter8.md:504 msgid "" "Note that the `exceptionHead` function is a somewhat impractical example, as " "it is best to avoid generating exceptions in PureScript code and instead use " @@ -27056,19 +27253,19 @@ msgstr "" "す。" #. type: Title ## -#: text/chapter8.md:504 +#: text/chapter8.md:505 #, no-wrap msgid "Mutable State" msgstr "可変状態" #. type: Plain text -#: text/chapter8.md:507 +#: text/chapter8.md:508 msgid "There is another effect defined in the core libraries: the `ST` effect." msgstr "" "中核ライブラリには `ST`作用という、これまた別の作用も定義されています。" #. type: Plain text -#: text/chapter8.md:509 +#: text/chapter8.md:510 msgid "" "The `ST` effect is used to manipulate mutable state. As pure functional " "programmers, we know that shared mutable state can be problematic. However, " @@ -27082,16 +27279,16 @@ msgstr "" "の共有を制限するのです。" #. type: Plain text -#: text/chapter8.md:511 +#: text/chapter8.md:512 msgid "" "The `ST` effect is defined in the `Control.Monad.ST` module. To see how it " "works, we need to look at the types of its actions:" msgstr "" -"`ST`作用は `Control.Monad.ST`モジュールで定義されています。これがどのように動" -"作するかを確認するには、そのアクションの型を見る必要があります。" +"`ST`作用は `Control.Monad.ST`モジュールで定義されています。\n" +"この挙動を確認するには、その動作の型を見る必要があります。" #. type: Fenced code block (hs) -#: text/chapter8.md:512 +#: text/chapter8.md:513 #, no-wrap msgid "" "new :: forall a r. a -> ST r (STRef r a)\n" @@ -27111,32 +27308,33 @@ msgstr "" "modify :: forall r a. (a -> a) -> STRef r a -> ST r a\n" #. type: Plain text -#: text/chapter8.md:523 +#: text/chapter8.md:524 msgid "" "`new` is used to create a new mutable reference cell of type `STRef r a`, " -"which can be read using the `read` action, and modified using the `write` " -"and `modify` actions. The type `a` is the type of the value stored in the " -"cell, and the type `r` is used to indicate a _memory region_ (or _heap_) in " -"the type system." +"which can be read using the `read` action and modified using the `write` and " +"`modify` actions. The type `a` is the type of the value stored in the cell, " +"and the type `r` is used to indicate a _memory region_ (or _heap_) in the " +"type system." msgstr "" -"`new`は型`STRef r a`の変更可能な参照領域を新しく作るのに使われます。\n" -"`STRef r a`は `read`アクションを使って状態を読み取ったり、`write`アクション" -"や `modify`アクションで状態を変更するのに使われます。\n" -"型`a`は領域に格納された値の型で、型 `r`は型システムで*メモリ領域*(または*" -"ヒープ*)を表しています。" +"`new`は型`STRef r a`の可変参照領域を新規作成するのに使われます。\n" +"この領域は`read`動作を使って読み取ったり、`write`動作や`modify`動作で状態を変" +"更するのに使えます。\n" +"型`a`は領域に格納された値の型を、型`r`は*メモリ領域*(または*ヒープ*)を、そ" +"れぞれ型システムで表しています。" #. type: Plain text -#: text/chapter8.md:525 +#: text/chapter8.md:526 msgid "" "Here is an example. Suppose we want to simulate the movement of a particle " -"falling under gravity by iterating a simple update function over a large " -"number of small time steps." +"falling under gravity by iterating a simple update function over many small " +"time steps." msgstr "" -"例を示します。小さな時間刻みで簡単な更新関数の実行を何度も繰り返すことによっ" -"て、重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。" +"例を示します。\n" +"重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。\n" +"これには小さな時間刻みで簡単な更新関数の実行を何度も繰り返します。" #. type: Plain text -#: text/chapter8.md:527 +#: text/chapter8.md:528 msgid "" "We can do this by creating a mutable reference cell to hold the position and " "velocity of the particle, and then using a `for` loop to update the value " @@ -27146,7 +27344,7 @@ msgstr "" "新するのにforループを使うことでこれを実現できます。" #. type: Fenced code block (hs) -#: text/chapter8.md:528 +#: text/chapter8.md:529 #, no-wrap msgid "" "import Prelude\n" @@ -27188,39 +27386,39 @@ msgstr "" " pure final.x\n" #. type: Plain text -#: text/chapter8.md:550 +#: text/chapter8.md:551 msgid "" -"At the end of the computation, we read the final value of the reference " -"cell, and return the position of the particle." +"At the end of the computation, we read the final value of the reference cell " +"and return the position of the particle." msgstr "" "計算の最後では、参照領域の最終的な値を読み取り、粒子の位置を返しています。" #. type: Plain text -#: text/chapter8.md:552 +#: text/chapter8.md:553 msgid "" -"Note that even though this function uses mutable state, it is still a pure " +"Note that even though this function uses a mutable state, it is still a pure " "function, so long as the reference cell `ref` is not allowed to be used by " -"other parts of the program. We will see that this is exactly what the `ST` " -"effect disallows." +"other program parts. We will see that this is exactly what the `ST` effect " +"disallows." msgstr "" "なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの" -"他の部分で使われるのが許されない限り、これは純粋な関数のままです。\n" -"`ST`作用が禁止するものが正確には何であるのかについては後ほど見ます。" +"他の部分での使用が許されない限り、これは純粋な関数のままです。\n" +"このことが正に`ST`作用が禁止するものであることを見ていきます。" #. type: Plain text -#: text/chapter8.md:554 +#: text/chapter8.md:555 msgid "" "To run a computation with the `ST` effect, we have to use the `run` function:" msgstr "`ST`作用付きで計算するには、`run`関数を使用する必要があります。" #. type: Fenced code block (hs) -#: text/chapter8.md:555 +#: text/chapter8.md:556 #, no-wrap msgid "run :: forall a. (forall r. ST r a) -> a\n" msgstr "run :: forall a. (forall r. ST r a) -> a\n" #. type: Plain text -#: text/chapter8.md:560 +#: text/chapter8.md:561 msgid "" "The thing to notice here is that the region type `r` is quantified _inside " "the parentheses_ on the left of the function arrow. That means that whatever " @@ -27228,25 +27426,25 @@ msgid "" msgstr "" "ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化" "されているということです。\n" -"`run`に渡したどんなアクションでも、*任意の領域*`r`が何であれ動作するというこ" -"とを意味しています。" +"`run`に渡したどんな動作でも、*任意の領域*`r`が何であれ動作するということを意" +"味しています。" #. type: Plain text -#: text/chapter8.md:562 +#: text/chapter8.md:563 msgid "" "However, once a reference cell has been created by `new`, its region type is " "already fixed, so it would be a type error to try to use the reference cell " -"outside the code delimited by `run`. This is what allows `run` to safely " -"remove the `ST` effect, and turn `simulate` into a pure function!" +"outside the code delimited by `run`. This allows `run` to safely remove the " +"`ST` effect and turn `simulate` into a pure function!" msgstr "" -"しかし、ひとたび参照領域が `new`によって作成されると、その領域の型は既に固定" -"されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エ" +"しかし、ひとたび参照領域が`new`によって作成されると、その領域の型は既に固定さ" +"れており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エ" "ラーになるでしょう。\n" -"`run`が安全に `ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由" -"なのです。" +"`run`が安全に`ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由な" +"のです。" #. type: Fenced code block (hs) -#: text/chapter8.md:563 +#: text/chapter8.md:564 #, no-wrap msgid "" "simulate' :: Number -> Number -> Int -> Number\n" @@ -27256,12 +27454,12 @@ msgstr "" "simulate' x0 v0 time = run (simulate x0 v0 time)\n" #. type: Plain text -#: text/chapter8.md:569 +#: text/chapter8.md:570 msgid "You can even try running this function in PSCi:" msgstr "PSCiでもこの関数を実行してみることができます。" #. type: Fenced code block (text) -#: text/chapter8.md:570 +#: text/chapter8.md:571 #, no-wrap msgid "" "> import Main\n" @@ -27299,7 +27497,7 @@ msgstr "" "21.54\n" #. type: Plain text -#: text/chapter8.md:590 +#: text/chapter8.md:591 msgid "" "In fact, if we inline the definition of `simulate` at the call to `run`, as " "follows:" @@ -27308,7 +27506,7 @@ msgstr "" "ようになります。" #. type: Fenced code block (hs) -#: text/chapter8.md:591 +#: text/chapter8.md:592 #, no-wrap msgid "" "simulate :: Number -> Number -> Int -> Number\n" @@ -27342,19 +27540,19 @@ msgstr "" " pure final.x\n" #. type: Plain text -#: text/chapter8.md:609 +#: text/chapter8.md:610 msgid "" -"then the compiler will notice that the reference cell is not allowed to " -"escape its scope, and can safely turn `ref` into a `var`. Here is the " -"generated JavaScript for `simulate` inlined with `run`:" +"Then the compiler will notice that the reference cell cannot escape its " +"scope and can safely turn `ref` into a `var`. Here is the generated " +"JavaScript for `simulate` inlined with `run`:" msgstr "" -"参照領域はそのスコープから逃れることができないことがコンパイラにわかります" -"し、安全に`ref`を`var`に変換できます。\n" +"そうして、参照領域はそのスコープから逃れられないことと、安全に`ref`を`var`に" +"変換できることにコンパイラが気付きます。\n" "`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになりま" "す。" #. type: Fenced code block (javascript) -#: text/chapter8.md:610 +#: text/chapter8.md:611 #, no-wrap msgid "" "var simulate = function (x0) {\n" @@ -27404,26 +27602,22 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter8.md:636 -msgid "" -"Note that this resulting JavaScript is not as optimal as it could be. See " -"[this issue](https://github.com/purescript-contrib/purescript-book/" -"issues/121) for more details. The above snippet should be updated once that " -"issue is resolved." +#: text/chapter8.md:637 +#, no-wrap +msgid "> Note that this resulting JavaScript is not as optimal as it could be. See [this issue](https://github.com/purescript-contrib/purescript-book/issues/121) for more details. The above snippet should be updated once that issue is resolved.\n" msgstr "" -"なおこの結果として得られたJavaScriptは最適化の余地があります。\n" -"詳細は[この課題](https://github.com/purescript-contrib/purescript-book/" -"issues/121)を参照してください。\n" -"上記の抜粋はその課題が解決されたら更新されるでしょう。" +"> なお、この結果として得られたJavaScriptは最適化の余地があります。\n" +"> 詳細は[こちらの課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。\n" +"> 上記の抜粋はそちらの課題が解決されたら更新されるでしょう。\n" #. type: Plain text -#: text/chapter8.md:638 +#: text/chapter8.md:639 msgid "" "For comparison, this is the generated JavaScript of the non-inlined form:" msgstr "比較としてこちらが埋め込まれていない形式で生成されたJavaScriptです。" #. type: Fenced code block (js) -#: text/chapter8.md:639 +#: text/chapter8.md:640 #, no-wrap msgid "" "var simulate = function (x0) {\n" @@ -27473,18 +27667,19 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter8.md:665 +#: text/chapter8.md:666 msgid "" "The `ST` effect is a good way to generate short JavaScript when working with " "locally-scoped mutable state, especially when used together with actions " -"like `for`, `foreach`, and `while` which generate efficient loops." +"like `for`, `foreach`, and `while`, which generate efficient loops." msgstr "" -"局所的な変更可能状態を扱うとき、特に作用が絡むループを生成する`for`、 " -"`foreach`、 `while`のようなアクションを一緒に使うときには、`ST`作用は短い" -"JavaScriptを生成する良い方法となります。" +"局所的な変更可能状態を扱うとき、`ST`作用は短いJavaScriptを生成する良い方法と" +"なります。\n" +"作用を持つ繰り返しを生成する`for`、`foreach`、`while`のような動作を一緒に使う" +"ときは特にそうです。" #. type: Bullet: '1. ' -#: text/chapter8.md:671 +#: text/chapter8.md:672 msgid "" "(Medium) Rewrite the `safeDivide` function as `exceptionDivide` and throw an " "exception using `throwException` with the message `\"div zero\"` if the " @@ -27495,7 +27690,7 @@ msgstr "" "さい。" #. type: Bullet: '1. ' -#: text/chapter8.md:671 +#: text/chapter8.md:672 msgid "" "(Medium) Write a function `estimatePi :: Int -> Number` that uses `n` terms " "of the [Gregory Series](https://mathworld.wolfram.com/GregorySeries.html) to " @@ -27511,7 +27706,7 @@ msgstr "" "る必要があるかもしれません。" #. type: Bullet: '1. ' -#: text/chapter8.md:671 +#: text/chapter8.md:672 msgid "" "(Medium) Write a function `fibonacci :: Int -> Int` to compute the `n`th " "Fibonacci number, using `ST` to track the values of the previous two " @@ -27523,13 +27718,13 @@ msgstr "" "基づく実装の実行速度を第4章の再帰実装に対して比較してください。" #. type: Title ## -#: text/chapter8.md:672 +#: text/chapter8.md:673 #, no-wrap msgid "DOM Effects" msgstr "DOM作用" #. type: Plain text -#: text/chapter8.md:675 +#: text/chapter8.md:676 msgid "" "In the final sections of this chapter, we will apply what we have learned " "about effects in the `Effect` monad to the problem of working with the DOM." @@ -27538,37 +27733,37 @@ msgstr "" "際のDOM操作の問題に応用します。" #. type: Plain text -#: text/chapter8.md:677 +#: text/chapter8.md:678 msgid "" -"There are a number of PureScript packages for working directly with the DOM, " -"or with open-source DOM libraries. For example:" +"There are several PureScript packages for working directly with the DOM or " +"open-source DOM libraries. For example:" msgstr "" "DOMを直接扱ったり、オープンソースのDOMライブラリを扱ったりするPureScriptパッ" "ケージが沢山あります。\n" "例えば以下です。" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 msgid "" "[`web-dom`](https://github.com/purescript-web/purescript-web-dom) provides " -"type definitions and low level interface implementations for the W3C DOM " +"type definitions and low-level interface implementations for the W3C DOM " "spec." msgstr "" -"[`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3C\n" -"のDOM規格に向けた型定義と低水準インターフェース実装を提供します。" +"[`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3CのDOM規" +"格に向けた型定義と低水準インターフェース実装を提供します。" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 msgid "" "[`web-html`](https://github.com/purescript-web/purescript-web-html) provides " -"type definitions and low level interface implementations for the W3C HTML5 " +"type definitions and low-level interface implementations for the W3C HTML5 " "spec." msgstr "" "[`web-html`](https://github.com/purescript-web/purescript-web-html)はW3Cの" "HTML5規格に向けた型定義と低水準インターフェース実装を提供します。" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 msgid "" "[`jquery`](https://github.com/paf31/purescript-jquery) is a set of bindings " "to the [jQuery](http://jquery.org) library." @@ -27577,18 +27772,18 @@ msgstr "" "jquery.org)ライブラリのバインディングの集まりです。" #. type: Plain text -#: text/chapter8.md:683 +#: text/chapter8.md:684 msgid "" -"There are also PureScript libraries which build abstractions on top of these " +"There are also PureScript libraries that build abstractions on top of these " "libraries, such as" msgstr "" -"上記のライブラリを抽象化するPureScriptライブラリもあります。\n" +"上記のライブラリを土台に抽象化を進めたPureScriptライブラリもあります。\n" "以下のようなものです。" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 msgid "" -"[`thermite`](https://github.com/paf31/purescript-thermite), which builds on " +"[`thermite`](https://github.com/paf31/purescript-thermite) builds on " "[`react`](https://github.com/purescript-contrib/purescript-react)" msgstr "" "[`thermite`](https://github.com/paf31/purescript-thermite)は[`react`]" @@ -27596,20 +27791,20 @@ msgstr "" "ます。" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 msgid "" "[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-" -"hooks), which builds on [`react-basic`](https://github.com/lumihq/purescript-" -"react-basic)" +"hooks) builds on [`react-basic`](https://github.com/lumihq/purescript-react-" +"basic)" msgstr "" "[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-" "hooks)は[`react-basic`](https://github.com/lumihq/purescript-react-basic)を土" "台に構築されています。" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 msgid "" -"[`halogen`](https://github.com/purescript-halogen/purescript-halogen) which " +"[`halogen`](https://github.com/purescript-halogen/purescript-halogen) " "provides a type-safe set of abstractions on top of a custom virtual DOM " "library." msgstr "" @@ -27617,7 +27812,7 @@ msgstr "" "仮想DOMライブラリを土台とする型安全な一揃いの抽象化を提供します。" #. type: Plain text -#: text/chapter8.md:689 +#: text/chapter8.md:690 msgid "" "In this chapter, we will use the `react-basic-hooks` library to add a user " "interface to our address book application, but the interested reader is " @@ -27628,13 +27823,13 @@ msgstr "" "進めることをお勧めします。" #. type: Title ## -#: text/chapter8.md:690 +#: text/chapter8.md:691 #, no-wrap msgid "An Address Book User Interface" msgstr "住所録のユーザーインターフェース" #. type: Plain text -#: text/chapter8.md:693 +#: text/chapter8.md:694 msgid "" "Using the `react-basic-hooks` library, we will define our application as a " "React _component_. React components describe HTML elements in code as pure " @@ -27651,7 +27846,7 @@ msgstr "" "す。" #. type: Plain text -#: text/chapter8.md:695 +#: text/chapter8.md:696 msgid "" "A full tutorial for the React library is well beyond the scope of this " "chapter, but the reader is encouraged to consult its documentation where " @@ -27663,21 +27858,21 @@ msgstr "" "目的に応じて、Reactは `Effect`モナドの実用的な例を提供してくれます。" #. type: Plain text -#: text/chapter8.md:697 +#: text/chapter8.md:698 msgid "" -"We are going to build a form which will allow a user to add a new entry into " +"We are going to build a form that will allow a user to add a new entry into " "our address book. The form will contain text boxes for the various fields " -"(first name, last name, city, state, etc.), and an area in which validation " +"(first name, last name, city, state, etc.) and an area where validation " "errors will be displayed. As the user types text into the text boxes, the " "validation errors will be updated." msgstr "" "利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。\n" -"フォームには、さまざまなフィールド(姓、名前、都市、州など)のテキストボック" -"ス、及び検証エラーが表示される領域が含まれます。\n" -"テキストボックスに利用者がテキストを入力すると、検証エラーが更新されます。" +"フォームには、様々なフィールド(姓、名、市町村、州など)のテキストボックス、" +"及び検証エラーが表示される領域が含まれます。\n" +"テキストボックスに利用者がテキストを入力する度に、検証エラーが更新されます。" #. type: Plain text -#: text/chapter8.md:699 +#: text/chapter8.md:700 msgid "" "To keep things simple, the form will have a fixed shape: the different phone " "number types (home, cell, work, other) will be expanded into separate text " @@ -27687,16 +27882,16 @@ msgstr "" "電話、仕事、その他)ごとに別々のテキストボックスへ分けることにします。" #. type: Plain text -#: text/chapter8.md:701 +#: text/chapter8.md:702 msgid "" "You can launch the web app from the `exercises/chapter8` directory with the " "following commands:" msgstr "" -"`exercises/chapter8`ディレクトリから以下のコマンドでWebアプリを立ち上げること" +"`exercises/chapter8`ディレクトリから以下のコマンドでwebアプリを立ち上げること" "ができます。" #. type: Fenced code block (shell) -#: text/chapter8.md:702 +#: text/chapter8.md:703 #, no-wrap msgid "" "$ npm install\n" @@ -27708,7 +27903,7 @@ msgstr "" "$ npx parcel src/index.html --open\n" #. type: Plain text -#: text/chapter8.md:709 +#: text/chapter8.md:710 msgid "" "If development tools such as `spago` and `parcel` are installed globally, " "then the `npx` prefix may be omitted. You have likely already installed " @@ -27721,10 +27916,10 @@ msgstr "" "`parcel`についても同じことができるでしょう。" #. type: Plain text -#: text/chapter8.md:711 +#: text/chapter8.md:712 msgid "" "`parcel` should launch a browser window with our \"Address Book\" app. If " -"you keep the `parcel` terminal open, and rebuild with `spago` in another " +"you keep the `parcel` terminal open and rebuild with `spago` in another " "terminal, the page should automatically refresh with your latest edits. You " "can also configure automatic rebuilds (and therefore automatic page refresh) " "on file-save if you're using an [editor](https://github.com/purescript/" @@ -27743,44 +27938,44 @@ msgstr "" "る)ように設定できます。" #. type: Plain text -#: text/chapter8.md:713 +#: text/chapter8.md:714 msgid "" -"In this Address Book app, you should be able to enter some values into the " -"form fields and see the validation errors printed onto the page." +"In this Address Book app, you can enter some values into the form fields and " +"see the validation errors printed onto the page." msgstr "" "このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上" -"に出力された検証エラーを見ることができるでしょう。" +"で出力された検証エラーが見られます。" #. type: Plain text -#: text/chapter8.md:715 +#: text/chapter8.md:716 msgid "Let's explore how it works." msgstr "動作の仕組みを散策しましょう。" #. type: Plain text -#: text/chapter8.md:717 +#: text/chapter8.md:718 msgid "The `src/index.html` file is minimal:" msgstr "`src/index.html`ファイルは最小限です。" #. type: Fenced code block (html) -#: text/chapter8.md:718 +#: text/chapter8.md:719 #, no-wrap msgid "{{#include ../exercises/chapter8/src/index.html}}\n" msgstr "{{#include ../exercises/chapter8/src/index.html}}\n" #. type: Plain text -#: text/chapter8.md:723 +#: text/chapter8.md:724 #, no-wrap msgid "The `>= document >>= toNonElementParentNode >>> getElementById \"container\"\n" #. type: Plain text -#: text/chapter8.md:760 +#: text/chapter8.md:761 msgid "" "It is a matter of personal preference whether the intermediate `w` and `doc` " "variables aid in readability." @@ -27864,17 +28059,17 @@ msgstr "" "途中の`w`や`doc`変数が読みやすさの助けになるかは主観的な好みの問題です。" #. type: Plain text -#: text/chapter8.md:762 +#: text/chapter8.md:763 msgid "" "Let's dig into our AddressBook `reactComponent`. We'll start with a " -"simplified component, and then build up to the actual code in `Main.purs`." +"simplified component and then build up to the actual code in `Main.purs`." msgstr "" "AddressBookの`reactComponent`を深堀りしましょう。\n" "単純化されたコンポーネントから始め、それから`Main.purs`で実際のコードに構築し" "ていきます。" #. type: Plain text -#: text/chapter8.md:764 +#: text/chapter8.md:765 msgid "" "Take a look at this minimal component. Feel free to substitute the full " "component with this one to see it run:" @@ -27883,7 +28078,7 @@ msgstr "" "遠慮なく全体のコンポーネントをこれに置き換えて実行の様子を見てみましょう。" #. type: Fenced code block (hs) -#: text/chapter8.md:765 +#: text/chapter8.md:766 #, no-wrap msgid "" "mkAddressBookApp :: Effect (ReactComponent {})\n" @@ -27899,12 +28094,12 @@ msgstr "" " (\\props -> pure $ D.text \"Hi! I'm an address book\")\n" #. type: Plain text -#: text/chapter8.md:774 +#: text/chapter8.md:775 msgid "`reactComponent` has this intimidating signature:" msgstr "`reactComponent`にはこのような威圧的なシグネチャがあります。" #. type: Fenced code block (hs) -#: text/chapter8.md:775 +#: text/chapter8.md:776 #, no-wrap msgid "" "reactComponent ::\n" @@ -27926,7 +28121,7 @@ msgstr "" " Effect (ReactComponent { | props })\n" #. type: Plain text -#: text/chapter8.md:787 +#: text/chapter8.md:788 msgid "" "The important points to note are the arguments after all the type class " "constraints. It takes a `String` (an arbitrary component name), a function " @@ -27938,18 +28133,18 @@ msgstr "" "記述する関数を取り、そして`Effect`に包まれた`ReactComponent`を返します。" #. type: Plain text -#: text/chapter8.md:789 +#: text/chapter8.md:790 msgid "The props-to-JSX function is simply:" msgstr "propsからJSXへの関数は単にこうです。" #. type: Fenced code block (hs) -#: text/chapter8.md:790 +#: text/chapter8.md:791 #, no-wrap msgid "\\props -> pure $ D.text \"Hi! I'm an address book\"\n" msgstr "\\props -> pure $ D.text \"Hi! I'm an address book\"\n" #. type: Plain text -#: text/chapter8.md:795 +#: text/chapter8.md:796 msgid "" "`props` are ignored, `D.text` returns `JSX`, and `pure` lifts to rendered " "JSX. Now `component` has everything it needs to produce the `ReactComponent`." @@ -27959,21 +28154,21 @@ msgstr "" "これで`component`には`ReactComponent`を生成するのに必要な全てがあります。" #. type: Plain text -#: text/chapter8.md:797 +#: text/chapter8.md:798 msgid "" -"Next we'll examine some of the additional complexities of the full Address " +"Next, we'll examine some of the additional complexities of the full Address " "Book component." msgstr "" -"次に完全なアドレス帳コンポーネントにある幾つかの複雑な事柄をもう少し調べてい" -"きます。" +"次に、完全なアドレス帳コンポーネントにある幾つかの複雑な事柄を調べていきま" +"す。" #. type: Plain text -#: text/chapter8.md:799 +#: text/chapter8.md:800 msgid "These are the first few lines of our full component:" msgstr "これらは完全なコンポーネントの最初の数行です。" #. type: Fenced code block (hs) -#: text/chapter8.md:800 +#: text/chapter8.md:801 #, no-wrap msgid "" "mkAddressBookApp :: Effect (ReactComponent {})\n" @@ -27987,34 +28182,33 @@ msgstr "" " Tuple person setPerson <- useState examplePerson\n" #. type: Plain text -#: text/chapter8.md:808 +#: text/chapter8.md:809 msgid "We track `person` as a piece of state with the `useState` hook." msgstr "`person`を`useState`フックの状態の一部として追跡します。" #. type: Fenced code block (hs) -#: text/chapter8.md:809 +#: text/chapter8.md:810 #, no-wrap msgid "Tuple person setPerson <- useState examplePerson\n" msgstr "Tuple person setPerson <- useState examplePerson\n" #. type: Plain text -#: text/chapter8.md:814 +#: text/chapter8.md:815 msgid "" "Note that you are free to break-up component state into multiple pieces of " "state with multiple calls to `useState`. For example, we could rewrite this " "app to use a separate piece of state for each record field of `Person`, but " -"that happens to result in a slightly less convenient architecture in this " -"case." +"that results in a slightly less convenient architecture in this case." msgstr "" "なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部" "品に分解することが自在にできます。\n" -"例えば`Person`のそれぞれのレコードフィールドについて分離した状態の部品を使っ" -"て、このアプリを書き直すことができるでしょう。\n" +"例えば`Person`の各レコードフィールドについて分離した状態の部品を使って、この" +"アプリを書き直すことができるでしょう。\n" "しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいま" "す。" #. type: Plain text -#: text/chapter8.md:816 +#: text/chapter8.md:817 msgid "" "In other examples, you may encounter the `/\\` infix operator for `Tuple`. " "This is equivalent to the above line:" @@ -28023,13 +28217,13 @@ msgstr "" "これは先の行と等しいものです。" #. type: Fenced code block (hs) -#: text/chapter8.md:817 +#: text/chapter8.md:818 #, no-wrap msgid "firstName /\\ setFirstName <- useState p.firstName\n" msgstr "firstName /\\ setFirstName <- useState p.firstName\n" #. type: Plain text -#: text/chapter8.md:822 +#: text/chapter8.md:823 msgid "" "`useState` takes a default initial value and returns the current value and a " "way to update the value. We can check the type of `useState` to gain more " @@ -28040,7 +28234,7 @@ msgstr "" "ます。" #. type: Fenced code block (hs) -#: text/chapter8.md:823 +#: text/chapter8.md:824 #, no-wrap msgid "" "useState ::\n" @@ -28054,7 +28248,7 @@ msgstr "" " Hook (UseState state) (Tuple state ((state -> state) -> Effect Unit))\n" #. type: Plain text -#: text/chapter8.md:831 +#: text/chapter8.md:832 msgid "" "We can strip the `Hook (UseState state)` wrapper off of the return value " "because `useState` is called within an `R.do` block. We'll elaborate on `R." @@ -28065,12 +28259,12 @@ msgstr "" "`R.do`は後で詳述します。" #. type: Plain text -#: text/chapter8.md:833 +#: text/chapter8.md:834 msgid "So now we can observe the following signatures:" msgstr "さてこれで以下のシグネチャを観察できます。" #. type: Fenced code block (hs) -#: text/chapter8.md:834 +#: text/chapter8.md:835 #, no-wrap msgid "" "person :: state\n" @@ -28080,7 +28274,7 @@ msgstr "" "setPerson :: (state -> state) -> Effect Unit\n" #. type: Plain text -#: text/chapter8.md:840 +#: text/chapter8.md:841 msgid "" "The specific type of `state` is determined by our initial default value. " "`Person` `Record` in this case because that is the type of `examplePerson`." @@ -28089,17 +28283,17 @@ msgstr "" "これは`examplePerson`の型なのでこの場合は`Person` `Record`です。" #. type: Plain text -#: text/chapter8.md:842 +#: text/chapter8.md:843 msgid "`person` is how we access the current state at each rerender." -msgstr "`person`はそれぞれの再描画の時点で現在の状態にアクセスする方法です。" +msgstr "`person`は各再描画の時点で現在の状態にアクセスする方法です。" #. type: Plain text -#: text/chapter8.md:844 +#: text/chapter8.md:845 msgid "" -"`setPerson` is how we update the state. We simply provide a function that " -"describes how to transform the current state to the new state. The record " -"update syntax is perfect for this when the type of `state` happens to be a " -"`Record`, for example:" +"`setPerson` is how we update the state. We provide a function describing how " +"to transform the current state into the new one. The record update syntax is " +"perfect for this when the type of `state` happens to be a `Record`, for " +"example:" msgstr "" "`setPerson`は状態を更新する方法です。\n" "単に現在の状態を新しい状態に変形する方法を記述する関数を提供します。\n" @@ -28108,7 +28302,7 @@ msgstr "" "例えば以下。" #. type: Fenced code block (hs) -#: text/chapter8.md:845 +#: text/chapter8.md:846 #, no-wrap msgid "" "setPerson (\\currentPerson -> currentPerson {firstName = \"NewName\"})\n" @@ -28118,18 +28312,18 @@ msgstr "" "\n" #. type: Plain text -#: text/chapter8.md:851 -msgid "or as shorthand:" +#: text/chapter8.md:852 +msgid "Or as shorthand:" msgstr "あるいは短かく以下です。" #. type: Fenced code block (hs) -#: text/chapter8.md:852 +#: text/chapter8.md:853 #, no-wrap msgid "setPerson _ {firstName = \"NewName\"}\n" msgstr "setPerson _ {firstName = \"NewName\"}\n" #. type: Plain text -#: text/chapter8.md:857 +#: text/chapter8.md:858 msgid "" "Non-`Record` states can also follow this update pattern. See [this guide]" "(https://github.com/megamaddu/purescript-react-basic-hooks/" @@ -28141,7 +28335,7 @@ msgstr "" "してください。" #. type: Plain text -#: text/chapter8.md:859 +#: text/chapter8.md:860 msgid "" "Recall that `useState` is used within an `R.do` block. `R.do` is a special " "react hooks variant of `do`. The `R.` prefix \"qualifies\" this as coming " @@ -28159,7 +28353,7 @@ msgstr "" "ます。" #. type: Plain text -#: text/chapter8.md:861 +#: text/chapter8.md:862 msgid "" "Another possible state management strategy is with `useReducer`, but that is " "outside the scope of this chapter." @@ -28168,12 +28362,12 @@ msgstr "" "です。" #. type: Plain text -#: text/chapter8.md:863 +#: text/chapter8.md:864 msgid "Rendering `JSX` occurs here:" msgstr "以下では`JSX`の描画が行われています。" #. type: Fenced code block (hs) -#: text/chapter8.md:864 +#: text/chapter8.md:865 #, no-wrap msgid "" "pure\n" @@ -28235,30 +28429,30 @@ msgstr "" " }\n" #. type: Plain text -#: text/chapter8.md:896 +#: text/chapter8.md:897 msgid "" -"Here we produce `JSX` which represents the intended state of the DOM. This " +"Here we produce `JSX`, which represents the intended state of the DOM. This " "JSX is typically created by applying functions corresponding to HTML tags (e." -"g. `div`, `form`, `h3`, `li`, `ul`, `label`, `input`) which create single " -"HTML elements. These HTML elements are actually React components themselves, " +"g., `div`, `form`, `h3`, `li`, `ul`, `label`, `input`) which create single " +"HTML elements. These HTML elements are React components themselves, " "converted to JSX. There are usually three variants of each of these " "functions:" msgstr "" -"ここでDOMの意図した状態を表現する`JSX`を生成しています。このJSXはHTMLタグ" -"(例:`div`、`form`、`h3`、`li`、`ul`、`label`、`input`)に対応し、典型的には" -"単一のHTML要素を作る関数を適用することで作られます。これらのHTML要素は実は" -"ReactコンポーネントそのものによりJSXに変換されます。通常これらの関数にはそれ" -"ぞれ3つの種類があります。" +"ここでDOMの意図した状態を表現する`JSX`を生成しています。\n" +"このJSXは単一のHTML要素を作るHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、" +"`label`、`input`)に対応する関数を適用することで作られるのが普通です。\n" +"これらのHTML要素はそれ自体がReactコンポーネントであり、JSXに変換されます。\n" +"通常これらの関数にはそれぞれ3つの種類があります。" #. type: Bullet: '- ' -#: text/chapter8.md:900 +#: text/chapter8.md:901 msgid "`div_`: Accepts an array of child elements. Uses default attributes." msgstr "" "`div_`: 子要素の配列を受け付けます。\n" "既定の属性を使います。" #. type: Bullet: '- ' -#: text/chapter8.md:900 +#: text/chapter8.md:901 msgid "" "`div`: Accepts a `Record` of attributes. An array of child elements may be " "passed to the `children` field of this record." @@ -28267,7 +28461,7 @@ msgstr "" "子要素の配列をこのレコードの`children`フィールドに渡すことができます。" #. type: Bullet: '- ' -#: text/chapter8.md:900 +#: text/chapter8.md:901 msgid "" "`div'`: Same as `div`, but returns the `ReactComponent` before conversion to " "`JSX`." @@ -28275,7 +28469,7 @@ msgstr "" "`div'`: `div`と同じですが、`JSX`に変換する前に`ReactComponent`を返します。" #. type: Plain text -#: text/chapter8.md:902 +#: text/chapter8.md:903 msgid "" "To display validation errors (if any) at the top of our form, we create a " "`renderValidationErrors` helper function that turns the `Errors` structure " @@ -28286,13 +28480,13 @@ msgstr "" "の残り部分の手前に付けます。" #. type: Fenced code block (hs) -#: text/chapter8.md:903 +#: text/chapter8.md:904 #, no-wrap msgid "{{#include ../exercises/chapter8/src/Main.purs:renderValidationErrors}}\n" msgstr "{{#include ../exercises/chapter8/src/Main.purs:renderValidationErrors}}\n" #. type: Plain text -#: text/chapter8.md:908 +#: text/chapter8.md:909 msgid "" "Note that since we are simply manipulating regular data structures here, we " "can use functions like `map` to build up more interesting elements:" @@ -28301,13 +28495,13 @@ msgstr "" "使ってもっと面白い要素を構築できます。" #. type: Fenced code block (hs) -#: text/chapter8.md:909 +#: text/chapter8.md:910 #, no-wrap msgid "children: [ D.ul_ (map renderError xs)]\n" msgstr "children: [ D.ul_ (map renderError xs)]\n" #. type: Plain text -#: text/chapter8.md:914 +#: text/chapter8.md:915 msgid "" "We use the `className` property to define classes for CSS styling. We're " "using the [Bootstrap](https://getbootstrap.com/) `stylesheet` for this " @@ -28322,13 +28516,13 @@ msgstr "" "`alert-danger`の装飾で強調されていてほしいです。" #. type: Fenced code block (hs) -#: text/chapter8.md:915 +#: text/chapter8.md:916 #, no-wrap msgid "className: \"alert alert-danger row\"\n" msgstr "className: \"alert alert-danger row\"\n" #. type: Plain text -#: text/chapter8.md:920 +#: text/chapter8.md:921 msgid "" "A second helper function is `formField`, which creates a text input for a " "single form field:" @@ -28337,13 +28531,13 @@ msgstr "" "これは、単一フォームフィールドのテキスト入力を作ります。" #. type: Fenced code block (hs) -#: text/chapter8.md:921 +#: text/chapter8.md:922 #, no-wrap msgid "{{#include ../exercises/chapter8/src/Main.purs:formField}}\n" msgstr "{{#include ../exercises/chapter8/src/Main.purs:formField}}\n" #. type: Plain text -#: text/chapter8.md:926 +#: text/chapter8.md:927 msgid "" "Putting the `input` and display `text` in a `label` aids in accessibility " "for screen readers." @@ -28352,7 +28546,7 @@ msgstr "" "ビリティの助けになります。" #. type: Plain text -#: text/chapter8.md:928 +#: text/chapter8.md:929 msgid "" "The `onChange` attribute allows us to describe how to respond to user input. " "We use the `handler` function, which has the following type:" @@ -28361,13 +28555,13 @@ msgstr "" "を使いますが、これは以下の型を持ちます。" #. type: Fenced code block (hs) -#: text/chapter8.md:929 +#: text/chapter8.md:930 #, no-wrap msgid "handler :: forall a. EventFn SyntheticEvent a -> (a -> Effect Unit) -> EventHandler\n" msgstr "handler :: forall a. EventFn SyntheticEvent a -> (a -> Effect Unit) -> EventHandler\n" #. type: Plain text -#: text/chapter8.md:934 +#: text/chapter8.md:935 msgid "" "For the first argument to `handler` we use `targetValue`, which provides the " "value of the text within the HTML `input` element. It matches the signature " @@ -28380,36 +28574,36 @@ msgstr "" "ています。" #. type: Fenced code block (hs) -#: text/chapter8.md:935 +#: text/chapter8.md:936 #, no-wrap msgid "targetValue :: EventFn SyntheticEvent (Maybe String)\n" msgstr "targetValue :: EventFn SyntheticEvent (Maybe String)\n" #. type: Plain text -#: text/chapter8.md:940 +#: text/chapter8.md:941 msgid "" -"In JavaScript, the `input` element's `onChange` event is actually " -"accompanied by a `String` value, but since strings in JavaScript can be " -"null, `Maybe` is used for safety." +"In JavaScript, the `input` element's `onChange` event is accompanied by a " +"`String` value, but since strings in JavaScript can be null, `Maybe` is used " +"for safety." msgstr "" -"JavaScriptでは`input`要素の`onChange`イベントは実は`String`値と一緒になってい" -"るのですが、JavaScriptの文字列はnullになりえるので、安全のために`Maybe`が使わ" -"れています。" +"JavaScriptでは`input`要素の`onChange`イベントには`String`値が伴います。\n" +"しかし、JavaScriptの文字列はnullになり得るので、安全のために`Maybe`が使われて" +"います。" #. type: Plain text -#: text/chapter8.md:942 +#: text/chapter8.md:943 #, no-wrap msgid "The second argument to `handler`, `(a -> Effect Unit)`, must therefore have this signature:\n" msgstr "したがって`(a -> Effect Unit)`の`handler`への2つ目の引数は、このシグネチャを持ちます。\n" #. type: Fenced code block (hs) -#: text/chapter8.md:943 +#: text/chapter8.md:944 #, no-wrap msgid "Maybe String -> Effect Unit\n" msgstr "Maybe String -> Effect Unit\n" #. type: Plain text -#: text/chapter8.md:948 +#: text/chapter8.md:949 msgid "" "It is a function that describes how to convert this `Maybe String` value " "into our desired effect. We define a custom `handleValue` function for this " @@ -28420,7 +28614,7 @@ msgstr "" "ます。" #. type: Fenced code block (hs) -#: text/chapter8.md:949 +#: text/chapter8.md:950 #, no-wrap msgid "" "onChange:\n" @@ -28440,27 +28634,27 @@ msgstr "" " handler targetValue handleValue\n" #. type: Plain text -#: text/chapter8.md:960 +#: text/chapter8.md:961 msgid "" "`setValue` is the function we provided to each `formField` call that takes a " "string and makes the appropriate record-update call to the `setPerson` hook." msgstr "" -"`setValue`はそれぞれの`formField`の呼び出しに与えた関数で、文字列を取り" -"`setPerson`フックに適切なレコード更新呼び出しを実施します。" +"`setValue`は`formField`の各呼び出しに与えた関数で、文字列を取り`setPerson`" +"フックに適切なレコード更新呼び出しを実施します。" #. type: Plain text -#: text/chapter8.md:962 +#: text/chapter8.md:963 msgid "Note that `handleValue` can be substituted as:" -msgstr "なお`handleValue`は以下のようにも置き換えられます。" +msgstr "なお、`handleValue`は以下のようにも置き換えられます。" #. type: Fenced code block (hs) -#: text/chapter8.md:963 +#: text/chapter8.md:964 #, no-wrap msgid "onChange: handler targetValue $ traverse_ setValue\n" msgstr "onChange: handler targetValue $ traverse_ setValue\n" #. type: Plain text -#: text/chapter8.md:968 +#: text/chapter8.md:969 msgid "" "Feel free to investigate the definition of `traverse_` to see how both forms " "are indeed equivalent." @@ -28468,18 +28662,20 @@ msgstr "" "`traverse_`の定義を調査して、両方の形式が確かに等価であることをご確認くださ" "い。" +# ここでのsourceはソースコードを意味していると思われます。 #. type: Plain text -#: text/chapter8.md:970 +#: text/chapter8.md:971 msgid "" "That covers the basics of our component implementation. However, you should " -"read the source accompanying this chapter in order to get a full " -"understanding of the way the component works." +"read the source accompanying this chapter to get a full understanding of the " +"way the component works." msgstr "" -"これでコンポーネント実装の基本を押さえました。しかし、コンポーネントの仕組み" -"を完全に理解するためには、この章に付随する出典元をお読みください。" +"これでコンポーネント実装の基本を押さえました。\n" +"しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随するソー" +"スをお読みください。" #. type: Plain text -#: text/chapter8.md:972 +#: text/chapter8.md:973 msgid "" "Obviously, this user interface can be improved in a number of ways. The " "exercises will explore some ways in which we can make the application more " @@ -28489,7 +28685,7 @@ msgstr "" "演習ではアプリケーションがより使いやすくなるような方法を追究していきます。" #. type: Plain text -#: text/chapter8.md:976 +#: text/chapter8.md:977 msgid "" "Modify `src/Main.purs` in the following exercises. There are no unit tests " "for these exercises." @@ -28498,42 +28694,45 @@ msgstr "" "これらの演習には単体試験はありません。" #. type: Bullet: '1. ' -#: text/chapter8.md:979 +#: text/chapter8.md:980 msgid "(Easy) Modify the application to include a work phone number text box." msgstr "" "(簡単)このアプリケーションを変更し、職場の電話番号を入力できるテキストボッ" "クスを追加してください。" #. type: Bullet: '1. ' -#: text/chapter8.md:979 +#: text/chapter8.md:980 msgid "" -"(Medium) Right now the application shows validation errors collected in a " +"(Medium) Right now, the application shows validation errors collected in a " "single \"pink-alert\" background. Modify to give each validation error its " "own pink-alert background by separating them with blank lines." msgstr "" "(普通)現時点でアプリケーションは検証エラーを単一の「pink-alert」背景に集め" "て表示させています。\n" -"空の線で分割することにより、それぞれの検証エラーにpink-alert背景を持たせるよ" -"うに変更してください。" +"空行で分離することにより、各検証エラーにpink-alert背景を持たせるように変更し" +"てください。" #. type: Plain text -#: text/chapter8.md:982 +#: text/chapter8.md:983 #, no-wrap msgid "" " _Hint_: Instead of using a `ul` element to show the validation errors in a list, modify the code to create one `div` with the `alert` and `alert-danger` styles for each error.\n" "1. (Difficult, Extended) One problem with this user interface is that the validation errors are not displayed next to the form fields they originated from. Modify the code to fix this problem.\n" msgstr "" -" *手掛かり*:リスト中の検証エラーを表示するのに`ul`要素を使う代わりに、コードを変更し、それぞれのエラーに`alert`と`alert-danger`装飾を持つ`div`を作ってください。\n" -"1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。コードを変更してこの問題を解決してください。\n" +" *手掛かり*:リスト中の検証エラーを表示するのに`ul`要素を使う代わりに、コードを変更し、各エラーに`alert`と`alert-danger`装飾を持つ`div`を作ってください。\n" +"1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。\n" +" コードを変更してこの問題を解決してください。\n" #. type: Plain text -#: text/chapter8.md:984 +#: text/chapter8.md:985 #, no-wrap -msgid " _Hint_: the error type returned by the validator should be extended to indicate which field caused the error. You might want to use the following modified `Errors` type:\n" -msgstr " *手掛かり*:検証器によって返されるエラーの型は、エラーの原因となっているフィールドを示すために拡張する必要があります。次のような変更されたエラー型を使用したくなるでしょう。\n" +msgid " _Hint_: The error type returned by the validator should be extended to indicate which field caused the error. You might want to use the following modified `Errors` type:\n" +msgstr "" +" *手掛かり*:検証器によって返されるエラーの型を、エラーの原因となっているフィールドを示すために拡張するべきです。\n" +" 以下の変更されたエラー型を使うと良いでしょう。\n" #. type: Plain text -#: text/chapter8.md:992 +#: text/chapter8.md:993 #, no-wrap msgid "" " ```hs\n" @@ -28553,13 +28752,13 @@ msgstr "" " | PhoneField PhoneType\n" #. type: Plain text -#: text/chapter8.md:994 +#: text/chapter8.md:995 #, no-wrap msgid " data ValidationError = ValidationError String Field\n" msgstr " data ValidationError = ValidationError String Field\n" #. type: Plain text -#: text/chapter8.md:997 +#: text/chapter8.md:998 #, no-wrap msgid "" " type Errors = Array ValidationError\n" @@ -28569,13 +28768,13 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter8.md:999 +#: text/chapter8.md:1000 #, no-wrap -msgid " You will need to write a function which extracts the validation error for a particular `Field` from the `Errors` structure.\n" +msgid " You will need to write a function that extracts the validation error for a particular `Field` from the `Errors` structure.\n" msgstr " `Error`構造体から特定の`Field`のための検証エラーを取り出す関数を書く必要があるでしょう。\n" #. type: Plain text -#: text/chapter8.md:1003 +#: text/chapter8.md:1004 msgid "" "This chapter has covered a lot of ideas about handling side-effects in " "PureScript:" @@ -28583,28 +28782,30 @@ msgstr "" "この章ではPureScriptでの副作用の扱いについての多くの考え方を導入しました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 -msgid "We met the `Monad` type class, and its connection to do notation." -msgstr "`Monad`型クラスとdo記法との関係性に出会いました。" +#: text/chapter8.md:1011 +msgid "We met the `Monad` type class and its connection to do notation." +msgstr "`Monad`型クラスとdo記法との関係性を見ました。" +# they allow usが訳せているかどうか…… #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 msgid "" -"We introduced the monad laws, and saw how they allow us to transform code " +"We introduced the monad laws and saw how they allow us to transform code " "written using do notation." msgstr "" "モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。" +# monads can be usedが訳せているかどうか…… #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 msgid "" -"We saw how monads can be used abstractly, to write code which works with " +"We saw how monads can be used abstractly to write code that works with " "different side-effects." msgstr "" -"異なる副作用を扱うコードを書くために、モナドを抽象的に使う方法を見ました。" +"異なる副作用を扱うコードを書く上で、モナドを抽象的に使う方法を見ました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 msgid "" "We saw how monads are examples of applicative functors, how both allow us to " "compute with side-effects, and the differences between the two approaches." @@ -28613,26 +28814,26 @@ msgstr "" "を可能にするのかということ、そして2つの手法の違いを説明しました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 msgid "" "The concept of native effects was defined, and we met the `Effect` monad, " -"which is used to handle native side-effects." +"which handles native side-effects." msgstr "" -"ネイティブな作用の概念を定義し、ネイティブな副作用を処理するために使用する " -"`Effect`モナドを導入しました。" +"ネイティブな作用の概念を定義し、`Effect`モナドを見ました。\n" +"これはネイティブな副作用を扱うものでした。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 msgid "" "We used the `Effect` monad to handle a variety of effects: random number " "generation, exceptions, console IO, mutable state, and DOM manipulation " "using React." msgstr "" "乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作と" -"いった、さまざまな作用を扱うために `Effect`モナドを使いました。" +"いった、様々な作用を扱うために `Effect`モナドを使いました。" #. type: Plain text -#: text/chapter8.md:1011 +#: text/chapter8.md:1012 msgid "" "The `Effect` monad is a fundamental tool in real-world PureScript code. It " "will be used in the rest of the book to handle side-effects in a number of " @@ -28653,13 +28854,14 @@ msgid "" "This chapter focuses on the `Aff` monad, which is similar to the `Effect` " "monad, but represents _asynchronous_ side-effects. We'll demonstrate " "examples of asynchronously interacting with the filesystem and making HTTP " -"requests. We'll also cover how to manage sequential and parallel execution " -"of asynchronous effects." +"requests. We'll also cover managing sequential and parallel execution of " +"asynchronous effects." msgstr "" -"この章では`Aff`モナドに集中します。これは`Effect`モナドに似ていますが、*非同" -"期*な副作用を表現するものです。ファイルシステムとやりとりしてHTTPリクエストを" -"作る、非同期な例を実演していきます。また非同期作用の直列ないし並列な実行の管" -"理方法も押さえます。" +"この章では`Aff`モナドに集中します。\n" +"これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。\n" +"非同期にファイルシステムとやり取りしたりHTTPリクエストしたりする例を実演して" +"いきます。\n" +"また非同期作用の直列ないし並列な実行の管理方法も押さえます。" #. type: Plain text #: text/chapter9.md:10 @@ -28690,10 +28892,10 @@ msgstr "`parallel` - `Aff`の並列実行。" #: text/chapter9.md:17 msgid "" "When running outside of the browser (such as in our Node.js environment), " -"the `affjax` library requires the `xhr2` NPM module, which is listed as " +"the `affjax` library requires the `xhr2` NPM module, which is listed as a " "dependency in the `package.json` of this chapter. Install that by running:" msgstr "" -"(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリは" +"(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリには" "`xhr2`NPMモジュールが必要です。\n" "このモジュールはこの章の`package.json`中の依存関係に挙げられています。\n" "以下を走らせてインストールします。" @@ -28766,7 +28968,7 @@ msgstr "" #: text/chapter9.md:43 msgid "" "It is also possible to use callbacks or synchronous functions, but those are " -"less desireable because:" +"less desirable because:" msgstr "" "コールバックや同期関数を使うことも可能ですが、以下の理由から望ましくありませ" "ん。" @@ -28821,23 +29023,23 @@ msgstr "" #: text/chapter9.md:58 msgid "" "It is also possible to re-write the above snippet using callbacks or " -"synchronous functions (for example with `Node.FS.Async` and `Node.FS.Sync` " +"synchronous functions (for example, with `Node.FS.Async` and `Node.FS.Sync`, " "respectively), but those share the same downsides as discussed earlier with " -"JavaScript, and so that coding style is not recommended." +"JavaScript, so that coding style is not recommended." msgstr "" -"上のコード片をコールバックや同期関数を使って書き換えることも可能ですが(例え" -"ば`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)、JavaScriptで前にお話し" -"したのと同じ短所がここでも通用するため、それらのコーディング形式は推奨されま" -"せん。" +"上のコード片をコールバックや同期関数を使って書き換えることも可能です(例えば" +"`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)。\n" +"しかし、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それら" +"のコーディング形式は推奨されません。" #. type: Plain text #: text/chapter9.md:60 msgid "" "The syntax for working with `Aff` is very similar to working with `Effect`. " -"They are both monads, and can therefore be written with do notation." +"They are both monads and can therefore be written with do notation." msgstr "" "`Aff`を扱う文法は`Effect`を扱うものと大変似ています。\n" -"どちらもモナドですし、したがってdo記法で書くことができます。" +"どちらもモナドですし、したがってdo記法で書けます。" #. type: Plain text #: text/chapter9.md:62 @@ -28907,7 +29109,7 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter9.md:90 msgid "" -"(Easy) Write a `concatenateFiles` function which concatenates two text files." +"(Easy) Write a `concatenateFiles` function that concatenates two text files." msgstr "" "(簡単)2つのテキストファイルを連結する関数`concatenateFiles`を書いてくださ" "い。" @@ -28916,11 +29118,11 @@ msgstr "" #: text/chapter9.md:92 msgid "" "(Medium) Write a function `concatenateMany` to concatenate multiple text " -"files, given an array of input file names and an output file name. _Hint_: " -"use `traverse`." +"files, given an array of input and output file names. _Hint_: use `traverse`." msgstr "" -"(普通)入力ファイル名の配列と出力ファイル名が与えられたとき、複数のテキスト" -"ファイルを連結する関数`concatenateMany`を書いてください。\n" +"(普通)複数のテキストファイルを連結する関数`concatenateMany`を書いてくださ" +"い。\n" +"入力ファイル名の配列と出力ファイル名が与えられます。\n" "*手掛かり*:`traverse`を使ってください。" #. type: Bullet: ' 1. ' @@ -28942,16 +29144,15 @@ msgstr "更なるAffの資料" #. type: Plain text #: text/chapter9.md:98 msgid "" -"If you haven't already taken a look at the [official Aff guide](https://" -"pursuit.purescript.org/packages/purescript-aff/), skim through that now. " -"It's not a direct prerequisite for completing the remaining exercises in " -"this chapter, but you may find it helpful to lookup some functions on " -"Pursuit." +"If you haven't already looked at the [official Aff guide](https://pursuit." +"purescript.org/packages/purescript-aff/), skim through that now. It's not a " +"direct prerequisite for completing the remaining exercises in this chapter, " +"but you may find it helpful to lookup some functions on Pursuit." msgstr "" "もしまだ[公式のAffの手引き](https://pursuit.purescript.org/packages/" "purescript-aff/)を見ていなければ、今ざっと目を通してください。\n" -"この章の残りの演習を完了する上で事前に必要なことではありませんが、Pursuitで何" -"らかの関数を見付けだす助けになるかもしれません。" +"この章の残りの演習を完了する上で事前に直接必要なことではありませんが、Pursuit" +"で何らかの関数を見付けだす助けになるかもしれません。" #. type: Plain text #: text/chapter9.md:100 @@ -28985,39 +29186,45 @@ msgid "A HTTP Client" msgstr "HTTPクライアント" #. type: Plain text -#: text/chapter9.md:109 +#: text/chapter9.md:107 msgid "" "The `affjax` library offers a convenient way to make asynchronous AJAX HTTP " -"requests with `Aff`. Depending on what environment you are targeting you " +"requests with `Aff`. Depending on what environment you are targeting, you " "need to use either the [purescript-affjax-web](https://github.com/purescript-" "contrib/purescript-affjax-web) or the [purescript-affjax-node](https://" -"github.com/purescript-contrib/purescript-affjax-node) library. In the rest " -"of this chapter we will be targeting node and thus using `purescript-affjax-" -"node`. Consult the [Affjax docs](https://pursuit.purescript.org/packages/" -"purescript-affjax) for more usage information. Here is an example that makes " -"HTTP GET requests at a provided URL and returns the response body or an " -"error message:" -msgstr "" -"`affjax`ライブラリは`Aff`で非同期AJAX HTTP要求する便利な手段を提供します。\n" +"github.com/purescript-contrib/purescript-affjax-node) library." +msgstr "" +"`affjax`ライブラリは`Aff`で非同期なAJAXのHTTP要求をする上での便利な手段を提供" +"します。\n" "対象としている環境が何であるかによって、[purescript-affjax-web](https://" "github.com/purescript-contrib/purescript-affjax-web)または[purescript-affjax-" "node](https://github.com/purescript-contrib/purescript-affjax-node)のどちらか" -"のライブラリを使う必要があります。\n" -"この章の以降ではNodeを対象としていくので、`purescript-affjax-node`を使いま" +"のライブラリを使う必要があります。" + +#. type: Plain text +#: text/chapter9.md:110 +msgid "" +"In the rest of this chapter, we will be targeting node and thus using " +"`purescript-affjax-node`. Consult the [Affjax docs](https://pursuit." +"purescript.org/packages/purescript-affjax) for more usage information. Here " +"is an example that makes HTTP GET requests at a provided URL and returns the " +"response body or an error message:" +msgstr "" +"この章の以降ではnodeを対象としていくので、`purescript-affjax-node`を使いま" "す。\n" "より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript." "org/packages/purescript-affjax)にあたってください。\n" -"以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例" -"です。" +"以下は与えられたURLに向けてHTTPのGET要求をして、応答本文ないしエラー文言を返" +"す例です。" #. type: Fenced code block (hs) -#: text/chapter9.md:110 +#: text/chapter9.md:111 #, no-wrap msgid "{{#include ../exercises/chapter9/test/HTTP.purs:getUrl}}\n" msgstr "{{#include ../exercises/chapter9/test/HTTP.purs:getUrl}}\n" #. type: Plain text -#: text/chapter9.md:115 +#: text/chapter9.md:116 msgid "" "When calling this in the repl, `launchAff_` is required to convert the `Aff` " "to a repl-compatible `Effect`:" @@ -29026,7 +29233,7 @@ msgstr "" "と変換する必要があります。" #. type: Fenced code block (shell) -#: text/chapter9.md:116 +#: text/chapter9.md:117 #, no-wrap msgid "" "$ spago repl\n" @@ -29060,7 +29267,7 @@ msgstr "" "{\"data\":{\"id\":1,\"email\":\"george.bluth@reqres.in\",\"first_name\":\"George\",\"last_name\":\"Bluth\", ...}}\n" #. type: Bullet: '1. ' -#: text/chapter9.md:136 +#: text/chapter9.md:137 msgid "" "(Easy) Write a function `writeGet` which makes an HTTP `GET` request to a " "provided url, and writes the response body to a file." @@ -29069,13 +29276,13 @@ msgstr "" "`writeGet`を書いてください。" #. type: Title ## -#: text/chapter9.md:137 +#: text/chapter9.md:138 #, no-wrap msgid "Parallel Computations" msgstr "並列計算" #. type: Plain text -#: text/chapter9.md:140 +#: text/chapter9.md:141 msgid "" "We've seen how to use the `Aff` monad and do notation to compose " "asynchronous computations in sequence. It would also be useful to be able to " @@ -29088,24 +29295,24 @@ msgstr "" "`Aff`があれば2つの計算を次々に開始するだけで並列に計算できます。" #. type: Plain text -#: text/chapter9.md:142 +#: text/chapter9.md:143 msgid "" -"The `parallel` package defines a type class `Parallel` for monads like `Aff` " -"which support parallel execution. When we met applicative functors earlier " -"in the book, we observed how applicative functors can be useful for " +"The `parallel` package defines a type class `Parallel` for monads like " +"`Aff`, which support parallel execution. When we met applicative functors " +"earlier in the book, we observed how applicative functors can be useful for " "combining parallel computations. In fact, an instance for `Parallel` defines " "a correspondence between a monad `m` (such as `Aff`) and an applicative " -"functor `f` which can be used to combine computations in parallel:" +"functor `f` that can be used to combine computations in parallel:" msgstr "" "`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義して" "おり、並列実行に対応しています。\n" "以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリ" "カティブ関手がどれほど便利なのかを見ました。\n" -"実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を合" -"成するために使われるアプリカティブ関手`f`との対応関係を定義しているのです。" +"実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を組" +"み合わせるために使えるアプリカティブ関手`f`との対応関係を定義しているのです。" #. type: Fenced code block (hs) -#: text/chapter9.md:143 +#: text/chapter9.md:144 #, no-wrap msgid "" "class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where\n" @@ -29117,12 +29324,12 @@ msgstr "" " parallel :: forall a. m a -> f a\n" #. type: Plain text -#: text/chapter9.md:150 +#: text/chapter9.md:151 msgid "The class defines two functions:" msgstr "このクラスは2つの関数を定義しています。" #. type: Bullet: '- ' -#: text/chapter9.md:153 +#: text/chapter9.md:154 msgid "" "`parallel`, which takes computations in the monad `m` and turns them into " "computations in the applicative functor `f`, and" @@ -29131,26 +29338,26 @@ msgstr "" "す。" #. type: Bullet: '- ' -#: text/chapter9.md:153 +#: text/chapter9.md:154 msgid "`sequential`, which performs a conversion in the opposite direction." msgstr "`sequential`:反対方向に変換します。" #. type: Plain text -#: text/chapter9.md:155 +#: text/chapter9.md:156 msgid "" "The `aff` library provides a `Parallel` instance for the `Aff` monad. It " -"uses mutable references to combine `Aff` actions in parallel, by keeping " +"uses mutable references to combine `Aff` actions in parallel by keeping " "track of which of the two continuations has been called. When both results " "have been returned, we can compute the final result and pass it to the main " "continuation." msgstr "" -"`aff`ライブラリは `Aff`モナドの `Parallel`インスタンスを提供します。\n" -"これは、2つの継続 (continuation) のどちらが呼び出されたかを把握することによっ" -"て、変更可能な参照を使用して並列に `Aff`アクションを組み合わせます。\n" -"両方の結果が返されたら、最終結果を計算してメインの継続に渡すことができます。" +"`aff`ライブラリは`Aff`モナドの`Parallel`インスタンスを提供します。\n" +"これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参" +"照を使用して並列に`Aff`動作を組み合わせます。\n" +"両方の結果が返されたら、最終結果を計算してメインの継続に渡せます。" #. type: Plain text -#: text/chapter9.md:157 +#: text/chapter9.md:158 msgid "" "Because applicative functors support lifting of functions of arbitrary " "arity, we can perform more computations in parallel by using the applicative " @@ -29163,19 +29370,20 @@ msgstr "" "関数から恩恵を受けることもできます。" #. type: Plain text -#: text/chapter9.md:159 +#: text/chapter9.md:160 msgid "" -"We can also combine parallel computations with sequential portions of code, " +"We can also combine parallel computations with sequential portions of code " "by using applicative combinators in a do notation block, or vice versa, " "using `parallel` and `sequential` to change type constructors where " "appropriate." msgstr "" -"必要に応じて `parralel`と`sequential`を使って型構築子を変更することで、do記法" -"ブロック中でアプリカティブコンビネータを使い、直列的なコードの一部で並列計算" -"を結合したり、またはその逆を行ったりできます。" +"直列的なコードの一部と並列計算を組み合わせることもできます。\n" +"それにはdo記法ブロック中でアプリカティブコンビネータを使います。\n" +"その逆も然りで、必要に応じて`parralel`と`sequential`を使って型構築子を変更す" +"れば良いのです。" #. type: Plain text -#: text/chapter9.md:163 +#: text/chapter9.md:164 msgid "" "To demonstrate the difference between sequential and parallel execution, " "we'll create an array of 100 10-millisecond delays, then execute those " @@ -29189,13 +29397,13 @@ msgstr "" "`parSequence_`で置き換えるだけで有効になるところに注目です。" #. type: Fenced code block (hs) -#: text/chapter9.md:164 +#: text/chapter9.md:165 #, no-wrap msgid "{{#include ../exercises/chapter9/test/ParallelDelay.purs:delays}}\n" msgstr "{{#include ../exercises/chapter9/test/ParallelDelay.purs:delays}}\n" #. type: Fenced code block (shell) -#: text/chapter9.md:168 +#: text/chapter9.md:169 #, no-wrap msgid "" "$ spago repl\n" @@ -29219,7 +29427,7 @@ msgstr "" "unit\n" #. type: Plain text -#: text/chapter9.md:181 +#: text/chapter9.md:182 msgid "" "Here's a more real-world example of making multiple HTTP requests in " "parallel. We're reusing our `getUrl` function to fetch information from two " @@ -29233,13 +29441,13 @@ msgstr "" "この例は代わりに`traverse`でも問題なく動きますがより遅くなるでしょう。" #. type: Fenced code block (hs) -#: text/chapter9.md:182 +#: text/chapter9.md:183 #, no-wrap msgid "{{#include ../exercises/chapter9/test/ParallelFetch.purs:fetchPar}}\n" msgstr "{{#include ../exercises/chapter9/test/ParallelFetch.purs:fetchPar}}\n" #. type: Fenced code block (shell) -#: text/chapter9.md:186 +#: text/chapter9.md:187 #, no-wrap msgid "" "$ spago repl\n" @@ -29263,7 +29471,7 @@ msgstr "" "]\n" #. type: Plain text -#: text/chapter9.md:199 +#: text/chapter9.md:200 msgid "" "A full listing of available parallel functions can be found in the " "[`parallel` docs on Pursuit](https://pursuit.purescript.org/packages/" @@ -29277,18 +29485,17 @@ msgstr "" "contrib/purescript-aff#parallel-execution)にもより多くの例が含まれています。" #. type: Bullet: '1. ' -#: text/chapter9.md:203 +#: text/chapter9.md:204 msgid "" -"(Easy) Write a `concatenateManyParallel` function which has the same " -"signature as the earlier `concatenateMany` function, but reads all input " -"files in parallel." +"(Easy) Write a `concatenateManyParallel` function with the same signature as " +"the earlier `concatenateMany` function but reads all input files in parallel." msgstr "" "(簡単)前の`concatenateMany`関数と同じシグネチャを持つ" "`concatenateManyParallel`関数を書いてください。\n" "ただし全ての入力ファイルを並列に読むようにしてください。" #. type: Bullet: '1. ' -#: text/chapter9.md:207 +#: text/chapter9.md:208 msgid "" "(Medium) Write a `getWithTimeout :: Number -> String -> Aff (Maybe String)` " "function which makes an HTTP `GET` request at the provided URL and returns " @@ -29299,7 +29506,7 @@ msgstr "" "い。" #. type: Bullet: ' - ' -#: text/chapter9.md:207 +#: text/chapter9.md:208 msgid "" "`Nothing`: if the request takes longer than the provided timeout (in " "milliseconds)." @@ -29307,15 +29514,15 @@ msgstr "" "`Nothing`: 要求してから与えられた時間制限(ミリ秒単位)より長く掛かった場合。" #. type: Bullet: ' - ' -#: text/chapter9.md:207 +#: text/chapter9.md:208 msgid "" "The string response: if the request succeeds before the timeout elapses." msgstr "文字列の応答:時間制限を越える前に要求が成功した場合。" #. type: Bullet: '1. ' -#: text/chapter9.md:209 +#: text/chapter9.md:210 msgid "" -"(Difficult) Write a `recurseFiles` function which takes a \"root\" file and " +"(Difficult) Write a `recurseFiles` function that takes a \"root\" file and " "returns an array of all paths listed in that file (and listed in the listed " "files too). Read listed files in parallel. Paths are relative to the " "directory of the file they appear in. _Hint:_ The `node-path` module has " @@ -29325,17 +29532,17 @@ msgstr "" "一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてくださ" "い。\n" "一覧にあるファイルを並列に読んでください。\n" -"パスはそのファイルが表れたディレクトリから相対的なものです。\n" -"*手掛かり*:`node_path`モジュールにはディレクトリを扱う上で便利な関数がありま" +"パスはそのファイルが現れたディレクトリから相対的なものです。\n" +"*手掛かり*:`node-path`モジュールにはディレクトリを扱う上で便利な関数がありま" "す。" #. type: Plain text -#: text/chapter9.md:211 +#: text/chapter9.md:212 msgid "For example, if starting from the following `root.txt` file:" msgstr "例えば次のような`root.txt`ファイルから始まるとします。" #. type: Fenced code block (shell) -#: text/chapter9.md:212 +#: text/chapter9.md:213 #, no-wrap msgid "" "$ cat root.txt\n" @@ -29373,32 +29580,166 @@ msgstr "" "$ cat c/a/a.txt\n" #. type: Plain text -#: text/chapter9.md:232 +#: text/chapter9.md:233 msgid "The expected output is:" msgstr "期待される出力は次の通り。" #. type: Fenced code block (hs) -#: text/chapter9.md:233 +#: text/chapter9.md:234 #, no-wrap msgid "[\"root.txt\",\"a.txt\",\"b/a.txt\",\"b/b.txt\",\"b/c/a.txt\",\"c/a/a.txt\"]\n" msgstr "[\"root.txt\",\"a.txt\",\"b/a.txt\",\"b/b.txt\",\"b/c/a.txt\",\"c/a/a.txt\"]\n" #. type: Plain text -#: text/chapter9.md:240 -msgid "In this chapter we covered asynchronous effects and learned how to:" -msgstr "この章では非同期エフェクトと以下の方法を押さえました。" +#: text/chapter9.md:241 +msgid "In this chapter, we covered asynchronous effects and learned how to:" +msgstr "この章では非同期作用と以下の方法を押さえました。" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 msgid "Run asynchronous code in the `Aff` monad with the `aff` library." msgstr "`aff`ライブラリを使って`Aff`モナド中で非同期コードを走らせる。" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 msgid "Make HTTP requests asynchronously with the `affjax` library." -msgstr "`affjax`ライブラリを使って非同期にHTTPリクエストを行う。" +msgstr "`affjax`ライブラリを使って非同期にHTTPリクエストする。" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 msgid "Run asynchronous code in parallel with the `parallel` library." msgstr "`parallel`ライブラリを使って並列に非同期コードを走らせる。" + +#. type: Title # +#: CONTRIBUTING.md:1 +#, no-wrap +msgid "Contributing" +msgstr "貢献" + +#. type: Plain text +#: CONTRIBUTING.md:4 +msgid "Please open PRs or Issues if you find anything to improve in the book." +msgstr "本書で何かしら改善になるものを見付けたらPRやイシューを開いてください。" + +#. type: Plain text +#: CONTRIBUTING.md:6 +msgid "We appreciate your feedback." +msgstr "フィードバックに感謝します。" + +#. type: Title ## +#: CONTRIBUTING.md:7 +#, no-wrap +msgid "Editing chapter text" +msgstr "章のテキストを編集する" + +#. type: Plain text +#: CONTRIBUTING.md:10 +msgid "" +"To test changes to the text locally, install [mdbook](https://github.com/" +"rust-lang/mdBook), then run this command from repo root:" +msgstr "テキストの変更をローカルで見てみるには、[mdbook](https://github.com/rust-lang/mdBook)をインストールし、以下のコマンドをリポジトリのルートで走らせます。" + +#. type: Fenced code block (sh) +#: CONTRIBUTING.md:11 +#, no-wrap +msgid "mdbook serve -o\n" +msgstr "mdbook serve -o\n" + +#. type: Plain text +#: CONTRIBUTING.md:15 +msgid "" +"The rendered webpage will automatically refresh with any changes to readme " +"files." +msgstr "readmeファイルへの変更毎に描画されたwebページが自動的に再読み込みされます。" + +#~ msgid "" +#~ "PureScript's functions correspond to JavaScript's functions. The " +#~ "PureScript standard libraries provide plenty of examples of functions, " +#~ "and we will see more in this chapter:" +#~ msgstr "" +#~ "PureScriptの関数はJavaScriptの関数に対応しています。PureScriptの標準ライブ" +#~ "ラリは多くの関数の例を提供しており、この章ではそれらをもう少し詳しく見てい" +#~ "きます。" + +#, no-wrap +#~ msgid "" +#~ "> import Prelude\n" +#~ "> :type flip\n" +#~ "forall a b c. (a -> b -> c) -> b -> a -> c\n" +#~ "\n" +#~ "> :type const\n" +#~ "forall a b. a -> b -> a\n" +#~ msgstr "" +#~ "> import Prelude\n" +#~ "> :type flip\n" +#~ "forall a b c. (a -> b -> c) -> b -> a -> c\n" +#~ "\n" +#~ "> :type const\n" +#~ "forall a b. a -> b -> a\n" + +#~ msgid "" +#~ "In the previous section, we saw the types of some functions defined in " +#~ "the Prelude. For example, the `flip` function had the following type:" +#~ msgstr "" +#~ "前の節ではPreludeで定義された関数の型を幾つか見てきました。\n" +#~ "例えば`flip`関数は次のような型を持っていました。" + +#, no-wrap +#~ msgid "" +#~ "> :type flip\n" +#~ "forall a b c. (a -> b -> c) -> b -> a -> c\n" +#~ msgstr "" +#~ "> :type flip\n" +#~ "forall a b c. (a -> b -> c) -> b -> a -> c\n" + +#, no-wrap +#~ msgid "(Int -> String -> String) -> String -> Int -> String\n" +#~ msgstr "(Int -> String -> String) -> String -> Int -> String\n" + +#, no-wrap +#~ msgid "" +#~ "> flip (\\n s -> show n <> s) \"Ten\" 10\n" +#~ "\n" +#~ "\"10Ten\"\n" +#~ msgstr "" +#~ "> flip (\\n s -> show n <> s) \"Ten\" 10\n" +#~ "\n" +#~ "\"10Ten\"\n" + +#~ msgid "" +#~ "While we can choose any types for `a`, `b`, and `c`, we have to be " +#~ "consistent. The type of function passed to `flip` had to be consistent " +#~ "with the types of the other arguments. That is why we passed the string " +#~ "`\"Ten\"` as the second argument and the number `10` as the third. It " +#~ "would not work if the arguments were reversed:" +#~ msgstr "" +#~ "`a`、`b`、`c`の型はどんな型でも選べるといっても、一貫していなければなりま" +#~ "せん。\n" +#~ "`flip`に渡す関数の型は他の引数の型と整合性がなくてはなりません。\n" +#~ "第2引数として文字列`\"Ten\"`、第3引数として数`10`を渡したのはそれが理由で" +#~ "す。\n" +#~ "もし引数が逆になっているとうまくいかないでしょう。" + +#, no-wrap +#~ msgid "" +#~ "> flip (\\n s -> show n <> s) 10 \"Ten\"\n" +#~ "\n" +#~ "Could not match type Int with type String\n" +#~ msgstr "" +#~ "> flip (\\n s -> show n <> s) 10 \"Ten\"\n" +#~ "\n" +#~ "Could not match type Int with type String\n" + +#~ msgid "" +#~ "Note how the declarations for `foo` and `bar` are indented past the " +#~ "declaration of `example`." +#~ msgstr "" +#~ "ここで `foo`や `bar`の宣言は `example`の宣言より深く字下げされていることに" +#~ "注意してください。" + +#~ msgid "" +#~ "The only exception to this rule is the `where` keyword in the initial " +#~ "`module` declaration at the top of a source file." +#~ msgstr "" +#~ "ただし、ソースファイルの先頭、最初の`module`宣言におけるキーワード`where`" +#~ "だけは、この規則の唯一の例外になっています。" diff --git a/translation/terms.txt b/translation/terms.txt new file mode 100644 index 00000000..3f7e7445 --- /dev/null +++ b/translation/terms.txt @@ -0,0 +1,20 @@ +JavaScript runtime: 実行器 +accumulator: 累算器。一般には「累積」とされることもあるようです。 +canvas: 固有名詞、HTML 5で導入された機能としてのCanvasは英単語として、一般名詞としては「キャンバス」と片仮名にします。 +context: 文脈。一般には単に「コンテキスト」とされるようです。 +corner case: 特殊な場合 +hash code: ハッシュコード。「ハッシュ値」とされていました。 +inhabitant: 現住 +optional: 省略可能な +pair: 組 +pattern match: パターン照合 +primitive type: 原始型 +run the computation: 計算する。計算を走らせる、が直訳ですが単純にします。 +synonym: 同義語。 +top level: 最上位 +type synonym: 型同義語 +configure: 構成。設定はsettingで一応区別したいです。 +handle: 制御対象 +help message: ヘルプ文言。「使用方法の文言」と噛み砕くのもありそうですが、ややまどろっこしい感じがします。 +open import: 一括インポート +keyword: キーワード。予約語はまた意味が違ってくるようです。