From 1410f28a936a22c0bb0aac45b37b08df8d2a0284 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Mon, 10 Jul 2023 22:33:29 +0900 Subject: [PATCH 01/29] [ disable ] CI when pull request --- .github/workflows/mdbook.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: From a92f91ebc5451cdc1f12ceb752ad7d7081c25e63 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Mon, 10 Jul 2023 21:31:15 +0900 Subject: [PATCH 02/29] [ update ] intro and chapter 1 translation * [ update ] PO file * [ resolve ] fuzzies --- text-ja/chapter1.md | 113 +- text-ja/chapter10.md | 426 ++- text-ja/chapter11.md | 1166 ------ text-ja/chapter12.md | 721 ---- text-ja/chapter13.md | 480 --- text-ja/chapter14.md | 827 ---- text-ja/chapter2.md | 55 +- text-ja/chapter3.md | 849 ----- text-ja/chapter4.md | 732 ---- text-ja/chapter5.md | 643 ---- text-ja/chapter6.md | 896 ----- text-ja/chapter7.md | 805 ---- text-ja/chapter8.md | 1154 ------ text-ja/chapter9.md | 98 +- translation/all.pot | 4541 +++++++++++----------- translation/ja.po | 8518 +++++++++++++++++++++++++++++------------- 16 files changed, 8607 insertions(+), 13417 deletions(-) delete mode 100644 text-ja/chapter11.md delete mode 100644 text-ja/chapter12.md delete mode 100644 text-ja/chapter13.md delete mode 100644 text-ja/chapter14.md delete mode 100644 text-ja/chapter3.md delete mode 100644 text-ja/chapter4.md delete mode 100644 text-ja/chapter5.md delete mode 100644 text-ja/chapter6.md delete mode 100644 text-ja/chapter7.md delete mode 100644 text-ja/chapter8.md diff --git a/text-ja/chapter1.md b/text-ja/chapter1.md index d1c29a4a..a04f7ff2 100644 --- a/text-ja/chapter1.md +++ b/text-ja/chapter1.md @@ -35,29 +35,31 @@ - [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は*静的型付け*の言語、つまり正しいプログラムはコンパイラによってその動作を示すような*型*を与えられる言語です。逆にいえば、型を与えることができないプログラムは -_誤ったプログラム_ -であり、コンパイラによって拒否されます。動的型付けの言語とは異なり、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 +67,8 @@ iAmANumber = in square 42.0 ``` -次のもっと複雑な例では、 _コンパイラにとって未知_ -の型が存在しているときでさえも、型注釈なしで型の正しさを確かめることができるということが示されています。 +より込み入った次の例では、*コンパイラにとって未知*の型が存在します。 +それでも、型注釈なく型の正しさを確かめられていることを示しています。 ```haskell iterate f 0 x = x @@ -78,20 +80,21 @@ iterate f n x = iterate f (n - 1) (f x) 本書で納得していただきたい(または既にお持ちの信条に寄り添って改めて断言したい)ことは、静的型が単にプログラムの正しさに自信を持つためだけのものではなく、それ自体の正しさによって開発の手助けになるものでもあるということです。JavaScriptではごく単純な抽象化を施すのでも大規模なコードのリファクタリングをすることは難しいですが、型検証器のある表現力豊かな型システムは、リファクタリングさえ楽しく対話的な体験にしてくれます。 -加えて、型システムによって提供されるこの安全網は、より高度な抽象化をも可能にします。 -実際に、関数型プログラミング言語Haskellによって知られるようになった、型駆動の強力な抽象化の形式である『型クラス』をPureScriptは備えています。 +加えて、型システムによって提供されるこの安全網は、より高度な抽象化を可能にします。 +実際に、根本的に型駆動な抽象化の強力な形式である型クラスをPureScriptは提供しています。 +この型クラスとは、関数型プログラミング言語Haskellによって有名になりました。 ## 多言語Webプログラミング -関数型プログラミングは既に多くの成功を収めています。 -枚挙に暇がありませんが、特に成功している応用例を幾つか挙げると、データ解析、構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理などがあります。 +関数型プログラミングは成功を収めてきました。 +特に成功している応用例を挙げると、データ解析、構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理といった具合に、枚挙に暇がありません。 PureScriptのような関数型言語でアプリケーション開発の最初から最後までを実施できるでしょう。 値や関数の型を提供することで既存のJavaScriptコードをインポートし、通常のPureScriptコードからこれらの関数を使用する機能をPureScriptは提供しています。 この手法については本書の後半で見ていくことになります。 しかし、PureScriptの強みの1つは、JavaScriptを対象とする他の言語との相互運用性にあります。 -アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分を記述するのに他の言語を使用するという方法もあります。 +アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分を記述するのに1つ以上の他の言語を使用するという方法もあります。 幾つかの例を示します。 @@ -108,8 +111,9 @@ PureScriptのような関数型言語でアプリケーション開発の最初 第1章では開発環境の構築を一から案内します。 これから使用するツールは、ほとんどの現代のオペレーティングシステムの標準リポジトリで使用できるものです。 -PureScriptコンパイラ自体はバイナリ形式でもダウンロードできますし、最新のHaskellコンパイラが動くシステム上でソースからもビルドできます。 -次の章ではこの手順を説明していきます。 +PureScriptコンパイラ自体はバイナリの配布物としてもダウンロードできますし、最新のGHC +Haskellコンパイラが動く任意のシステム上でソースからのビルドもできます。 +次の章ではこの手順を進めていきます。 本書のこのバージョンのコードは`0.15.*`バージョンのPureScriptコンパイラと互換性があります。 @@ -119,23 +123,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 +158,9 @@ main = log "Hello, World!" $ spago build ``` -通常、これらのコマンドはLinuxやMac -OSの利用者ならそのまま適用できますが、Windowsの利用者はファイル区切り文字を変更する、シェルの組み込み機能をWindowsの相当するものに置き換えるなどの小さな変更を加える必要があるかもしれません。 +通常、これらのコマンドはLinuxやMac OSの利用者に合わせたものになっています。 +そのためWindowsの利用者は小さな変更を加える必要があるかもしれません。 +ファイル区切り文字を変更したり、シェルの組み込み機能をWindowsの相当するものに置き換えるなどです。 PSCi対話式モードプロンプトに入力するコマンドは、行の先頭に山括弧が付けられています。 @@ -161,17 +169,21 @@ 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)は別のかなり深く踏み込んだ学習資料です。 この本の中のある概念が理解しにくかったら、そちらの参考書の対応する節を読むとよいでしょう。 @@ -180,34 +192,37 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 - 非公式の[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サイトです。 - 幾つかの簡単なコードの例があります。 + 幾つかの簡単なコードの例もあります。 -もし例を読んで学ぶ方が好きでしたら、GitHubの -`purescript`組織、`purescript-node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。 +もし例を読んで学ぶ方が好きでしたら、GitHubの`purescript`組織、`purescript-node`組織及び`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..551d350a 100644 --- a/text-ja/chapter10.md +++ b/text-ja/chapter10.md @@ -2,9 +2,9 @@ ## この章の目標 -この章でPureScriptの _外部関数インターフェース_ (foreign function interface; _FFI_) を紹介します。 -これによりPureScriptコードからJavaScriptコードへの呼び出し、及びその逆が可能になります。 -これから扱うのは次のようなものです。 +This chapter will introduce PureScript's _foreign function interface_ (or +_FFI_), which enables communication from PureScript code to JavaScript code +and vice versa. We will cover how to: - 純粋で、作用のある、非同期なJavaScript関数をPureScriptから呼び出す。 - 型付けされていないデータを扱う。 @@ -16,15 +16,19 @@ - 利用者にポップアップ通知で警告する。 - フォームのデータを直列化してブラウザのローカルストレージに保存し、アプリケーションが再起動したときにそれを再読み込みする -さらに一般にはそこまで重用されない幾つかの話題を押さえた補遺もあります。 -ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本の残りを読み進める妨げにならないようにしてください。 +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: - 実行時のPureScriptの値の表現を理解する。 - JavaScriptからPureScriptを呼び出す。 ## プロジェクトの準備 -このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれています。 +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 +source files from those chapters. この章は`argonaut`ライブラリを依存関係として導入しています。 このライブラリはJSONにエンコードしたりJSONをデコードしたりするために使います。 @@ -37,14 +41,18 @@ test`を走らせることによって`test/Main.purs`中の単体試験につ ## 免責事項 -JavaScriptを扱う作業をできる限り簡単にするため、PureScriptは直感的な外部関数インターフェースを提供しています。 -しかし、FFIはPureScriptの*応用的な*機能であることには留意していただきたいと思います。 -FFIを安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現についてよく理解していなければなりません。 -この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝授することを目指します。 +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 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. -PureScriptのFFIはとても柔軟に設計されています。 -実際には、外部関数に最低限の型だけを与えるか、それとも型システムを利用して外部のコードの誤った使い方を防ぐようにするか、開発者が選べるということを意味しています。 -標準ライブラリのコードは、後者の手法を好む傾向にあります。 +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 +of foreign code. Code in the standard libraries tends to favor the latter +approach. 簡単な例としては、JavaScriptの関数で戻り値が `null`にならないことは保証できません。 実のところ、JavaScriptらしさのあるコードはかなり頻繁に `null`を返します。 @@ -68,7 +76,7 @@ node> encodeURIComponent('Hello World') 'Hello%20World' ``` -`null`でない文字列から `null`でない文字列への関数であり、副作用を持っていないので、この関数は型 `String -> String`について適切な実行時表現を持っています。 +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. 次のような外部インポート宣言を使うと、この関数に型を割り当てることができます。 @@ -76,10 +84,12 @@ node> encodeURIComponent('Hello World') {{#include ../exercises/chapter10/test/URI.purs}} ``` -インポートしてくるための外部JavaScriptモジュールを書く必要もあります。 -対応する外部JavaScriptモジュールは、同名で拡張子が`.purs`から`.js`に変わったものです。 -上のPureScriptモジュールが`URI.purs`として保存されているなら、外部JavaScriptモジュールを`URI.js`として保存します。 -`encodeURIComponent`は既に定義されているので、`_encodeURIComponent`としてエクスポートせねばなりません。 +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 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 `_encodeURIComponent`: ```javascript {{#include ../exercises/chapter10/test/URI.js}} @@ -135,9 +145,9 @@ $ spago repl {{#include ../exercises/chapter10/test/Examples.purs:diagonal}} ``` -PureScriptの関数は _カリー化_ されていることを思い出してください。 -`diagonal`は`Number`を取って _関数_ を返す関数です。 -そして返された関数は`Number`を取って`Number`を返します。 +Recall that functions in PureScript are _curried_. `diagonal` is a function +that takes a `Number` and returns a _function_ that takes a `Number` and +returns a `Number`. ```js {{#include ../exercises/chapter10/test/Examples.js:diagonal}} @@ -192,7 +202,8 @@ Type -> Type -> Type -> Type `Fn2 a b c`は、型 `a`と `b`の2つの引数、返り値の型 `c`をもつカリー化されていない関数の型を表現しています。 これを使って外部モジュールから`diagonalUncurried`をインポートしました。 -カリー化されていない関数と引数を取る`runFn2`で呼び出すことができます。 +We can then call it with `runFn2`, which takes the uncurried function and +then the arguments. ```text $ spago repl @@ -207,7 +218,11 @@ $ spago repl ## カリー化されていない関数についての補足 -PureScriptのカリー化された関数にはもちろん利点があります。部分的に関数を適用でき、関数型に型クラスインスタンスを与えられます。しかし効率上の代償も付いてくるのです。効率性が決定的に重要なコードでは多変数を受け付けるカリー化されていないJavaScript関数を定義する必要が時々あります。 +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 +code, it is sometimes necessary to define uncurried JavaScript functions +which accept multiple arguments. PureScriptでカリー化されていない関数を作ることもできます。 2引数の関数については`mkFn2`関数が使えます。 @@ -239,8 +254,8 @@ var uncurriedSum = uncurriedAdd(3, 10); {{#include ../exercises/chapter10/test/Examples.purs:curried_add}} ``` -そして生成結果のコードが以下です。 -入れ子の関数のため比較的簡潔ではありません。 +And the resulting generated code, which is less compact due to the nested +functions: ```javascript var curriedAdd = function (n) { @@ -254,13 +269,19 @@ var curriedSum = curriedAdd(3)(10); ## 現代的なJavaScriptの構文についての補足 -前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しすればIE11)と互換性がありません。 -執筆時点でWebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことができないと推計](https://caniuse.com/#feat=arrow-functions)されています。 +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 browser. -ほとんどの利用者にとって互換性があるようにするため、PureScriptコンパイラによって生成されるJavaScriptコードは矢印関数を使っていません。 -また、同じ理由で**公開するライブラリでも矢印関数を避ける**ことが推奨されます。 +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. -それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程でES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/babel#intro)などのツールを含めるべきです。 +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. ES6の矢印関数がより読みやすく感じたら[Lebab](https://github.com/lebab/lebab)のようなツールを使ってコンパイラの`output`ディレクトリにJavaScriptのコードを変換できます。 @@ -299,7 +320,10 @@ Record | Object `String`と`Number`という原始型の例は既に見てきました。 ここから`Array`や`Record`(JavaScriptでは`Object`)といった構造的な型を眺めていきます。 -`Array`の受け渡しを実演するために、以下に`Int`の`Array`を取って別の配列として累計の和を返すJavaScriptの関数の呼び出し方を示します。前にありましたが、JavaScriptは`Int`のための分離した型を持たないため、PureScriptでの`Int`と`Number`はJavaScriptでの`Number`に翻訳されます。 +To demonstrate passing `Array`s, here's how to call a JavaScript function +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. ```hs foreign import cumulativeSums :: Array Int -> Array Int @@ -325,8 +349,10 @@ $ spago repl [1,3,6] ``` -`Record`の受け渡しを実演するために、以下に2つの`Complex`な数をレコードとして取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。 -PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意してください。 +To demonstrate passing `Records`, here's how to call a JavaScript function +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: ```hs type Complex = { @@ -354,7 +380,11 @@ $ spago repl { imag: 6.0, real: 4.0 } ``` -なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要があります。PureScriptはJavaScriptのコードに型検査を適用できないからです。この型安全性の配慮について後のJSONの節でより詳しく記述していきます。型の不整合から身を守る手法についても押さえます。 +Note that the above techniques require trusting that JavaScript will return +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. ## 演習 @@ -427,28 +457,32 @@ maybeHead arr = maybeHeadImpl Just Nothing arr forall a. (forall x. x -> Maybe x) -> (forall x. Maybe x) -> Array a -> Maybe a ``` -以下ではないことに注意です。 +And not: ```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`の場所での招かれざる入力に侵されやすくなります。例えばより脆弱な場合では以下のようにして呼ぶことができます。 +While both forms work, the latter is more vulnerable to unwanted inputs in +place of `Just` and `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`を返します。 + +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). より安全な型シグネチャでは、入力の配列に基づいて`a`が`Int`に決定されたとしても、`forall x`に絡むシグネチャに合致する妥当な関数を提供する必要があります。`(forall x. Maybe x)`の *唯一* の選択肢は`Nothing`ですが、それは`Just`値が`x`の型を前提にしてしまうと、もはや全ての`x`については妥当でなくなってしまうからです。`(forall x. x -> Maybe x)`の唯一の選択肢は`Just`(望まれている引数)と`(\_ -> Nothing)`であり、後者は唯一残っている脆弱性になるのです。 ## 外部型の定義 -`Maybe a`を返す代わりに実は`arr[0]`を返したいのだとしましょう。 -型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する型がほしいです。 -この型を`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`. _外部インポート宣言_ を使うと、*外部型* (foreign type) を定義できます。構文は外部関数を定義するのと似ています。 @@ -462,7 +496,7 @@ foreign import data Undefined :: Type -> Type この場合は`Undefined`の種が `Type -> Type`であると宣言しています。 言い換えれば`Undefined`は型構築子です。 -これで元の`head`の定義を単に再利用できます。 +We can now reuse our original definition for `head`: ```javascript export const undefinedHead = arr => @@ -475,12 +509,12 @@ PureScriptモジュールには以下を追加します。 foreign import undefinedHead :: forall a. Array a -> Undefined a ``` -`undefinedHead`関数の本体は`undefined`かもしれない`arr[0]`を返します。 -そしてこの型シグネチャはその事実を正しく反映しています。 +The body of the `undefinedHead` function returns `arr[0]`, which may be +`undefined`, and the type signature correctly reflects that fact. -この関数はその型の適切な実行時表現を持っていますが、型 `Undefined a`の値を使用する方法がないので、全く役に立ちません。 -いや、言い過ぎました。 -別のFFIでこの型を使えますからね。 +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! 値が未定義かどうかを教えてくれる関数を書くことができます。 @@ -502,9 +536,11 @@ isEmpty :: forall a. Array a -> Boolean isEmpty = isUndefined <<< undefinedHead ``` -このように、定義したこの外部関数はとても簡単です。 -つまりPureScriptの型検査器を使うことによる利益が最大限得られるのです。 -一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理はPureScriptコードへ移動しておくことをお勧めします。 +Here, the foreign function we defined is very simple, which means we can +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. ## 例外 @@ -559,11 +595,13 @@ export const unsafeHead = arr => { ## 型クラスメンバー関数を使う -つい先程までFFI越しに`Maybe`の構築子を渡す手引きをしましたが、今回はJavaScriptを呼び出すPureScriptを書く別の場合です。 -JavaScriptの呼び出しでも続けざまにPureScriptの関数を呼び出します。 -ここでは型クラスのメンバー関数を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. -型`x`に合う適切な`show`のインスタンスを期待する外部JavaScript関数を書くことから始めます。 +We start with writing a foreign JavaScript function that expects the +appropriate instance of `show` to match the type of `x`. ```js export const boldImpl = show => x => @@ -576,14 +614,14 @@ export const boldImpl = show => x => foreign import boldImpl :: forall a. (a -> String) -> a -> String ``` -そして`show`の正しいインスタンスを渡す梱包関数も書きます。 +And a wrapper function that passes the correct instance of `show`: ```hs bold :: forall a. Show a => a -> String bold x = boldImpl show x ``` -代わりにポイントフリー形式だとこうです。 +Alternatively, in point-free form: ```hs bold :: forall a. Show a => a -> String @@ -650,7 +688,8 @@ yell :: forall a. Show a => a -> Effect Unit yell = yellImpl show ``` -REPLで試すと文字列が(引用符で囲まれず)直接コンソールに印字され`unit`値が返ることがわかります。 +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. ```text $ spago repl @@ -666,9 +705,11 @@ unit これらは既に見た`Data.Function.Uncurried`の梱包`Fn`に似ています。 これらの梱包があればカリー化されていない作用のある関数をPureScriptで呼び出すことができます。 -一般的にこれらを使うのは、こうしたAPIをカリー化された関数に包むのではなく、既存のJavaScriptライブラリのAPIを直接呼び出したいときぐらいです。 -したがってカリー化していない`yell`の例を見せてもあまり意味がありません。 -というのもJavaScriptがPureScriptの型クラスのメンバーに依っているからで、更にそれは既存のJavaScriptの生態系にそのメンバーが見付からないためです。 +You'd generally only use these if you want to call existing JavaScript +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 wouldn't find that in the existing JavaScript ecosystem. 翻って以前の`diagonal`の例を変更し、結果を返すことに加えてログ出力を含めるとこうなります。 @@ -743,8 +784,9 @@ unit done waiting ``` -REPLでの非同期ログ出力はブロック全体が実行を終了するまで印字を待機する点に注意しましょう。 -このコードを`spago test`で走らせた場合、印字の _合間に_ 僅かな遅延があり、より予測に近い挙動をします。 +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. 他にプロミスから値を返す例を見てみましょう。 この関数は`async`と`await`を使って書かれていますが、これはプロミスの糖衣構文に過ぎません。 @@ -791,10 +833,10 @@ unit ## JSON -アプリケーションでJSONを使うことには多くの理由があります。 -例えばWebのAPIと疎通するよくある手段であるためです。 -この節では他の用例についてもお話ししましょう。 -構造的なデータをFFI越しに渡すことで型安全性を向上させる手法から始めます。 +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 +passing structural data over the FFI. 少し前のFFI関数`cumulativeSums`と`addComplex`を再訪し、それぞれに1つバグを混入させてみましょう。 @@ -818,7 +860,8 @@ export const addComplexBroken = a => b => { }; ``` -実際は返る型が正しくないのですが、元々の型シグネチャを使うことができ、依然としてコードはコンパイルされます。 +We can use the original type signatures, and the code will still compile, +despite the incorrect return types. ```hs foreign import cumulativeSumsBroken :: Array Int -> Array Int @@ -983,20 +1026,13 @@ Map String Int JsonDecodeError (Set v)`です。 なお`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。 コンパイラが導いてくれます。 -1. (普通)少し前の`quadraticRoots`を書き換えて`quadraticRootSet`としてください。 - この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返します。 -1. (難しい)少し前の`quadraticRoots`を書き換えて`quadraticRootsSafe`としてください。 - この関数はJSONを使って`Complex`の根の`Pair`をFFI越しに渡します。 - JavaScriptでは`Pair`構築子を使わないでください。 - その代わり、デコーダーに互換性のある形式で対を返すだけにしてください。 - *手掛かり*:`DecodeJson`インタンスを`Pair`用に書く必要があるでしょう。 - 独自のデコードインスタンスを書く上での説明については[argonautのドキュメント](https://github.com/purescript-contrib/purescript-argonaut-codecs/tree/main/docs#writing-new-instances)をあたってください。 - [decodeJsonTuple](https://github.com/purescript-contrib/purescript-argonaut-codecs/blob/master/src/Data/Argonaut/Decode/Class.purs)インスタンスも参考になるかもしれません。 - 「孤立インスタンス」を作ることを避けるために、`Pair`に`newtype`の梱包が必要になる点に注意してください。 -1. (普通)2次元配列を含むJSON文字列を構文解析してデコードする`parseAndDecodeArray2D :: String -> Either String (Array (Array Int))`関数を書いてください。 - 例えば`"[[1, 2, 3], [4, 5], [6]]"`です。 - *手掛かり*:デコードの前に`jsonParser`を使って`String`を`Json`に変換する必要があるでしょう。 -1. (普通)以下のデータ型は値が葉にある二分木を表現します。 +1. (Medium) Rewrite the earlier `quadraticRoots` function as + `quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON + (instead of as a `Pair`). +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. +_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". +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. +1. (Medium) The following data type represents a binary tree with values at the leaves: ```haskell data Tree a @@ -1021,8 +1057,9 @@ Map String Int ## 住所録 -この節では新しく獲得したFFIとJSONの知識を応用して、第8章の住所録の例を構築していきたいと思います。 -以下の機能を加えていきます。 +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: - 保存ボタンをフォームの一番下に配置し、クリックしたときにフォームの状態をJSONに直列化してローカルストレージに保存します。 - ページの再読み込み時にローカルストレージからJSON文書を自動的に取得します。 @@ -1088,9 +1125,10 @@ validateAndSave = do Data.Argonaut.Encode.Class.EncodeJson PhoneType ``` -これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンスを必要としているからです。 -単純に汎用のエンコードインスタンスとデコードインスタンスを導出すれば完了です。 -この仕組みについて、より詳しくはargonautのドキュメントで見られます。 +This is because `PhoneType` in the `Person` record needs an `EncodeJson` +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: ```hs {{#include ../exercises/chapter10/src/Data/AddressBook.purs:import}} @@ -1108,10 +1146,12 @@ validateAndSave = do item <- getItem "person" ``` -そうしてローカルストレージから、文字列から`Person`レコードへの変換を扱う補助関数をつくります。 -なおこのストレージ中の文字列は`null`かもしれないので、うまく`String`としてデコードされるまでは外部の`Json`として表現します。 -道中には他にも多くの変換工程があり、それぞれで`Either`の値を返します。 -そのためこれらを`do`ブロックの中に纏めるのは理に適っています。 +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. ```hs processItem :: Json -> Either String Person @@ -1121,9 +1161,9 @@ processItem item = do decodeJson j ``` -そうしてこの結果が成功しているかどうか調べます。 -もし失敗していればエラーをログ出力し、既定の`examplePerson`を使います。 -そうでなければローカルストレージから取得した人物を使います。 +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. ```hs initialPerson <- case processItem item of @@ -1159,17 +1199,17 @@ processItem item = do lmap ("Cannot decode Person: " <> _) $ decodeJson j ``` -最初のエラーのみがこのアプリの通常の操作内で起こります。 -他のエラーはWebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。 -どのようにJSON文字列を変更したかが、どのエラーの引き金になるかを決定します。 -それぞれのエラーを引き起こせるかどうかやってみてください。 +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. -これでローカルストレージについては押さえました。 -次に`alert`アクションを実装していきます。 -このアクションは`Effect.Console`モジュールの`log`アクションによく似ています。 -唯一の相違点は`alert`アクションが`window.alert`メソッドを使うことで、対して`log`アクションは`console.log`メソッドを使っています。 -そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができます。 -例えばWebブラウザなどです。 +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. ```hs foreign import alert :: String -> Effect Unit @@ -1205,14 +1245,19 @@ alert $ "Error: " <> err <> ". Loading examplePerson" ## まとめ -この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。また、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。 +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 +using the FFI: - 外部関数が正しい表現を持っていることを確かめる重要性を見てきました。 -- 外部型や`Json`データ型を使用することによって、null値やJavaScriptの他の型のデータのような特殊な場合に対処する方法を学びました。 +- 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. - 安全にJSONデータを直列化・直列化復元する方法を見ました。 -より多くの例については、Githubの `purescript`組織、`purescript-contrib`組織および -`purescript-node`組織が、FFIを使用するライブラリの例を多数提供しています。残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾つか見ていきます。 +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. ## 補遺 @@ -1230,7 +1275,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 +1289,10 @@ import Test from 'Test.js'; Test.gcd(15)(20); ``` -ここでは、コードがPureScriptモジュールをESモジュールにコンパイルする `spago -build`でコンパイルされていると仮定しています。そのため、 `import`を使って `Test`モジュールをインポートした後、 -`Test`オブジェクトの `gcd`関数を参照できました。 +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`. `spago bundle-app`や`spago bundle-module`コマンドを使って生成されたJavaScriptを単一のファイルにまとめることもできます。 @@ -1254,7 +1300,10 @@ bundle-module`コマンドを使って生成されたJavaScriptを単一のフ ### 名前の生成を理解する -PureScriptはコード生成時にできるだけ名前を保存することを目的としています。具体的には、少なくともトップレベルで宣言される名前については、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存されます。 +PureScript aims to preserve names during code generation as much as +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. 識別子としてJavaScriptのキーワードを使う場合は、名前は2重のドル記号でエスケープされます。 例えば次のPureScriptコードを考えてみます。 @@ -1263,7 +1312,7 @@ PureScriptはコード生成時にできるだけ名前を保存することを null = [] ``` -これは以下のJavaScriptを生成します。 +Generates the following JavaScript: ```javascript var $$null = []; @@ -1276,21 +1325,24 @@ var $$null = []; example' = 100 ``` -これは以下のJavaScriptを生成します。 +Generates the following JavaScript: ```javascript var example$prime = 100; ``` -コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めします。 -ユーザ定義演算子がPureScriptコードでの使用のために提供される場合でも、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。 +Where compiled PureScript code is intended to be called from JavaScript, it +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. ### 実行時のデータ表現 -型はプログラムがある意味で「正しい」ことをコンパイル時に判断できるようにします。 -つまり、その点については壊れることがありません。 -しかし、これは何を意味するのでしょうか。 -PureScriptでは式の型は実行時の表現と互換性がなければならないことを意味します。 +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 +mean? In PureScript, it means that the type of an expression should be +compatible with its representation at runtime. そのため、PureScriptとJavaScriptコードを一緒に効率的に使用できるように、実行時のデータ表現について理解することが重要です。 これはつまり、与えられた任意のPureScriptの式について、その値が実行時にどのように評価されるかという挙動を理解できるべきだということです。 @@ -1303,38 +1355,43 @@ PureScriptでは式の型は実行時の表現と互換性がなければなら つまり、型 `Boolean`の式は `true`もしくは `false`のどちらか一方の(JavaScriptの)値へと評価されます。 特に`null`や `undefined`に評価される型`Boolean`なPureScriptの式はありません。 -`Int`や`Number`や`String`の型の式についても同様のことが成り立ちます。 -`Int`や`Number`型の式は `null`でないJavaScriptの数へと評価されますし、 `String`型の式は -`null`でないJavaScriptの文字列へと評価されます。 -`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式は実行時に整数に評価されます。 +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`. -`Unit`についてはどうでしょうか。 -`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何で表現されるかは重要ではありません。 -古いコードは`{}`を使って表現する傾向がありました。 -しかし比較的新しいコードでは`undefined`を使う傾向にあります。 -なので、`Unit`を表現するのに使うものは本当に何でも問題にならないのですが、`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を返します)。 +What about `Unit`? Well, since `Unit` has only one inhabitant (`unit`) and +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`). もっと複雑な型についてはどうでしょうか。 -既に見てきたように、PureScriptの関数は引数が1つのJavaScriptの関数に対応しています。 -厳密に言えばこうなります。 -任意の型`a`と`b`について、式`f`の型が`a -> b`で、式`x`が型`a`についての適切な実行時表現の値へと評価されるとします。 -このとき`f`はJavaScriptの関数へと評価され、`x`を評価した結果に`f`を適用すると型`b`の適切な実行時表現を持ちます。 -簡単な例としては、 `String -> String`型の式は、 `null`でないJavaScript文字列から `null`でないJavaScript文字列への関数へと評価されます。 +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. -ご想像の通り、PureScriptの配列はJavaScriptの配列に対応しています。 -しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っていることは覚えておいてください。 -具体的には、もしPureScriptの式 `e`が何らかの型 `a`について型 `Array a`を持つなら、 -`e`は全ての要素が(`null`でない)型 `a`の適切な実行時表現を持ったJavaScript配列へと評価されます。 +As you might expect, PureScript's arrays correspond to JavaScript +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 +type `a`. -PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てきました。 -ちょうど関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールドのデータの実行時の表現についても推論できます。 -もちろん、レコードのそれぞれのフィールドは、同じ型である必要はありません。 +We've already seen that PureScript's records evaluate to JavaScript +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. ### ADTの表現 -PureScriptコンパイラは、代数的データ型の全ての構築子についてそれぞれを関数として定義し、新たなJavaScriptオブジェクト型を作成します。 -これらの構築子は雛形に基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。 +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 that create new JavaScript objects +based on those prototypes. 例えば次のような単純なADTを考えてみましょう。 @@ -1368,16 +1425,16 @@ PureScriptコンパイラは補助関数も生成します。 `value`プロパティを生成します。 1つ以上の引数を持つ構築子では、コンパイラは適切な表現を持つ引数を取り適切な構築子を適用する `create`関数を生成します。 -2引数以上の構築子についてはどうでしょうか。 -その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成します。 -ここでは補助関数は2引数のカリー化された関数なのです。 -例えば次のような代数的データ型を考えます。 +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 a curried function of +two arguments. For example, this algebraic data type: ```haskell data Two a b = Two a b ``` -このコードからは、次のようなJavaScriptコードが生成されます。 +Generates this JavaScript code: ```javascript function Two(value0, value1) { @@ -1392,20 +1449,23 @@ Two.create = function (value0) { }; ``` -ここで、オブジェクト型 `Two`の値はキーワード`new`または `Two.create`関数を使用すると作成できます。 +Here, values of the object type `Two` can be created using the `new` keyword +or by using the `Two.create` function. -newtypeの場合はまた少し異なります。 -newtypeは単一の引数を取る単一の構築子を持つよう制限された代数的データ型であることを思い出してください。 -この場合、実際のnewtypeの実行時表現は、その引数の型と同じになります。 +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 +the same as its argument type. -例えば、電話番号を表す次のようなnewtypeを考えます。 +For example, this newtype represents telephone numbers is represented as a +JavaScript string at runtime: ```haskell newtype PhoneNumber = PhoneNumber String ``` -これは実行時にJavaScriptの文字列として表されます。 -newtypeは更なる型安全性のための層を提供しますが、実行時の関数呼び出しのオーバーヘッドがないので、ライブラリを設計するのに役に立ちます。 +This is useful for designing libraries since newtypes provide an additional +layer of type safety without the runtime overhead of another function call. ### 量化された型の表現 @@ -1434,11 +1494,12 @@ identity a = a 量化された型 `forall a. t`の実行時表現はどうなっているのでしょうか。さて、この型の実行時表現を持つ任意の式は、型 `a`をどのように選んでも型 `t`の適切な実行時表現を持っていなければなりません。上の例では、型 `forall a. a -> a`の関数は、 `String -> String`、 `Number -> Number`、 `Array Boolean -> Array Boolean`などといった型について、適切な実行時表現を持っていなければなりません。 これらは、文字列から文字列、数から数の関数でなくてはなりません。 -しかし、それだけでは充分ではありません。 -量化された型の実行時表現は、これよりも更に厳しくなります。 -任意の式が*パラメトリック多相的*でなければなりません。 -つまり、その実装において、引数の型についてのどんな情報も使うことができないのです。 -この追加の条件は、考えられる多相型のうち、以下のJavaScriptの関数のような問題のある実装を防止します。 +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 +argument in its implementation. This additional condition prevents +problematic implementations such as the following JavaScript function from +inhabiting a polymorphic type: ```javascript function invalid(a) { @@ -1450,21 +1511,26 @@ function invalid(a) { } ``` -確かにこの関数は文字列から文字列、数から数へというような関数ではありますが、追加条件を満たしていません。 -引数の実行時の型を調べており、したがって、この関数は型 `forall a. a -> a`の正しい実装だとはいえないのです。 +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`. -関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけであり、したがって `id`はたしかに `forall a. a -> a`の唯一の実装なのです。 +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`. -*パラメトリック多相*と*パラメトリック性*についての詳しい議論は本書の範囲を超えています。 -ただ、PureScriptの型は実行時に*消去*されており、PureScriptの多相関数は(FFIを使わない限り)引数の実行時表現を検査*できない*ため、この多相的なデータの表現が適切になっているという点にはご留意ください。 +A full discussion of _parametric polymorphism_ and _parametricity_ is beyond +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), so this +representation of polymorphic data is appropriate. ### 制約のある型の表現 -型クラス制約を持つ関数は、実行時に面白い表現を持っています。 -関数の挙動はコンパイラによって選ばれた型クラスのインスタンスに依存する可能性があるため、関数には*型クラス辞書*と呼ばれる追加の引数が与えられます。 -この辞書には選ばれたインスタンスから提供される型クラスの関数の実装が含まれます。 +Functions with a type class constraint have an interesting representation at +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. -例えば、 `Show`型クラスを使った制約のある型を持つ、次のような単純なPureScript関数について考えます。 +For example, here is a simple PureScript function with a constrained type +that uses the `Show` type class: ```haskell shout :: forall a. Show a => a -> String @@ -1508,10 +1574,11 @@ shout(showNumber)(42); ### 副作用の表現 -`Effect`モナドも外部型として定義されています。 -その実行時表現はとても簡単です。 -型 `Effect a`の式は**引数なしの**JavaScript関数へと評価されます。 -この関数はあらゆる副作用を実行し型 `a`の適切な実行時表現で値を返します。 +The `Effect` monad is also defined as a foreign type. Its runtime +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`. `Effect`型構築子の定義は、 `Effect`モジュールで次のように与えられています。 @@ -1531,9 +1598,10 @@ foreign import random :: Effect Number export const random = Math.random; ``` -`random`関数は実行時には引数なしの関数として表現されていることに注目してください。 -この関数は乱数生成という副作用を実行して返しますが、返り値は `Number`型の実行時表現と一致します。 -`Number`型は`null`でないJavaScriptの数です。 +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, +returns it, and the return value matches the runtime representation of the +`Number` type: it is a non-null JavaScript number. もう少し興味深い例として、`console`パッケージ中の`Effect.Console`モジュールで定義された `log`関数を考えてみましょう。 `log`関数は次の型を持っています。 @@ -1564,5 +1632,5 @@ import { main } from 'Main' main(); ``` -`spago bundle-app --to`または `spago run`を使用するときは、`Main`モジュールが定義されている場合は常に、この -`main`の呼び出しを自動的に生成できます。 +When using `spago bundle-app --to` or `spago run`, this call to `main` is +generated automatically whenever the `Main` module is defined. diff --git a/text-ja/chapter11.md b/text-ja/chapter11.md deleted file mode 100644 index 1eaa8b27..00000000 --- a/text-ja/chapter11.md +++ /dev/null @@ -1,1166 +0,0 @@ -# モナドな冒険 - -## この章の目標 - -この章の目標は*モナド変換子*について学ぶことです。 -モナド変換子は異なるモナドから提供された副作用を合成する方法を提供します。 -NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームを題材として扱います。 -ゲームの様々な副作用(ロギング、状態、及び設定)が全てモナド変換子スタックによって提供されます。 - -## プロジェクトの準備 - -このモジュールのプロジェクトでは以下の新しい依存関係が導入されます。 - -- `ordered-collections` は不変のマップと集合のためのデータ型を提供します -- `transformers` は標準的なモナド変換子の実装を提供します -- `node-readline`はNodeJSが提供する[`readline`](http://nodejs.org/api/readline.html)インターフェイスへのFFIバインディングを提供します -- `optparse` はコマンドライン引数を処理するアプリカティブ構文解析器を提供します - -## ゲームの遊びかた - -プロジェクトを走らせるには`spago run`を使います。 - -既定では使い方が表示されます。 - -```text -Monadic Adventures! A game to learn monad transformers - -Usage: run.js (-p|--player ) [-d|--debug] - Play the game as - -Available options: - -p,--player - The player's name - -d,--debug Use debug mode - -h,--help Show this help text -``` - -コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-a`オプション付きで`spago run`を呼び出すか、`spago bundle-app`とすればよいです。 -2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。 -例えば`-p`オプションを使ってプレイヤー名を与えるには次のようにします。 - -```text -$ spago run -a "-p Phil" -> -``` - -```text -$ spago bundle-app -$ node index.js -p Phil -> -``` - -プロンプトからは、 `look`、 `inventory`、 `take`、 `use`、 `north`、`south`、 `east`、 -`west`などのコマンドを入力できます。 -`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合に、ゲームの状態を出力するのに使えます。 - -ゲームは2次元の碁盤の目の上が舞台で、コマンド `north`、 `south`、`east`、 -`west`を発行することによってプレイヤーが移動します。 -ゲームにはアイテムの集まりがあり、プレイヤーの所持アイテム一覧を表したり、ゲーム盤上のその位置にあるアイテムの一覧を表すのに使われます。 -`take`コマンドを使うと、プレイヤーの位置にあるアイテムを拾い上げることができます。 - -参考までに、このゲームのひと通りの流れは次のようになります。 - -```text -$ spago run -a "-p Phil" - -> look -You are at (0, 0) -You are in a dark forest. You see a path to the north. -You can see the Matches. - -> take Matches -You now have the Matches - -> north -> look -You are at (0, 1) -You are in a clearing. -You can see the Candle. - -> take Candle -You now have the Candle - -> inventory -You have the Candle. -You have the Matches. - -> use Matches -You light the candle. -Congratulations, Phil! -You win! -``` - -このゲームはとても単純ですが、この章の目的は -`transformers`パッケージを使用してこのようなゲームを素早く開発できるようにするライブラリを構築することです。 - -## Stateモナド - -`transformers`パッケージで提供されている幾つかのモナドを眺めることから始めましょう。 - -最初の例は`State`モナドです。 -これは純粋なコードで*変更可能状態*をモデル化する手段を提供します。 -既に`Effect`モナドによって提供される変更可能状態の手法について見てきました。 -`State`はその代替を提供します。 - -`State`型構築子は、状態の型 `s`、及び返り値の型 `a`という2種類の引数を取ります。 -「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのインスタンスが任意の型`s`についての `State -s`型構築子に対して提供されています。 - -`Control.Monad.State`モジュールは以下のAPIを提供しています。 - -```haskell -get :: forall s. State s s -gets :: forall s. (s -> a) -> State s a -put :: forall s. s -> State s Unit -modify :: forall s. (s -> s) -> State s s -modify_ :: forall s. (s -> s) -> State s Unit -``` - -なおここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式で表されています。 -実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきます。 -ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないでください。 - -例を見てみましょう。 -`State`モナドの使いかたの1つとしては、整数の配列中の値を現在の状態に加えるものが考えられます。 -状態の型`s`として`Int`を選択し、配列の走査に `traverse_`を使って、配列の要素それぞれについて -`modify`を呼び出すと、これを実現できます。 - -```haskell -import Data.Foldable (traverse_) -import Control.Monad.State -import Control.Monad.State.Class - -sumArray :: Array Int -> State Int Unit -sumArray = traverse_ \n -> modify \sum -> sum + n -``` - -`Control.Monad.State`モジュールは、`State`モナドで計算するための次の3つの関数を提供します。 - -```haskell -evalState :: forall s a. State s a -> s -> a -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 -s`型の値として表現された両方を返します。 - -先ほどの `sumArray`関数が与えられているとき、PSCiで `execState`を使うと次のように複数の配列内の数字を合計できます。 - -```text -> :paste -… execState (do -… sumArray [1, 2, 3] -… sumArray [4, 5] -… sumArray [6]) 0 -… ^D -21 -``` - -## 演習 - - 1. (簡単)上の例で、`execState`を`runState`や`evalState`で置き換えると結果はどうなるでしょうか。 -1. (普通)括弧からなる文字列について、次の何れかであれば*平衡している*とします。 - 1つは0個以上のより短い平衡した文字列を連結したもので、もう1つはより短い平衡した文字列を一対の括弧で囲んだものです。 - - `State`モナドと `traverse_`関数を使用して、次のような関数を書いてください。 - - ```haskell - testParens :: String -> Boolean - ``` - - これは `String`が括弧の対応が正しく付けられているかどうかを調べる関数です。 - 調べるにはまだ閉じられていない開括弧の数を把握しておきます。 - この関数は次のように動作しなくてはなりません。 - - ```text - > testParens "" - true - - > testParens "(()(())())" - true - - > testParens ")" - false - - > testParens "(()()" - false - ``` - - *手掛かり*:入力の文字列を文字の配列に変換するのに、`Data.String.CodeUnits`モジュールの `toCharArray`関数を使うと良いでしょう。 - -## Readerモナド - -`transformers`パッケージでは `Reader`というモナドも提供されています。 -このモナドは大域的な設定を読み取る機能を提供します。 -`State`モナドが1つの可変状態を読み書きする機能を提供するのに対し、 `Reader`モナドは1つのデータの読み取り機能だけを提供します。 - -`Reader`型構築子は、設定の型を表す型 `r`、及び戻り値の型 `a`の2つの型引数を取ります。 - -`Control.Monad.Reader`モジュールは以下のAPIを提供します。 - -```haskell -ask :: forall r. Reader r r -local :: forall r a. (r -> r) -> Reader r a -> Reader r a -``` - -`ask`アクションは現在の設定を読み取るために使い、 `local`アクションは変更された設定で計算するために使います。 - -例えば、権限で制御するアプリケーションを開発しており、現在の利用者の権限オブジェクトを保持するのに `Reader`モナドを使いたいとしましょう。 -型 `r`を次のようなAPIを備えた型 `Permission`として選択できます。 - -```haskell -hasPermission :: String -> Permissions -> Boolean -addPermission :: String -> Permissions -> Permissions -``` - -利用者が特定の権限を持っているかどうかを確認したいときは、 `ask`を使って現在の権限オブジェクトを取得すればいつでも調べることができます。 -例えば管理者だけが新しい利用者の作成を許可されているとしましょう。 - -```haskell -createUser :: Reader Permissions (Maybe User) -createUser = do - permissions <- ask - if hasPermission "admin" permissions - then map Just newUser - else pure Nothing -``` - -`local`アクションを使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユーザーの権限を昇格させることもできます。 - -```haskell -runAsAdmin :: forall a. Reader Permissions a -> Reader Permissions a -runAsAdmin = local (addPermission "admin") -``` - -こうすると、利用者が `admin`権限を持っていなかった場合であっても新しい利用者を作成できるような関数を書くことができます。 - -```haskell -createUserAsAdmin :: Reader Permissions (Maybe User) -createUserAsAdmin = runAsAdmin createUser -``` - -`Reader`モナドを計算するには、大域的な設定を与える`runReader`関数を使います。 - -```haskell -runReader :: forall r a. Reader r a -> r -> a -``` - -## 演習 - -以下の演習では、 `Reader`モナドを使って、字下げのついた文書を出力するための小さなライブラリを作っていきます。 -「大域的な設定」は、現在の字下げの深さを示す数になります。 - -```haskell -type Level = Int - -type Doc = Reader Level String -``` - - 1. (簡単)現在の字下げの深さで文字列を出力する関数 `line`を書いてください。 - 関数は以下の型を持つ必要があります。 - - ```haskell - line :: String -> Doc - ``` - - *手掛かり*:現在の字下げの深さを読み取るためには `ask`関数を使用します。 - `Data.Monoid`の`power`関数も役に立つかもしれません。 -1. (普通)`local`関数を使用して次の関数を書いてください。 - - ```haskell - indent :: Doc -> Doc - ``` - - この関数はコードブロックの字下げを深くします。 -1. (普通)`Data.Traversable`で定義された `sequence`関数を使用して、次の関数を書いてください。 - - ```haskell - cat :: Array Doc -> Doc - ``` - - この関数は文書の集まりを改行で区切って連結します。 -1. (普通)`runReader`関数を使用して次の関数を書いてください。 - - ```haskell - render :: Doc -> String - ``` - - この関数は文書を文字列として出力します。 - - これで、このライブラリを次のように使うと、簡単な文書を書くことができるでしょう。 - - ```haskell - render $ cat - [ line "Here is some indented text:" - , indent $ cat - [ line "I am indented" - , line "So am I" - , indent $ line "I am even more indented" - ] - ] - ``` - -## Writerモナド - -`Writer`モナドは、計算の返り値に加えて、もう1つの値を累積していく機能を提供します。 - -よくある使い方としては型 `String`もしくは `Array String`でログを累積していくというものなどがありますが、 -`Writer`モナドはこれよりもっと一般的なものです。 -累積するのに任意のモノイドの値を使うことができ、`Additive Int`モノイドを使って、合計を追跡し続けるのに使ったり、 `Disj -Boolean`モノイドを使って途中の `Boolean`値の何れかが真であるかどうかを追跡するのに使うことができます。 - -`Writer`型の構築子は、 `Monoid`型クラスのインスタンスである型 `w`、および返り値の型 `a`という2つの型引数を取ります。 - -`Writer`のAPIで重要なのは `tell`関数です。 - -```haskell -tell :: forall w a. Monoid w => w -> Writer w Unit -``` - -`tell`アクションは、与えられた値を現在の累積結果に付け加えます。 - -例として、 `Array String`モノイドを使用して、既存の関数にログ機能を追加してみましょう。 _最大公約数_ 関数の以前の実装を考えてみます。 - -```haskell -gcd :: Int -> Int -> Int -gcd n 0 = n -gcd 0 m = m -gcd n m = if n > m - then gcd (n - m) m - else gcd n (m - n) -``` - -`Writer (Array String) Int`へと返り値の型を変更することで、この関数にログ機能を追加できます。 - -```haskell -import Control.Monad.Writer -import Control.Monad.Writer.Class - -gcdLog :: Int -> Int -> Writer (Array String) Int -``` - -各手順での2つの入力を記録するためには、少し関数を変更する必要があります。 - -```haskell - gcdLog n 0 = pure n - gcdLog 0 m = pure m - gcdLog n m = do - tell ["gcdLog " <> show n <> " " <> show m] - if n > m - then gcdLog (n - m) m - else gcdLog n (m - n) -``` - -`Writer`モナドを計算するには、`execWriter`関数または`runWriter`関数の何れかを使います。 - -```haskell -execWriter :: forall w a. Writer w a -> w -runWriter :: forall w a. Writer w a -> Tuple a w -``` - -ちょうど `State`モナドの場合と同じように、 `execWriter`が累積されたログだけを返すのに対して、 -`runWriter`は累積されたログと結果の両方を返します。 - -PSCiで改変した関数を試してみましょう。 - -```text -> import Control.Monad.Writer -> import Control.Monad.Writer.Class - -> runWriter (gcdLog 21 15) -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`で始まるコラッツ数列は次のようになります。 - - ```text - 10, 5, 16, 8, 4, 2, 1, ... - ``` - - コラッツ関数の有限回の適用を繰り返すと、コラッツ数列は必ず最終的に `1`になるということが予想されています。 - - 数列が `1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する再帰的な関数を書いてください。 - - `Writer`モナドを使用してコラッツ関数のそれぞれの適用の経過を記録するように、関数を変更してください。 - -## モナド変換子 - -上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*の例となっています。 -対応するモナド変換子はそれぞれ `StateT`、 `ReaderT`、 `WriterT`と呼ばれています。 - -モナド変換子とは何でしょうか。 -さて、これまで見てきたように、モナドはPureScriptのコードを何らかの種類の副作用で拡張するものでした。 -このモナドはPureScriptで適切な制御子(`runState`、 `runReader`、`runWriter`など)を使って解釈できます。 -使用する必要がある副作用が*1つだけ*なら、これで問題ありません。 -しかし、同時に複数の副作用を使用できると便利なことがよくあります。 -例えば、 `Maybe`と`Reader`を一緒に使用すると、ある大域的な設定の文脈で*省略可能な結果*を表現できます。 -もしくは、 `Either`モナドの純粋なエラー追跡機能と、 `State`モナドが提供する変更可能な状態が同時に欲しくなるかもしれません。 -この問題を解決するのが*モナド変換子*です。 - -ただし`Effect`モナドがこの問題に対する部分的な解決策を提供していたことは既に見てきました。 -モナド変換子はまた違った解決策を提供しますが、これらの手法にはそれぞれ利点と制約があります。 - -モナド変換子は型だけでなく別の型構築子もパラメータに取る型構築子です。モナド変換子はモナドを1つ取り、独自のいろいろな副作用を追加した別のモナドへと変換します。 - -例を見てみましょう。`State`のモナド変換子版は`Control.Monad.State.Trans`モジュールで定義されている`StateT`です。 -PSCiを使って `StateT`の種を見てみましょう。 - -```text -> import Control.Monad.State.Trans -> :kind StateT -Type -> (Type -> Type) -> Type -> Type -``` - -とても読みにくそうに見えるかもしれませんが、使い方を理解するために、`StateT`に1つ引数を与えてみましょう。 - -`State`の場合、最初の型引数は使いたい状態の型です。 -それでは型`String`を与えてみましょう。 - -```text -> :kind StateT String -(Type -> Type) -> Type -> Type -``` - -次の引数は種 `Type -> Type`の型構築子です。 -これは `StateT`の機能を追加したい元のモナドを表します。 -例として、 `Either String`モナドを選んでみます。 - -```text -> :kind StateT String (Either String) -Type -> Type -``` - -型構築子が残りました。 -最後の引数は戻り値の型を表しており、例えばそれを`Number`にできます。 - -```text -> :kind StateT String (Either String) Number -Type -``` - -最後に、種 `Type`の何かが残りましたが、これはつまりこの型の値を探してみることができるということです。 - -構築したモナド `StateT String (Either -String)`は、エラーで失敗する可能性があり、変更可能な状態を使える計算を表しています。 - -外側の `StateT String (Either -String)`モナドのアクション(`get`、`put`、`modify`)は直接使うことができますが、梱包されている内側のモナド (`Either -String`) の作用を使うためには、これらの関数をモナド変換子まで「持ち上げ」なくてはいけません。 -`Control.MonadTrans`モジュールでは、モナド変換子であるような型構築子を捉える`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`を一緒に使うことができることを意味します。 - -例えば、次の計算は `StateT`モナド変換子で導入されている状態を読み込み、状態が空の文字列である場合はエラーを投げます。 - -```haskell -import Data.String (drop, take) - -split :: StateT String (Either String) String -split = do - s <- get - case s of - "" -> lift $ Left "Empty string" - _ -> do - put (drop 1 s) - pure (take 1 s) -``` - -状態が空でなければ、この計算は `put`を使って状態を `drop 1 s`(最初の文字を取り除いた `s`)へと更新し、 `take 1 -s`(`s`の最初の文字)を返します。 - -それではPSCiでこれを試してみましょう。 - -```text -> runStateT split "test" -Right (Tuple "t" "est") - -> runStateT split "" -Left "Empty string" -``` - -これは `StateT`を使わなくても実装できるので、さほど驚くようなことはありません。 -しかし、モナドとして扱っているので、do記法やアプリカティブコンビネータを使って、小さな計算から大きな計算を構築していくことができます。 -例えば、2回 `split`を適用すると、文字列から最初の2文字を読むことができます。 - -```text -> runStateT ((<>) <$> split <*> split) "test" -(Right (Tuple "te" "st")) -``` - -他にもアクションを沢山用意すれば、 `split`関数を使って、基本的な構文解析ライブラリを構築できます。これは実際に -`parsing`ライブラリで採用されている手法です。これがモナド変換子の力なのです。必要な副作用を選択して、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。 - -## ExceptTモナド変換子 - -`transformers`パッケージでは、 `Either e`モナドに対応する変換子である`ExceptT e`モナド変換子も定義されています。 -これは次のAPIを提供します。 - -```haskell -class MonadError e m where - throwError :: forall a. e -> m a - catchError :: forall a. m a -> (e -> m a) -> m a - -instance Monad m => MonadError e (ExceptT e m) - -runExceptT :: forall e m a. ExceptT e m a -> m (Either e a) -``` - -`MonadError`クラスは `e`型のエラーを投げたりキャッチに対応したりするモナドを取得し、 `ExceptT -e`モナド変換子のインスタンスが提供されます。 -`Either e`モナドの `Left`と同じように、 `throwError`アクションは失敗を示すために使われます。 -`catchError`アクションを使うと、 `throwError`でエラーが投げられたあとでも処理を継続できるようになります。 - -`runExceptT`制御子を使うと、型 `ExceptT e m a`を計算できます。 - -このAPIは `exceptions`パッケージの `Exception`作用によって提供されているものと似ています。 -しかし、幾つかの重要な違いがあります。 - -- `Exception`が実際のJavaScriptの例外を使っているのに対して`ExceptT`モデルは代数的データ型を使っています。 -- `Exception`作用がJavaScriptの`Error`型という1つの例外の型だけを扱うのに対して、`ExceptT`は`Error`型クラスのどんな型のエラーでも扱います。つまり、 - `ExceptT`では新たなエラー型を自由に定義できます。 - -試しに `ExceptT`を使って `Writer`モナドを包んでみましょう。 -ここでもモナド変換子 `ExceptT e`のアクションを直接使うことも自由にできますが、`Writer`モナドの計算は -`lift`を使って持ちあげるべきです。 - -```haskell -import Control.Monad.Except -import Control.Monad.Writer - -writerAndExceptT :: ExceptT String (Writer (Array String)) String -writerAndExceptT = do - lift $ tell ["Before the error"] - _ <- throwError "Error!" - lift $ tell ["After the error"] - pure "Return value" -``` - -PSCiでこの関数を試すと、ログの蓄積とエラーの送出という2つの作用がどのように相互作用しているのかを見ることができます。 -まず、 `runExceptT`を使って外側の`ExceptT`を計算し、型 `Writer (Array String) (Either String -String)`の結果を残します。 -それから、 `runWriter`で内側の`Writer`を計算します。 - -```text -> runWriter $ runExceptT writerAndExceptT -Tuple (Left "Error!") ["Before the error"] -``` - -実際に追加されるログは、エラーが投げられる前に書かれたログメッセージだけであることにも注目してください。 - -## モナド変換子スタック - -これまで見てきたように、モナド変換子を使うと既存のモナドを土台に新しいモナドを構築できます。 -任意のモナド変換子 `t1`と任意のモナド`m`について、その適用 `t1 m`もまたモナドになります。 -これは*2つめの*モナド変換子 `t2`を先ほどの結果 `t1 m`に適用すると、3つ目のモナド `t2 (t1 m)`を作れることを意味しています。 -このように、構成するモナドによって提供された副作用を組み合わせる、モナド変換子の*スタック*を構築できます。 - -実際には、基本となるモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さもなくば -`Data.Identity`モジュールで定義されている`Identity`モナドになります。 -`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換はモナド変換子の作用だけを提供します。 -実際に、`State`モナドと`Reader`モナドと`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`と`ReaderT`と`WriterT`で変換することによって実装されています。 - -それでは3つの副作用が組み合わされている例を見てみましょう。 -`Identity`モナドをスタックの底にして、 `StateT`作用、 `WriterT`作用、`ExceptT`作用を使います。 -このモナド変換子スタックは、可変状態、ログの蓄積、そして純粋なエラーの副作用を提供します。 - -このモナド変換子スタックを使うと、ロギングの機能が追加された `split`アクションに作り変えられます。 - -```haskell -type Errors = Array String - -type Log = Array String - -type Parser = StateT String (WriterT Log (ExceptT Errors Identity)) - -split :: Parser String -split = do - s <- get - lift $ tell ["The state is " <> s] - case s of - "" -> lift $ lift $ throwError ["Empty string"] - _ -> do - put (drop 1 s) - pure (take 1 s) -``` - -この計算をPSCiで試してみると、 `split`が実行されるたびに状態がログに追加されることがわかります。 - -モナド変換子スタックに現れる順序に従って、副作用を取り除いていかなければならないことに注意してください。 -最初に `StateT`型構築子を取り除くために `runStateT`を使い、それから -`runtWriteT`を使い、その後`runExceptT`を使います。 -最後に `unwrap`を使用して `Identity`モナドを演算します。 - -```text -> runParser p s = unwrap $ runExceptT $ runWriterT $ runStateT p s - -> runParser split "test" -(Right (Tuple (Tuple "t" "est") ["The state is test"])) - -> runParser ((<>) <$> split <*> split) "test" -(Right (Tuple (Tuple "te" "st") ["The state is test", "The state is est"])) -``` - -しかし、状態が空であることが理由で解析が失敗した場合、ログは全く出力されません。 - -```text -> runParser split "" -(Left ["Empty string"]) -``` - -これは、 `ExceptT`モナド変換子が提供する副作用が、 `WriterT`モナド変換子が提供する副作用と干渉するためです。 -これはモナド変換子スタックが構成されている順序を変更することで解決できます。 -スタックの最上部に `ExceptT`変換子を移動すると、先ほど `Writer`を -`ExceptT`に変換したときと同じように、最初のエラーまでに書かれた全てのメッセージが含まれるようになります。 - -このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、 `lift`関数を複数回使わなければならないということです。 -例えば`throwError`の呼び出しは、1回目は `WriteT`へ、2回目は `StateT`へと、2回持ちあげなければなりません。 -小さなモナド変換子スタックならなんとかなりますが、そのうち不便だと感じるようになるでしょう。 - -幸いなことに、これから見るような型クラス推論によって提供されるコードの自動生成を使うと、ほとんどの「重労働」を任せられます。 - -## 演習 - - 1. (簡単)`Identity`関手を土台とする`ExceptT`モナド変換子を使って、2つの数の商を求める関数 - `safeDivide`を書いてください。 - この関数は分母がゼロの場合に(文字列「Divide by zero!」の)エラーを投げます。 - 1. (普通)次のような構文解析関数を書いてください。 - - ```haskell - string :: String -> Parser String - ``` - - これは現在の状態が接頭辞に適合するか、もしくはエラーメッセージとともに失敗します。 - - この構文解析器は次のように動作します。 - - ```text - > runParser (string "abc") "abcdef" - (Right (Tuple (Tuple "abc" "def") ["The state is abcdef"])) - ``` - - *手掛かり*:出発点として`split`の実装を使うといいでしょう。 - `stripPrefix`関数も役に立ちます。 -1. (難しい)以前 `Reader`モナドを使用して書いた文書表示ライブラリを、`ReaderT`と `WriterT`モナド変換子を使用して再実装してください。 - - 文字列を出力する `line`や文字列を連結する `cat`を使うのではなく、`WriteT`モナド変換子と一緒に `Array String`モノイドを使い、結果へ行を追加するのに `tell`を使ってください。 - アポストロフィ (`'`) を付ける以外は元の実装と同じ名前を使ってください。 - -## 型クラスが助けに来たぞっ - -本章の最初で扱った `State`モナドを見てみると、 `State`モナドのアクションには次のような型が与えられていました。 - -```haskell -get :: forall s. State s s -put :: forall s. s -> State s Unit -modify :: forall s. (s -> s) -> State s Unit -``` - -`Control.Monad.State.Class`モジュールで与えられている型は、実際にはこれよりもっと一般的です。 - -```haskell -get :: forall m s. MonadState s m => m s -put :: forall m s. MonadState s m => s -> m Unit -modify :: forall m s. MonadState s m => (s -> s) -> m Unit -``` - -`Control.Monad.State.Class`モジュールには`MonadState`(多変数)型クラスが定義されています。 -この型クラスは「変更可能な状態を提供する純粋なモナド」への抽象化を可能にします。 -予想できると思いますが、 `State s`型構築子は `MonadState -s`型クラスのインスタンスになっており、このクラスには他にも興味深いインスタンスが数多くあります。 - -特に、 `transformers`パッケージではモナド変換子 `WriterT`、 `ReaderT`、`ExceptT`についての -`MonadState`のインスタンスが提供されています。 -通底する`Monad`が`MonadState`インスタンスを持っていれば常に、これらのモナド変換子にもインスタンスがあります。 -実践的には、 `StateT`がモナド変換子スタックの*どこか*に現れ、 `StateT`より上の全てが -`MonadState`のインスタンスであれば、 `get`、 `put`、 `modify`を直接自由に使用できます。 - -当然ですが、これまで扱ってきた `ReaderT`、 `WriterT`、 -`ExceptT`変換子についても、同じことが成り立っています。`transformers`では主な変換子それぞれについての型クラスが定義されています。これによりそれらの操作に対応するモナドの上に抽象化できるのです。 - -上の `split`関数の場合、構築されたこのモナドスタックは型クラス`MonadState`、 `MonadWriter`、 -`MonadError`それぞれのインスタンスです。 -これはつまり、`lift`は全く呼び出す必要がないのです。 -まるでモナドスタック自体に定義されていたかのように、アクション `get`、`put`、 `tell`、 -`throwError`をそのまま使用できます。 - -```haskell -{{#include ../exercises/chapter11/src/Split.purs:split}} -``` - -この計算はまるで、可変状態、ロギング、エラー処理という3つの副作用に対応した、独自のプログラミング言語を拡張したかのようにみえます。 -しかし、内部的には全てはあくまで純粋な関数と普通のデータを使って実装されているのです。 - -## 代替 - -`control`パッケージでは失敗しうる計算を制御するための抽象化が幾つか定義されています。 -その1つは `Alternative`型クラスです。 - -```haskell -class Functor f <= Alt f where - alt :: forall a. f a -> f a -> f a - -class Alt f <= Plus f where - empty :: forall a. f a - -class (Applicative f, Plus f) <= Alternative f -``` - -`Alternative`は2つの新しいコンビネータを提供しています。 -1つは失敗しうる計算の雛形を提供する`empty`値で、もう1つはエラーが起きたときに*代替の*計算へ戻ってやり直す機能を提供する`alt`関数(そしてその別名`<|>`)です。 - -`Data.Array`モジュールでは `Alternative`型クラスで型構築子を操作する2 -つの便利な関数を提供します。 - -```haskell -many :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a) -some :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a) -``` - -`Data.List`にも等価な`many`と`some`があります。 - -`many`コンビネータは計算を _ゼロ回以上_ 繰り返し実行するために`Alternative`型クラスを使用しています。 -`some`コンビネータも似ていますが、成功するために少なくとも1回の計算を必要とします。 - -`Parser`モナド変換子スタックの場合は、`ExceptT`コンポーネントによる`Alternative`のインスタンスがあります。 -このコンポーネントでは異なる分枝のエラーに`Monoid`インスタンスを使って組み合わせることによって対応しています(だから`Errors`型に`Array -String`を選ぶ必要があったんですね)。 -これは、構文解析器を複数回実行するのに`many`関数と`some`関数を使うことができることを意味します。 - -```text -> import Data.Array (many) - -> runParser (many split) "test" -(Right (Tuple (Tuple ["t", "e", "s", "t"] "") - [ "The state is \"test\"" - , "The state is \"est\"" - , "The state is \"st\"" - , "The state is \"t\"" - ])) -``` - -ここでは入力文字列 `"test"`は、1文字からなる文字列4つの配列を返すように繰り返し分割されています。 -残った状態は空で、ログは `split`コンビネータが4回適用されたことを示しています。 - -## モナド内包表記 - -`Control.MonadPlus`モジュールには `MonadPlus`と呼ばれる`Alternative`型クラスの副クラスが定義されています。 -`MonadPlus`はモナドと`Alternative`両方のインスタンスである型構築子を取ります。 - -```haskell -class (Monad m, Alternative m) <= MonadPlus m -``` - -実際、`Parser`モナドは `MonadPlus`のインスタンスです。 - -以前本書中で配列内包表記を扱ったとき、不要な結果を除いて絞り込むために使われる`guard`関数を導入しました。 -実際には`guard`関数はもっと一般的で、 `MonadPlus`のインスタンスである全てのモナドに対して使うことができます。 - -```haskell -guard :: forall m. Alternative m => Boolean -> m Unit -``` - -`<|>`演算子は失敗時にバックトラッキングできるようにします。 -これがどのように役立つかを見るために、大文字だけに適合する `split`コンビネータの亜種を定義してみましょう。 - -```haskell -{{#include ../exercises/chapter11/src/Split.purs:upper}} -``` - -ここで、文字列が大文字でない場合に失敗するよう -`guard`を使用しています。このコードは前に見た配列内包表記とよく似ていることに注目してください。このように`MonadPlus`を使うことは、 -_モナド内包表記_ (monad comprehensions) の構築と呼ばれることがあります。 - -## バックトラッキング - -`<|>`演算子を使うと、失敗したときに別の代替計算へとバックトラックできます。 -これを確かめるために、小文字に一致するもう1つの構文解析器を定義してみましょう。 - -```haskell -{{#include ../exercises/chapter11/src/Split.purs:lower}} -``` - -これにより、まずもし最初の文字が大文字なら複数の大文字に適合し、さもなくばもし最初の文字が小文字なら複数の小文字に適合する、という構文解析器を定義できます。 - -```text -> upperOrLower = some upper <|> some lower -``` - -この構文解析器は、大文字と小文字が切り替わるまで、文字に適合し続けます。 - -```text -> runParser upperOrLower "abcDEF" -(Right (Tuple (Tuple ["a","b","c"] ("DEF")) - [ "The state is \"abcDEF\"" - , "The state is \"bcDEF\"" - , "The state is \"cDEF\"" - ])) -``` - -また、`many`を使うと文字列を小文字と大文字の要素に完全に分割できます。 - -```text -> components = many upperOrLower - -> runParser components "abCDeFgh" -(Right (Tuple (Tuple [["a","b"],["C","D"],["e"],["F"],["g","h"]] "") - [ "The state is \"abCDeFgh\"" - , "The state is \"bCDeFgh\"" - , "The state is \"CDeFgh\"" - , "The state is \"DeFgh\"" - , "The state is \"eFgh\"" - , "The state is \"Fgh\"" - , "The state is \"gh\"" - , "The state is \"h\"" - ])) -``` - -繰り返しになりますが、これはモナド変換子がもたらす再利用性の威力を示しています。 -標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器を、ほんの数行のコードで書くことができました。 - -## 演習 - - 1. (簡単)`string`構文解析器の実装から `lift`関数の呼び出しを取り除いてください。 - 新しい実装の型が整合していることを確認し、なぜそのようになるのかをよく納得しておきましょう。 - 1. (普通)`string`構文解析器と `many`コンビネータを使って、文字列`"a"`の連続と、それに続く文字列 - `"b"`の連続からなる文字列を認識する構文解析器`asFollowedByBs`を書いてください。 - 1. (普通)`<|>`演算子を使って、文字 `a`と文字 - `b`が任意の順序で現れるような文字列を認識する構文解析器`asOrBs`を書いてください。 - 1. (難しい)`Parser`モナドを次のようにも定義できます。 - - ```haskell - type Parser = ExceptT Errors (StateT String (WriterT Log Identity)) - ``` - - このように変更すると、構文解析関数にどのような影響を与えるでしょうか。 - -## RWSモナド - -モナド変換子のとある特定の組み合わせは頻出なので、`transformers`パッケージ内の単一のモナド変換子として提供されています。 -`Reader`、 -`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わさり、より単純に`RWS`モナドともされます。 -このモナドは `RWST`モナド変換子と呼ばれる、対応するモナド変換子を持っています。 - -ここでは `RWS`モナドを使ってテキストアドベンチャーゲームの処理を設計していきます。 - -`RWS`モナドは(戻り値の型に加えて)3つの型変数を使って定義されています。 - -```haskell -type RWS r w s = RWST r w s Identity -``` - -ここで、副作用を提供しない`Identity`を基底のモナドに設定することで、 `RWS`モナドが独自のモナド変換子を用いて定義されています。 - -第1型引数 `r`は大域的な設定の型を表します。 -第2型引数 `w`はログを蓄積するために使用するモノイド、第3型引数 `s`は可変状態の型を表しています。 - -このゲームの場合には、大域的な設定は -`Data.GameEnvironment`モジュールの`GameEnvironment`という名前の型で定義されています。 - -```haskell -{{#include ../exercises/chapter11/src/Data/GameEnvironment.purs:env}} -``` - -プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義されています。 -これらのオプションは、モナド変換子を実行するときにコマンドラインから設定されます。 - -可変状態は `Data.GameState`モジュールの `GameState`と呼ばれる型で定義されています。 - -```haskell -{{#include ../exercises/chapter11/src/Data/GameState.purs:imports}} - -{{#include ../exercises/chapter11/src/Data/GameState.purs:GameState}} -``` - -`Coords`データ型は2次元平面の点を表し、 `GameItem`データ型はゲーム内のアイテムの列挙です。 - -```haskell -{{#include ../exercises/chapter11/src/Data/GameItem.purs:GameItem}} -``` - -`GameState`型は2つの新しいデータ構造を使っています。 -`Map`と`Set`はそれぞれ整列されたマップと整列された集合を表します。 -`items`属性は、そのゲーム平面上の座標からゲームアイテムの集合への対応付けになっています。 -`player`属性はプレイヤーの現在の座標を格納しており、 `inventory`属性は現在プレイヤーが保有するゲームアイテムの集合です。 - -`Map`と `Set`のデータ構造はキーによって整列され、 -`Ord`型クラスの任意の型をキーとして使用できます。これは今回のデータ構造のキーが完全に順序付けできることを意味します。 - -ゲームのアクションを書く上で`Map`と `Set`構造をどのように使っていくのかを見ていきます。 - -ログとしては `List String`モノイドを使います。 -`Game`モナド用の型同義語を定義し、`RWS`を使って実装できます。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:Game}} -``` - -## ゲームロジックの実装 - -今回は`Reader`モナドと`Writer`モナドと`State`モナドのアクションを再利用し、`Game`モナドで定義されている単純なアクションを組み合わせてゲームを構築していきます。 -このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドはコンソールにテキストを出力するような観測可能な副作用へと結果を変換するために使っています。 - -このゲームで最も簡単なアクションの1つは -`has`アクションです。このアクションはプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調べます。これは次のように定義されます。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:has}} -``` - -この関数は、現在のゲームの状態を読み取るために `MonadState`型クラスで定義されている `get`アクションを使っています。 -またそれから指定した`GameItem`が持ち物アイテムの`Set`に出現するかどうかを調べるために`Data.Set`で定義されている -`member`関数を使っています。 - -他にも `pickUp`アクションがあります。 -現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加します。 -これには`MonadWriter`と `MonadState`型クラスのアクションを使っています。 -一番最初に現在のゲームの状態を読み取ります。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:pickup_start}} -``` - -次に `pickUp`は現在の位置にあるアイテムの集合を検索します。 -これは`Data.Map`で定義された `lookup`関数を使って行います。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:pickup_case}} -``` - -`lookup`関数は `Maybe`型構築子で示されたオプショナルな結果を返します。 -`lookup`関数は、キーがマップにない場合は `Nothing`を返し、それ以外の場合は `Just`構築子で対応する値を返します。 - -関心があるのは、指定されたゲームアイテムが対応するアイテムの集合に含まれている場合です。 -ここでも`member`関数を使うとこれを調べることができます。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}} -``` - -この場合、 `put`を使ってゲームの状態を更新し、 `tell`を使ってログにメッセージを追加できます。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:pickup_body}} -``` - -ここで2つの計算のどちらも`lift`が必要ないことに注意してください。 -なぜなら`MonadState`と `MonadWriter`の両方について `Game`モナド変換子スタック用の適切なインスタンスが存在するからです。 - -`put`への引数では、レコード更新を使ってゲームの状態の `items`と`inventory`フィールドを変更しています。 -また、特定のキーの値を変更する`Data.Map`の `update`関数を使っています。 -このとき、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`関数を使って指定したアイテムを集合から取り除いています。 -`insert`を使って新しいアイテムをプレイヤーの持ち物集合に加えるときにも、`inventory`は更新されます。 - -最後に、`pickUp`関数は `tell`を使ってユーザに次のように通知することにより、残りの場合を処理します。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:pickup_err}} -``` - -`Reader`モナドを使う例として、 `debug`コマンドのコードを見てみましょう。 -ゲームがデバッグモードで実行されている場合、このコマンドを使うとユーザは実行時にゲームの状態を調べることができます。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:debug}} -``` - -ここでは、ゲームの設定を読み込むために `ask`アクションを使用しています。 -繰り返しますが、どの計算でも`lift`は必要がなく、同じdo記法ブロック内で`MonadState`、 `MonadReader`、 -`MonadWriter`型クラスで定義されているアクションを使うことができることに注意してください。 - -`debugMode`フラグが設定されている場合、 `tell`アクションを使うとログに状態が追加されます。 -そうでなければ、エラーメッセージが追加されます。 - -`Game.purs`モジュールの残りの部分では、`MonadState`型クラスと`MonadReader`型クラスと`MonadWriter`型クラスでそれぞれ定義されたアクションだけを使い、同様のアクションが定義されています。 - -## 計算の実行 - -このゲームロジックは `RWS`モナドで動くため、ユーザのコマンドに応答するためには計算する必要があります。 - -このゲームのフロントエンドは2つのパッケージで構成されています。 -アプリカティブなコマンドライン構文解析を提供する`optparse`と、対話的なコンソールベースのアプリケーションを書くことを可能にする、NodeJSの -`readline`モジュールを梱包する `node-readline`パッケージです。 - -このゲームロジックへのインターフェースは `Game`モジュール内の関数`game`によって提供されます。 - -```haskell -{{#include ../exercises/chapter11/src/Game.purs:game_sig}} -``` - -これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してから、 `runRWS`を使って `RWS`の計算結果を実行します。 - -```haskell -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`を組み合わせたように見えます。 -これは、引数として大域的な設定及び初期状態をとり、ログ、結果、最的な終状態を含むデータ構造を返します。 - -このアプリケーションのフロントエンドは、次の型シグネチャを持つ関数`runGame`によって定義されます。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:runGame_sig}} -``` - -この関数は(`node-readline`と`console`パッケージを使って)コンソールを介してユーザとやり取りします。 -`runGame`は関数の引数としてのゲームの設定を取ります。 - -`node-readline`パッケージでは`LineHandler`型が提供されています。 -これは端末からのユーザ入力を扱う `Effect`モナドのアクションを表します。 -対応するAPIは次の通りです。 - -```haskell -type LineHandler a = String -> Effect a - -foreign import setLineHandler - :: forall a - . Interface - -> LineHandler a - -> Effect Unit -``` - -`Interface`型はコンソールの制御対象を表しており、コンソールとやり取りする関数への引数として渡されます。 -`createConsoleInterface`関数を使用すると `Interface`を作成できます。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:import_RL}} - -{{#include ../exercises/chapter11/src/Main.purs:runGame_interface}} -``` - -最初の工程はコンソールにプロンプトを設定することです。 -`interface`制御対象を渡し、プロンプト文字列と字下げレベルを与えます。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:runGame_prompt}} -``` - -今回は行制御関数を実装することに関心があります。 -ここでの行制御は`let`宣言内の補助関数を使って次のように定義されています。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:runGame_lineHandler}} -``` - -`let`束縛が`env`という名前のゲーム構成や`interface`という名前のコンソール制御対象を包み込んでいます。 - -この制御子は追加の最初の引数としてゲームの状態を取ります。 -ゲームのロジックを実行するために`runRWS`にゲームの状態を渡さなければならないので、これは必要となっています。 - -このアクションが最初に行うことは、 `Data.String`モジュールの `split`関数を使用して、ユーザーの入力を単語に分割することです。 -それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`モナドで)`game`アクションを実行しています。 - -純粋な計算であるゲームロジックを実行するには、画面に全てのログメッセージを出力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。 -`for_`アクションが(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。 -最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`アクションを使ってプロンプトを再び表示しています。 - -`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付けて、最初のプロンプトを表示します。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:runGame_attach_handler}} -``` - -## 演習 - - 1. (普通)ゲームの格子上にある全てのゲームアイテムをユーザの持ちものに移動する新しいコマンド `cheat`を実装してください。 - 関数`cheat :: Game Unit`を`Game`モジュールに作り、この関数を`game`から使ってください。 - 1. (難しい)`RWS`モナドの ` - Writer`コンポーネントは、エラーメッセージと情報メッセージの2つの種類のメッセージのために使われています。 - このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用しています。 - - エラーメッセージを扱うのに `ExceptT`モナド変換子を使うようにし、情報メッセージを扱うのに`RWS`を使うようにするよう、コードをリファクタリングしてください。 - *補足*:この演習にはテストはありません。 - -## コマンドラインオプションの扱い - -このアプリケーションの最後の部品には、コマンドラインオプションの解析と`GameEnvironment`設定レコードを作成する役目があります。 -このためには`optparse`パッケージを使用します。 - -`optparse`は*アプリカティブなコマンドラインオプション構文解析器*の一例です。 -アプリカティブ関手を使うと、いろいろな副作用の型を表す型構築子まで任意個数の引数の関数を持ち上げられることを思い出してください。 -`optparse`パッケージの場合には、コマンドラインオプションからの読み取りの副作用を追加する`Parser`関手(optparseのモジュール`Options.Applicative`からインポートされたもの。`Split`モジュールで定義した`Parser`と混同しないように)が興味深い関手になっています。 -これは次のような制御子を提供しています。 - -```haskell -customExecParser :: forall a. ParserPrefs → ParserInfo a → Effect a -``` - -実例を見るのが一番です。 -このアプリケーションの `main`関数は`customExecParser`を使って次のように定義されています。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:main}} -``` - -最初の引数は`optparse`ライブラリを設定するために使用されます。 -今回の場合、アプリケーションが引数なしで走らされたときは、(「missing argument」エラーを表示する代わりに)`OP.prefs -OP.showHelpOnEmpty`を使って使用方法のメッセージを表示するように設定していますが、`Options.Applicative.Builder`モジュールには他にも幾つかの選択肢を提供しています。 - -2つ目の引数は解析プログラムの完全な説明です。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:argParser}} - -{{#include ../exercises/chapter11/src/Main.purs:parserOptions}} -``` - -ここで`OP.info`は使用方法のメッセージの書式方法のオプションの集合と共に`Parser`を結合します。 -`env <**> OP.helper`は`env`と名付けられた任意のコマンドライン引数`Parser`を取り、自動的に`--help`オプションを加えます。 -使用方法のメッセージ用のオプションは型が`InfoMod`であり、これはモノイドなので`fold`関数を使って複数のオプションを一緒に追加できます。 - -解析器の面白い部分は`GameEnvironment`の構築にあります。 - -```haskell -{{#include ../exercises/chapter11/src/Main.purs:env}} -``` - -`player`と`debug`は両方とも`Parser`なので、アプリカティブ演算子`<$>`と`<*>`を使って`gameEnvironment`関数を持ち上げることができます。 -この関数は`Parser`上で型`PlayerName -> Boolean -> GameEnvironment`を持ちます。 -`OP.strOption`は文字列値を期待するコマンドラインオプションを構築し、一緒に畳み込まれた`Mod`の集まりを介して設定されています。 -`OP.flag`は似たような動作をしますが、関連付けられた値は期待しません。 -`optparse`は多種多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。 - -アプリカティブ演算子による記法を使うことで、コマンドラインインターフェイスに対して簡潔で宣言的な仕様を与えることが可能になったことに注目です。 -また、`runGame`に新しい関数引数を追加し、`env`の定義中で`<*>`を使って追加の引数まで `runGame`を持ち上げるだけで、簡単に新しいコマンドライン引数を追加できます。 - -## 演習 - - 1. (普通)`GameEnvironment`レコードに新しい真偽値のプロパティ`cheatMode`を追加してください。 - また、 `optparse`設定に、チートモードを有効にする新しいコマンドラインフラグ `-c`を追加してください。 - チートモードが有効になっていない場合、 `cheat`コマンドは禁止されなければなりません。 - -## まとめ - -この章ではこれまで学んできた技術を実践的に実演しました。 -モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロントエンドを構築するための `Effect`モナドがそれです。 - -ユーザインターフェイスからの実装を分離したので、ゲームの別のフロントエンドも作成できるでしょう。 -例えば、`Effect`モナドでCanvas APIやDOMを使用して、ブラウザでゲームを描画するようなことができるでしょう。 - -モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見てきました。 -このスタイルでは型システムによって作用が追跡されています。 -また、型クラスはモナドが提供するアクションへと抽象化する強力な方法を提供します。 -このモナドのお陰でコードの再利用が可能になりました。 -標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のような標準的な抽象化を使用して、役に立つモナドを構築できました。 - -モナド変換子は、高階多相や多変数型クラスなどの高度な型システムの機能を利用することによって記述でき、表現力の高いコードの優れた実演となっています。 diff --git a/text-ja/chapter12.md b/text-ja/chapter12.md deleted file mode 100644 index 650ea4e3..00000000 --- a/text-ja/chapter12.md +++ /dev/null @@ -1,721 +0,0 @@ -# Canvasグラフィックス - -## この章の目標 - -この章は`canvas`パッケージに焦点を当てる発展的な例となります。 -このパッケージはPureScriptでHTML5のCanvas APIを使用して2Dグラフィックスを生成する手段を提供します。 - -## プロジェクトの準備 - -このモジュールのプロジェクトでは以下の新しい依存関係が導入されます。 - -- `canvas`はHTML5のCanvas APIメソッドの型を与えます。 -- `refs`は _大域的な変更可能領域への参照_ を使うための副作用を提供します。 - -この章のソースコードは、それぞれに `main`メソッドが定義されているモジュールの集合へと分割されています。 -この章のそれぞれの節の内容は個別のファイルで実装されており、それぞれの時点での適切なファイルの`main`メソッドを実行できるように、Spagoビルドコマンドを変更することで`Main`モジュールを合わせられるようになっています。 - -HTMLファイル `html/index.html`には、各例で使用される単一の -`canvas`要素、及びコンパイルされたPureScriptコードを読み込む `script`要素が含まれています。 -ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありません。 - -## 単純な図形 - -`Example/Rectangle.purs`ファイルには簡単な導入例が含まれています。 -この例ではcanvasの中心に青い四角形を1つ描画します。 -このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas -APIを扱うための`Effect`モナドのアクションを含む`Graphics.Canvas`モジュールをインポートします。 - -他のモジュールでも同様ですが、 -`main`アクションは最初に`getCanvasElementById`アクションを使ってcanvasオブジェクトへの参照を取得します。 -また、 `getContext2D`アクションを使ってキャンバスの2D描画コンテキストを参照します。 - -`void`関数は関手を取り値を`Unit`で置き換えます。 -例では`main`がシグネチャに沿うようにするために使われています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Rectangle.purs:main}} -``` - -*補足*:この`unsafePartial`の呼び出しは必須です。 -これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと照合するためです。 -ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子と照合させ、適切なエラーメッセージを提供したほうがよいでしょう。 - -これらのアクションの型はPSCiを使うかドキュメントを見ると確認できます。 - -```haskell -getCanvasElementById :: String -> Effect (Maybe CanvasElement) - -getContext2D :: CanvasElement -> Effect Context2D -``` - -`CanvasElement`と `Context2D`は `Graphics.Canvas`モジュールで定義されている型です。 -このモジュールでは`Canvas`作用も定義されており、モジュール内の全てのアクションで使用されています。 - -グラフィックスコンテキスト`ctx`はcanvasの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用するためのメソッドを提供します。 - -話を進めると、`setFillStyle`アクションを使うことで塗り潰しスタイルを濃い青に設定できます。 -より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がより簡単です。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Rectangle.purs:setFillStyle}} -``` - -`setFillStyle`アクションがグラフィックスコンテキストを引数として取っていることに注意してください。 -これは `Graphics.Canvas`ではよくあるパターンです。 - -最後に、 `fillPath`アクションを使用して矩形を塗り潰しています。 -`fillPath`は次のような型を持っています。 - -```haskell -fillPath :: forall a. Context2D -> Effect a -> Effect a -``` - -`fillPath`はグラフィックスコンテキストと描画するパスを構築する別のアクションを引数にとります。 -`rect`アクションを使うとパスを構築できます。 -`rect`はグラフィックスコンテキストと矩形の位置及びサイズを格納するレコードを引数にとります。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Rectangle.purs:fillPath}} -``` - -mainモジュールの名前として`Example.Rectangle`を与えてこの長方形のコード例をビルドしましょう。 - -```text -$ spago bundle-app --main Example.Rectangle --to dist/Main.js -``` - -それでは `html/index.html`ファイルを開き、このコードによってcanvasの中央に青い四角形が描画されていることを確認してみましょう。 - -## 行多相を利用する - -パスを描画する方法は他にもあります。 `arc`関数は円弧を描画します。 -`moveTo`関数、 `lineTo`関数、 `closePath`関数は断片的な線分のパスを描画するのに使えます。 - -`Shapes.purs`ファイルでは長方形と円弧と三角形の、3つの図形を描画しています。 - -`rect`関数は引数としてレコードをとることを見てきました。 -実際には、長方形のプロパティは型同義語で定義されています。 - -```haskell -type Rectangle = - { x :: Number - , y :: Number - , width :: Number - , height :: Number - } -``` - -`x`と `y`プロパティは左上隅の位置を表しており、 `w`と `h`のプロパティはそれぞれ幅と高さを表しています。 - -`arc`関数に以下のような型を持つレコードを渡して呼び出すと、円弧を描画できます。 - -```haskell -type Arc = - { x :: Number - , y :: Number - , radius :: Number - , start :: Number - , end :: Number - } -``` - -ここで、 `x`と `y`プロパティは弧の中心、 `r`は半径、 `start`と `end`は弧の両端の角度を弧度法で表しています。 - -例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰します。 -弧は1回転のうち2/3ラジアン分あります。 -単位円が上下逆様になっている点に注意してください。 -これはy軸がcanvasの下向きに伸びるためです。 - -```haskell - fillPath ctx $ arc ctx - { x : 300.0 - , y : 300.0 - , radius : 50.0 - , start : 0.0 - , end : Math.tau * 2.0 / 3.0 - } -``` - -`Number`型の `x`と `y`というプロパティが `Rectangle`レコード型と`Arc`レコード型の両方に含まれていますね。 -どちらの場合でもこの組は点を表しています。 -これは、何れのレコード型にも適用できる、行多相な関数を書くことができることを意味します。 - -例えば`Shapes`モジュールでは `x`と `y`のプロパティを変更し図形を並行移動する `translate`関数を定義されています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Shapes.purs:translate}} -``` - -この行多相型に注目してください。 -`translate`が `x`と -`y`というプロパティと、*それに加えて他の任意のプロパティ*を持つどんなレコードでも受け入れ、同じ型のレコードを返すと書かれています。 -`x`フィールドと `y`フィールドは更新されますが、残りのフィールドは変更されません。 - -これは*レコード更新構文*の例です。 -`shape { ... }`という式は、`shape`を元にして、括弧の中で指定された値で更新されたフィールドを持つ新たなレコードを作ります。 -なお、波括弧の中の式はレコード直値のようなコロンではなく、等号でラベルと式を区切って書きます。 - -`Shapes`の例からわかるように、 `translate`関数は `Rectangle`レコードと`Arc`レコード双方に対して使うことができます。 - -`Shape`の例で描画される3つ目の型は線分の断片からなるパスです。 -対応するコードは次のようになります。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Shapes.purs:path}} -``` - -ここでは3つの関数が使われています。 - -- `moveTo`はパスの現在地を指定された座標に移動します。 -- `lineTo`は現在地と指定された座標の間の線分を描画し、現在地を更新します。 -- `closePath`は現在地と開始地点とを結ぶ線分を描画してパスを完結します。 - -このコード片の結果は二等辺三角形の塗り潰しになります。 - -mainモジュールとして`Example.Shapes`を指定して、この例をビルドしましょう。 - -```text -$ spago bundle-app --main Example.Shapes --to dist/Main.js -``` - -そしてもう一度 `html/index.html`を開き、結果を確認してください。canvas -に3つの異なる図形が描画されるはずです。 - -## 演習 - - 1. (簡単)これまでの例のそれぞれについて、 `strokePath`関数や`setStrokeStyle`関数を使ってみましょう。 - 1. (簡単)関数の引数の内部のdo記法ブロックにより、`fillPath`関数と`strokePath`関数を使って共通のスタイルを持つ複雑なパスを描画できます。 - 同じ `fillPath`呼び出しで隣り合った2つの矩形を描画するように、`Rectangle`のコード例を変更してみてください。 - 線分と円弧を組み合わせて、扇形を描画してみてください。 - 1. (普通)次のような2次元の点を表すレコードが与えられたとします。 - - ```haskell - type Point = { x :: Number, y :: Number } - ``` - - これは2次元の点を表現しています。 - 多数の点からなる閉じたパスを線描きする関数 `renderPath`を書いてください。 - - ```haskell - renderPath - :: Context2D - -> Array Point - -> Effect Unit - ``` - - 次のような関数を考えます。 - - ```haskell - f :: Number -> Point - ``` - - この関数は引数として `1`から `0`の間の `Number`をとり、 `Point`を返します。 - `renderPath`関数を利用して関数 `f`のグラフを描くアクションを書いてください。 - そのアクションでは有限個の点を `f`からサンプリングすることによって近似しなければなりません。 - - 関数 `f`を変更し、様々なパスが描画されることを確かめてください。 - -## 無作為に円を描く - -`Example/Random.purs`ファイルには2種類の異なる副作用が混在した`Effect`モナドを使う例が含まれています。 -1つは乱数生成で、もう1つはcanvasの操作です。 -この例では無作為に生成された円をキャンバスに100個描画します。 - -`main`アクションではこれまでのようにグラフィックスコンテキストへの参照を取得し、ストロークと塗り潰しスタイルを設定します。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Random.purs:style}} -``` - -次のコードでは `for_`アクションを使って `0`から `100`までの整数について反復しています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Random.purs:for}} -``` - -それぞれの繰り返しでのdo記法ブロックは、`0`と`1`の間に分布する3つの乱数を生成することから始まります。 -これらの数は `0`から `1`の間に無作為に分布しており、それぞれ `x`座標、 `y`座標、半径 `r`を表しています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Random.purs:random}} -``` - -次のコードではそれぞれの円について、これらの変数に基づいて `Arc`を作成し、最後に現在のスタイルに従って円弧を塗り潰し線描きします。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Random.purs:path}} -``` - -mainモジュールとして`Example.Random`を指定して、この例をビルドしましょう。 - -```text -$ spago bundle-app --main Example.Random --to dist/Main.js -``` - -`html/index.html`を開いて、結果を確認してみましょう。 - -## 座標変換 - -キャンバスは簡単な図形を描画するだけのものではありません。 -キャンバスは変換行列を扱うことができ、描画の前に形状を変形してから図形を描画できます。 -図形は平行移動、回転、拡大縮小、及び斜めに変形できます。 - -`canvas`ライブラリではこれらの変換を以下の関数で提供しています。 - -```haskell -translate :: Context2D - -> TranslateTransform - -> Effect Context2D - -rotate :: Context2D - -> Number - -> Effect Context2D - -scale :: Context2D - -> ScaleTransform - -> Effect Context2D - -transform :: Context2D - -> Transform - -> Effect Context2D -``` - -`translate`アクションは`TranslateTransform`レコードのプロパティで指定した大きさだけ平行移動します。 - -`rotate`アクションは最初の引数で指定されたラジアンの値に応じて、原点を中心として回転します。 - -`scale`アクションは原点を中心として拡大縮小します。 -`ScaleTransform`レコードは `X`軸と `y`軸に沿った拡大率を指定するのに使います。 - -最後の `transform`はこの4つのうちで最も一般化されたアクションです。 -このアクションでは行列に従ってアフィン変換します。 - -これらのアクションが呼び出された後に描画される図形は、自動的に適切な座標変換が適用されます。 - -実際には、これらの関数のそれぞれの作用は、コンテキストの現在の変換行列に対して変換行列を*右から乗算*していきます。 -つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されていきます。 - -```haskell -transformations ctx = do - translate ctx { translateX: 10.0, translateY: 10.0 } - scale ctx { scaleX: 2.0, scaleY: 2.0 } - rotate ctx (Math.tau / 4.0) - - renderScene -``` - -この一連のアクションの作用では、まずシーンが回転され、それから拡大縮小され、最後に平行移動されます。 - -## コンテキストの保存 - -変換を適用してシーンの一部を描画し、それからその変換を元に戻す、という使い方はよくあります。 - -Canvas APIにはキャンバスの状態の*スタック*を操作する`save`と`restore`メソッドが備わっています。 -`canvas`ではこの機能を次のような関数で梱包しています。 - -```haskell -save - :: Context2D - -> Effect Context2D - -restore - :: Context2D - -> Effect Context2D -``` - -`save`アクションは現在のコンテキストの状態(現在の変換行列や描画スタイル)をスタックにプッシュし、 -`restore`アクションはスタックの一番上の状態をポップし、コンテキストの状態を復元します。 - -これらのアクションにより、現在の状態を保存し、いろいろなスタイルや変換を適用してから原始的な図形を描画し、最後に元の変換と状態を復元できます。 -例えば、次の関数は回転を適用してから幾つかのキャンバスアクションを実行し、そのあとに変換を復元します。 - -```haskell -rotated ctx render = do - save ctx - rotate (Math.tau / 3.0) ctx - render - restore ctx -``` - -こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元のコンテキスト状態を保存しつつ幾つかのキャンバスアクションを実行する -`withContext`関数が提供されています。 - -```haskell -withContext - :: Context2D - -> Effect a - -> Effect a -``` - -`withContext`を使うと、先ほどの `rotated`関数を次のように書き換えることができます。 - -```haskell -rotated ctx render = - withContext ctx do - rotate (Math.tau / 3.0) ctx - render -``` - -## 大域的な変更可能状態 - -この節では `refs`パッケージを使って `Effect`モナドの別の作用について実演してみます。 - -`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及び関連する作用を提供します。 - -```text -> import Effect.Ref - -> :kind Ref -Type -> Type -``` - -型`Ref a`の値は型`a`の値を含む可変参照セルであり、大域的な変更を追跡するのに使われます。 -そういったわけでこれは少しだけ使う分に留めておくべきです。 - -`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに `Ref`作用を使用する例が含まれています。 - -このコードでは最初に`new`アクションを使って値`0`を含む新しい参照を作成しています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Refs.purs:clickCount}} -``` - -クリックイベント制御子の内部では、 `modify`アクションを使用してクリック数を更新し、更新された値が返されています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Refs.purs:count}} -``` - -`render`関数ではクリック数に応じた変換を矩形に適用しています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}} -``` - -このアクションでは元の変換を保存するために -`withContext`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。 - -- 矩形が`(-100, -100)`だけ平行移動し、中心が原点に来ます。 -- 矩形が原点を中心に拡大されます。 -- 矩形が原点を中心に`10`の倍数分の角度で回転します。 -- 矩形が`(300, 300)`だけ平行移動し、中心がcanvasの中心に来ます。 - -このコード例をビルドしてみましょう。 - -```text -$ spago bundle-app --main Example.Refs --to dist/Main.js -``` - -`html/index.html`ファイルを開いてみましょう。 -緑の四角形が表示され、何度かキャンバスをクリックするとキャンバスの中心の周りで回転するはずです。 - -## 演習 - - 1. (簡単)パスの線描と塗り潰しを同時に行う高階関数を書いてください。 - その関数を使用して `Random.purs`例を書き直してください。 - 1. (普通)`Random`作用と - `Dom`作用を使用して、マウスがクリックされたときに、キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してください。 - 1. (普通)指定された座標を中心としてシーンを回転させる関数を書いてください。 - *手掛かり*:最初にシーンを原点まで平行移動しましょう。 - -## L-System - -この章の最後の例として、 `canvas`パッケージを使用して*L-system*(またの名を*Lindenmayer -system*)を描画する関数を記述します。 - -L-Systemは*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生成規則*の集合で定義されています。 -各生成規則は、アルファベットの文字をとり、それを置き換える文字の配列を返します。 -この処理は文字の初期配列から始まり、複数回繰り返されます。 - -もしアルファベットの各文字がcanvas上で実行される命令と対応付けられていれば、その指示に順番に従うことでL-Systemを描画できます。 - -例えばアルファベットが文字 `L`(左回転)、 `R`(右回転)、 `F`(前進)で構成されているとします。 -また、次のような生成規則を定義します。 - -```text -L -> L -R -> R -F -> FLFRRFLF -``` - -配列 "FRRFRRFRR" から始めて処理を繰り返すと、次のような経過を辿ります。 - -```text -FRRFRRFRR -FLFRRFLFRRFLFRRFLFRRFLFRRFLFRR -FLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLF... -``` - -この命令群に対応する線分パスをプロットすると、*コッホ曲線*と呼ばれる曲線に近似されます。 -反復回数を増やすと、曲線の解像度が増していきます。 - -それでは型と関数のある言語へとこれを翻訳してみましょう。 - -アルファベットの文字は以下のADTで表現できます。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:letter}} -``` - -このデータ型では、アルファベットの文字ごとに1つずつデータ構築子が定義されています。 - -文字の初期配列はどのように表したらいいでしょうか。 -単なるアルファベットの配列でいいでしょう。 -これを `Sentence`と呼ぶことにします。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:sentence}} - -{{#include ../exercises/chapter12/src/Example/LSystem.purs:initial}} -``` - -生成規則は以下のように`Letter`から `Sentence`への関数として表すことができます。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:productions}} -``` - -これはまさに上記の仕様をそのまま書き写したものです。 - -これで、この形式の仕様を受け取りcanvasに描画する関数 `lsystem`を実装できます。 -`lsystem`はどのような型を持っているべきでしょうか。 -この関数は初期状態 `initial`や生成規則 -`productions`のような値だけでなく、アルファベットの文字をcanvasに描画する関数を引数に取る必要があります。 - -`lsystem`の型の最初の大まかな設計は以下です。 - -```haskell -Sentence --> (Letter -> Sentence) --> (Letter -> Effect Unit) --> Int --> Effect Unit -``` - -最初の2つの引数の型は、値 `initial`と `productions`に対応しています。 - -3番目の引数は、アルファベットの文字を取り、canvas上の幾つかのアクションを実行することによって*解釈*する関数を表します。 -この例では、文字`L`は左回転、文字 `R`で右回転、文字 `F`は前進を意味します。 - -最後の引数は、実行したい生成規則の繰り返し回数を表す数です。 - -最初に気付くことは、この`lsystem`関数は1つの型`Letter`に対してのみ動作するのですが、どんなアルファベットについても機能すべきですから、この型はもっと一般化されるべきです。 -それでは、量子化された型変数 `a`について、`Letter`と `Sentence`を `a`と `Array a`で置き換えましょう。 - -```haskell -forall a. Array a - -> (a -> Array a) - -> (a -> Effect Unit) - -> Int - -> Effect Unit -``` - -次に気付くこととしては、「左回転」と「右回転」のような命令を実装するためには、幾つかの状態を管理する必要があります。 -具体的に言えば、その時点でパスが向いている方向を状態として持たなければなりません。 -計算を通じて状態を関数に渡すように変更する必要があります。 -ここでも `lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数 `s`を使用してそれを表しています。 - -型 `s`を追加する必要があるのは3箇所で、次のようになります。 - -```haskell -forall a s. Array a - -> (a -> Array a) - -> (s -> a -> Effect s) - -> Int - -> s - -> Effect s -``` - -まず追加の引数の型として `lsystem`に型 `s`が追加されています。 -この引数はL-Systemの初期状態を表しています。 - -型 -`s`は引数にも現れますが、解釈関数(`lsystem`の第3引数)の返り値の型としても現れます。解釈関数は今のところ、引数としてL-Systemの現在の状態を受け取り、返り値として更新された新しい状態を返します。 - -この例の場合では、次のような型を使って状態を表す型を定義できます。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:state}} -``` - -プロパティ `x`と `y`はパスの現在の位置を表しています。 -プロパティ`theta`はパスの現在の向きを表しており、ラジアンで表された水平線に対するパスの角度として指定されています。 - -システムの初期状態は次のように指定されます。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:initialState}} -``` - -それでは、 `lsystem`関数を実装してみます。定義はとても単純であることがわかるでしょう。 - -`lsystem`は第4引数の値(型は`Int`)に応じて再帰するのが良さそうです。 -再帰の各ステップでは、生成規則に従って状態が更新され、現在の文が変化していきます。 -このことを念頭に置きつつ、まずは関数の引数の名前を導入して、補助関数に処理を移譲することから始めましょう。 - -```haskell -lsystem :: forall a s - . Array a - -> (a -> Array a) - -> (s -> a -> Effect s) - -> Int - -> s - -> Effect s -{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_impl}} -``` - -`go`関数は第2引数に応じて再帰することで動作します。 -場合分けは2つであり、`n`がゼロであるときと `n`がゼロでないときです。 - -1つ目の場合は再帰は完了し、解釈関数に応じて現在の文を解釈します。 -型`Array a`の文、型 `s`の状態、型 `s -> a -> Effect s`の関数があります。 -以前定義した `foldM`でやったことみたいです。 -この関数は`control`パッケージで手に入ります。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_0}} -``` - -ゼロでない場合ではどうでしょうか。 -その場合は、単に生成規則を現在の文のそれぞれの文字に適用して、その結果を連結し、そして再帰的に`go`を呼び出すことによって繰り返します。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_i}} -``` - -これだけです。 -`foldM`や `concatMap`のような高階関数を使うと、このようにアイデアを簡潔に表現できるのです。 - -しかし、話はこれで終わりではありません。 -ここで与えた型は、実際はまだ特殊化されすぎています。 -この定義ではcanvasの操作が実装のどこにも使われていないことに注目してください。 -それに、全く`Effecta`モナドの構造を利用していません。 -実際には、この関数は*どんな*モナド`m`についても動作します。 - -この章に添付されたソースコードで指定されている`lsystem`の型はもっと一般的になっています。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_anno}} -``` - -この型で書かれていることは、この解釈関数はモナド `m`が持つ任意の副作用を完全に自由に持つことができる、ということだと理解できます。 -キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれませんし、失敗や複数の戻り値に対応しているかもしれません。 -こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めします。 - -この関数は実装からデータを分離することの威力を示す良い例となっています。 -この手法の利点は、複数の異なる方法でデータを解釈する自由が得られることです。 -`lsystem`は2つの小さな関数へと分解さえできるかもしれません。 -1つ目は `concatMap`の適用の繰り返しを使って文を構築するもので、2つ目は `foldM`を使って文を解釈するものです。 -これは読者の演習として残しておきます。 - -それでは解釈関数を実装して、この章の例を完成させましょう。 -`lsystem`の型が教えてくれているのは、型シグネチャが、何らかの型 `a`と `s`、型構築子 `m`について、 `s -> a -> m s`でなければならないということです。 -`a`を `Letter`、 `s`を `State`、モナド `m`を `Effect`というように選びたいということがわかっています。 -これにより次のような型になります。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpret_anno}} -``` - -この関数を実装するには、 `Letter`型の3つのデータ構築子それぞれについて処理する必要があります。文字 `L`(左回転)と -`R`(右回転)の解釈では、`theta`を適切な角度へ変更するように状態を更新するだけです。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} -``` - -文字 `F`(前進)を解釈するには、パスの新しい位置を計算し、線分を描画し、状態を次のように更新します。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretF}} -``` - -なおこの章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`関数は `main`関数内で -`let`束縛を使用して定義されています。 -`State`型がコンテキストを持つように変更できるでしょうが、それはこのシステムの状態の変化する部分ではないので不適切でしょう。 - -このL-Systemを描画するには、次のような `strokePath`アクションを使用するだけです。 - -```haskell -{{#include ../exercises/chapter12/src/Example/LSystem.purs:strokePath}} -``` - -次のコマンドを使ってL-Systemをコンパイルします。 - -```text -$ spago bundle-app --main Example.LSystem --to dist/Main.js -``` - -`html/index.html`を開いてみましょう。 -キャンバスにコッホ曲線が描画されるのがわかると思います。 - -## 演習 - - 1. (簡単)`strokePath`の代わりに `fillPath`を使用するように、上のL-Systemの例を変更してください。 - *手掛かり*:`closePath`の呼び出しを含め、 `moveTo`の呼び出しを `interpret`関数の外側に移動する必要があります。 - 1. (簡単)描画システムへの影響を理解するために、コード中の様々な数値の定数を変更してみてください。 - 1. (普通)`lsystem`関数を2つの小さな関数に分割してください。 - 1つ目は`concatMap`の適用の繰り返しを使用して最終的な文を構築するもので、2つ目は - `foldM`を使用して結果を解釈するものでなくてはなりません。 - 1. (普通)`setShadowOffsetX`アクション、 - `setShadowOffsetY`アクション、`setShadowBlur`アクション、 - `setShadowColor`アクションを使い、塗りつぶされた図形にドロップシャドウを追加してください。 - *手掛かり*:PSCiを使って、これらの関数の型を調べてみましょう。 - 1. (普通)向きを変えるときの角度の大きさは今のところ一定 (`tau/6`) です。 - これに代えて、`Letter`データ型の中に角度を移動させ、生成規則によって変更できるようにしてください。 - - ```haskell - type Angle = Number - - data Letter = L Angle | R Angle | F - ``` - - 生成規則でこの新しい情報を使うと、どんな面白い図形を作ることができるでしょうか。 -1. (難しい)`L`(60度左回転)、 `R`(60度右回転)、`F`(前進)、 `M`(これも前進)という4つの文字からなるアルファベットでL-Systemが与えられたとします。 - - このシステムの文の初期状態は、単一の文字 `M`です。 - - このシステムの生成規則は次のように指定されています。 - - ```text - L -> L - R -> R - F -> FLMLFRMRFRMRFLMLF - M -> MRFRMLFLMLFLMRFRM - ``` - - このL-Systemを描画してください。 - *補足*:最後の文のサイズは反復回数に従って指数関数的に増大するので、生成規則の繰り返しの回数を削減する必要があります。 - - ここで、生成規則における `L`と `M`の間の対称性に注目してください。2つの「前進」命令は、次のようなアルファベット型を使用すると、`Boolean`値を使って区別できます。 - - ```haskell - data Letter = L | R | F Boolean - ``` - - このアルファベットの表現を使用して、もう一度このL-Systemを実装してください。 -1. (難しい)解釈関数で別のモナド `m`を使ってみましょう。`Effect.Console`作用を利用してコンソール上にL-Systemを出力したり、`Random`作用を利用して状態の型に無作為の「突然変異」を適用したりしてみてください。 - -## まとめ - -この章では、 `canvas`ライブラリを使用することにより、PureScriptからHTML5 Canvas APIを使う方法について学びました。 -また、これまで学んできた手法の多くを利用した実用的な例について見ました。 -マップや畳み込み、レコードと行多相、副作用を扱うための `Effect`モナドなどです。 - -この章の例では、高階関数の威力を示すとともに、 _実装からのデータの分離_ -も実演してみせました。これは例えば、代数データ型を使用してこれらの概念を次のように拡張し、描画関数からシーンの表現を完全に分離できるようになります。 - -```haskell -data Scene - = Rect Rectangle - | Arc Arc - | PiecewiseLinear (Array Point) - | Transformed Transform Scene - | Clipped Rectangle Scene - | ... -``` - -この手法は `drawing`パッケージでも採用されており、描画前にさまざまな方法でデータとしてシーンを操作できる柔軟性をもたらしています。 - -canvasに描画されるゲームの例については[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 deleted file mode 100644 index 0fb359ed..00000000 --- a/text-ja/chapter13.md +++ /dev/null @@ -1,480 +0,0 @@ -# テストの自動生成 - -## この章の目標 - -この章では、テスティングの問題に対する、型クラスの特に洗練された応用について示します。 -*どのように*テストするのかをコンパイラに教えるのではなく、コードが*どのような*性質を持っているべきかを教えることでテストします。 -型クラスを使って無作為データ生成のための紋切り型なコードを書かずして、テスト項目を仕様から無作為に生成できます。 -これは*生成的テスティング*(generative testing、または*property-based -testing*)と呼ばれ、Haskellの[QuickCheck](http://wiki.haskell.org/Introduction_to_QuickCheck1)ライブラリによって普及した手法です。 - -`quickcheck`パッケージはHaskellのQuickCheckライブラリをPureScriptにポーティングしたもので、型や構文はもとのライブラリとほとんど同じようになっています。 -`quickcheck`を使って簡単なライブラリをテストし、Spagoでテストスイートを自動化されたビルドに統合する方法を見ていきます。 - -## プロジェクトの準備 - -この章のプロジェクトには依存関係として `quickcheck`が追加されます。 - -Spagoプロジェクトでは、テストソースは `test`ディレクトリに置かれ、テストスイートのメインモジュールは -`Test.Main`と名づけられます。 テストスイートは、 `spago test`コマンドを使用して実行できます。 - -## 性質を書く - -`Merge`モジュールでは簡単な関数 `merge`が実装されています。 -これを`quickcheck`ライブラリの機能を実演するために使っていきます。 - -```haskell -merge :: Array Int -> Array Int -> Array Int -``` - -`merge`は2つの整列された整数の配列を取って、結果が整列されるように要素を統合します。 -例えば次のようになります。 - -```text -> import Merge -> merge [1, 3, 5] [2, 4, 5] - -[1, 2, 3, 4, 5, 5] -``` - -典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成し、結果が正しい値と等しいことを確認することでテストを実施します。 -しかし、 `merge`関数について知る必要があるものは全て、この性質に要約できます。 - -- `xs`と`ys`が整列済みなら、`merge xs ys`は両方の配列が一緒に結合されて整列された結果になります。 - -`quickcheck`では、無作為なテスト項目を生成することで、直接この性質をテストできます。 -コードが持つべき性質を関数として述べるだけです。 -この場合は1つの性質があります。 - -```haskell -main = do - quickCheck \xs ys -> - eq (merge (sort xs) (sort ys)) (sort $ xs <> ys) -``` - -このコードを実行すると、 `quickcheck`は無作為な入力 `xs`と -`ys`を生成してこの関数に渡すことで、主張しようとしている性質を反証しようとします。 -何らかの入力に対して関数が `false`を返した場合、性質は正しくないことが示され、ライブラリはエラーを発生させます。 -幸いなことに、次のように100個の無作為なテスト項目を生成しても、ライブラリはこの性質を反証できません。 - -```text -$ spago test - -Installation complete. -Build succeeded. -100/100 test(s) passed. -... -Tests succeeded. -``` - -もし -`merge`関数に意図的にバグを混入した場合(例えば、大なりのチェックを小なりのチェックへと変更するなど)、最初に失敗したテスト項目の後で例外が実行時に投げられます。 - -```text -Error: Test 1 failed: -Test returned false -``` - -見ての通りこのエラーメッセージではあまり役に立ちませんが、少し工夫するだけで改良できます。 - -## エラーメッセージの改善 - -テスト項目が失敗した時に同時にエラーメッセージを提供する上で、`quickcheck`は``演算子を提供しています。 -次のように性質の定義とエラー文言を``で区切って書くだけです。 - -```haskell -quickCheck \xs ys -> - let - result = merge (sort xs) (sort ys) - expected = sort $ xs <> ys - in - eq result expected "Result:\n" <> show result <> "\nnot equal to expected:\n" <> show expected -``` - -このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗したときに改良されたエラーメッセージが表示されます。 - -```text -Error: Test 1 (seed 534161891) failed: -Result: -[-822215,-196136,-116841,618343,887447,-888285] -not equal to expected: -[-888285,-822215,-196136,-116841,618343,887447] -``` - -入力 `xs`が無作為に選ばれた数の配列として生成されていることに注目してください。 - -## 演習 - - 1. (簡単)配列に空の配列を統合しても元の配列は変更されないことを確かめる性質を書いてください。 - *補足*:この新しい性質は冗長です。 - というのもこの状況は既に既存の性質で押さえられているからです。 - ここでは読者がQuickCheckを使う練習のための簡単なやり方を示そうとしているだけです。 - 1. (簡単)`merge`の残りの性質に対して、適切なエラーメッセージを追加してください。 - -## 多相的なコードのテスト - -`Merge`モジュールでは、数の配列だけでなく、 `Ord`型クラスに属するどんな型の配列に対しても動作する、 `merge`関数を一般化した -`mergePoly`という関数が定義されています。 - -```haskell -mergePoly :: forall a. Ord a => Array a -> Array a -> Array a -``` - -`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエラーメッセージが表示されます。 - -```text -No type class instance was found for - - Test.QuickCheck.Arbitrary.Arbitrary t0 - -The instance head contains unknown type variables. -Consider adding a type annotation. -``` - -このエラーメッセージは、配列に持たせたい要素の型が何なのかわからないので、コンパイラが無作為なテスト項目を生成できなかったということを示しています。 -このような場合、型註釈を使ってコンパイラが特定の型を推論するように強制できます。 -例えば`Array Int`などです。 - -```haskell -quickCheck \xs ys -> - eq (mergePoly (sort xs) (sort ys) :: Array Int) (sort $ xs <> ys) -``` - -代替案として型を指定する補助関数を使うこともできます。 -こうするとより見通しのよいコードになることがあります。 -例えば同値関数の同義な関数`ints`を定義したとしましょう。 - -```haskell -ints :: Array Int -> Array Int -ints = id -``` - -それから、コンパイラが引数の2つの配列の型 `Array Int`を推論するように、テストを変更します。 - -```haskell -quickCheck \xs ys -> - eq (ints $ mergePoly (sort xs) (sort ys)) (sort $ xs <> ys) -``` - -ここで、 `ints`関数が不明な型を解消するために使われているため、 `xs`と `ys`はどちらも型 `Array Int`を持っています。 - -## 演習 - - 1. (簡単)`xs`と `ys`の型を `Array Boolean`に強制する関数 `bools`を書き、 - `mergePoly`をその型でテストする性質を追加してください。 - 1. (普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエラーメッセージを含めてQuickCheckの性質を書いてください。 - その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定しなければいけません。 - -## 任意のデータの生成 - -`quickcheck`ライブラリを使って性質に対するテスト項目を無作為に生成する方法について説明します。 - -無作為に値を生成できるような型は、次のような型クラス `Arbitary`のインスタンスを持っています。 - -```haskell -class Arbitrary t where - arbitrary :: Gen t -``` - -`Gen`型構築子は*決定的無作為データ生成*の副作用を表しています。 -決定的無作為データ生成は、擬似乱数生成器を使って、シード値から決定的無作為関数の引数を生成します。 -`Test.QuickCheck.Gen`モジュールは、生成器を構築するための幾つかの有用なコンビネータを定義しています。 - -`Gen`はモナドでもアプリカティブ関手でもあるので、 -`Arbitary`型クラスの新しいインスタンスを作成するのに、いつも使っているようなコンビネータを自由に使うことができます。 - -例えば、 `quickcheck`ライブラリで提供されている `Int`型用の -`Arbitrary`インスタンスを使い、256個のバイト値上の分布を作ることができます。 -これには`Gen`用に`Functor`インスタンスを使って整数から任意の整数値のバイトまでマップします。 - -```haskell -newtype Byte = Byte Int - -instance Arbitrary Byte where - arbitrary = map intToByte arbitrary - where - intToByte n | n >= 0 = Byte (n `mod` 256) - | otherwise = intToByte (-n) -``` - -ここでは、0から255までの間の整数値であるような型 `Byte`を定義しています。 -`Arbitrary`インスタンスは `map`演算子を使って、 `intToByte`関数を `arbitrary`アクションまで持ち上げています。 -`arbitrary`アクション内部の型は `Gen Int`と推論されます。 - -この考え方を `merge`用のテストに使うこともできます。 - -```haskell -quickCheck \xs ys -> - eq (numbers $ mergePoly (sort xs) (sort ys)) (sort $ xs <> ys) -``` - -このテストでは、任意の配列 `xs`と `ys`を生成しますが、 `merge`は整列済みの入力を期待しているので、 `xs`と -`ys`を整列しておかなければなりません。 -一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する `Arbitrary`インスタンスを書くこともできます。 - -```haskell -newtype Sorted a = Sorted (Array a) - -sorted :: forall a. Sorted a -> Array a -sorted (Sorted xs) = xs - -instance (Arbitrary a, Ord a) => Arbitrary (Sorted a) where - arbitrary = map (Sorted <<< sort) arbitrary -``` - -この型構築子を使うと、テストを次のように変更できます。 - -```haskell -quickCheck \xs ys -> - eq (ints $ mergePoly (sorted xs) (sorted ys)) (sort $ sorted xs <> sorted ys) -``` - -これは些細な変更に見えるかもしれませんが、 `xs`と `ys`の型はただの `Array Int`から `Sorted Int`へと変更されています。 -これにより、 `mergePoly`関数は整列済みの入力を取る、という*意図*を、わかりやすく示すことができます。 -理想的には、 `mergePoly`関数自体の型が `Sorted`型構築子を使うようにするといいでしょう。 - -より興味深い例として、 `Tree`モジュールでは枝の値で整列された二分木の型が定義されています。 - -```haskell -data Tree a - = Leaf - | Branch (Tree a) a (Tree a) -``` - -`Tree`モジュールでは次のAPIが定義されています。 - -```haskell -insert :: forall a. Ord a => a -> Tree a -> Tree a -member :: forall a. Ord a => a -> Tree a -> Boolean -fromArray :: forall a. Ord a => Array a -> Tree a -toArray :: forall a. Tree a -> Array a -``` - -`insert`関数は新しい要素を整列済みの二分木に挿入するのに使われ、 `member`関数は特定の値の有無を木に問い合わせるのに使われます。 -例えば次のようになります。 - -```text -> import Tree - -> member 2 $ insert 1 $ insert 2 Leaf -true - -> member 1 Leaf -false -``` - -`toArray`関数と `fromArray`関数は、整列された木と整列された配列を相互に変換するために使われます。 -`fromArray`を使うと、木についての `Arbitrary`インスタンスを書くことができます。 - -```haskell -instance (Arbitrary a, Ord a) => Arbitrary (Tree a) where - arbitrary = map fromArray arbitrary -``` - -型 `a`についての`Arbitary`インスタンスが使えるなら、テストする性質の引数の型として `Tree a`を使うことができます。例えば、 -`member`テストは値を挿入した後は常に `true`を返すことをテストできます。 - -```haskell -quickCheck \t a -> - member a $ insert a $ treeOfInt t -``` - -ここでは、引数 `t`は `Tree Number`型の無作為に生成された木です。 -型引数は、同値関数 `treeOfInt`によって明確にされています。 - -## 演習 - - 1. (普通)`a-z`の範囲から無作為に選ばれた文字の集まりを生成する - `Arbitrary`インスタンスを持つ、`String`のnewtypeを作ってください。 - *手掛かり*:`Test.QuickCheck.Gen`モジュールから `elements`と `arrayOf`関数を使います。 - 1. (難しい)木に挿入された値は、どれだけ挿入があった後でも、その木の構成要素であることを主張する性質を書いてください。 - -## 高階関数のテスト - -`Merge`モジュールは `merge`関数の別の一般化も定義しています。 -`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を決定するのに使われます。 -つまり `mergeWith`は高階関数です。 - -例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列を統合できます。 -このとき、結果も長さの昇順になっていなければなりません。 - -```haskell -> import Data.String - -> mergeWith length - ["", "ab", "abcd"] - ["x", "xyz"] - -["","x","ab","xyz","abcd"] -``` - -このような関数をテストするにはどうしたらいいでしょうか。 -理想的には、関数である最初の引数を含めた、3つの引数全てについて、値を生成したいと思うでしょう。 - -関数を無作為に生成できるようにする、もう1つの型クラスがあります。 -この型クラスは `Coarbitrary`と呼ばれており、次のように定義されています。 - -```haskell -class Coarbitrary t where - coarbitrary :: forall r. t -> Gen r -> Gen r -``` - -`coarbitrary`関数は、型 `t`と、関数の結果の型 `r`についての乱数生成器を関数の引数としてとり、乱数生成器を _かき乱す_ -のにこの引数を使います。つまり関数の引数を使って、乱数生成器の無作為な出力を変更しているのです。 - -また、もし関数の定義域が `Coarbitrary`で、値域が -`Arbitrary`なら、`Arbitrary`の関数を与える型クラスインスタンスが存在します。 - -```haskell -instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b) -``` - -実は、これが意味しているのは、引数として関数を取るような性質を記述できるということです。 -`mergeWith`関数の場合では、新しい引数を考慮するようにテストを修正すると、最初の引数を無作為に生成できます。 - -結果が整列されていることは保証できません。 -必ずしも`Ord`インスタンスを持っているとさえ限らないのです。 -しかし、引数として渡す関数 `f`に従って結果が整列されていることは期待されます。 -更に、2つの入力配列が `f`に従って整列されている必要がありますので、`sortBy`関数を使って関数 `f`が適用されたあとの比較に基づいて -`xs`と`ys`を整列します。 - -```haskell -quickCheck \xs ys f -> - let - result = - map f $ - mergeWith (intToBool f) - (sortBy (compare `on` f) xs) - (sortBy (compare `on` f) ys) - expected = - map f $ - sortBy (compare `on` f) $ xs <> ys - in - eq result expected -``` - -ここでは、関数 `f`の型を明確にするために、関数 `intToBool`を使用しています。 - -```haskell -intToBool :: (Int -> Boolean) -> Int -> Boolean -intToBool = id -``` - -関数は `Arbitrary`であるだけでなく `Coarbitrary`でもあります。 - -```haskell -instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b) -``` - -これは値の生成が単純な関数だけに限定されるものではないことを意味しています。 -つまり*高階関数*や、引数が高階関数であるような関数もまた、無作為に生成できるのです。 - -## Coarbitraryのインスタンスを書く - -`Gen`の `Monad`や `Applicative`インスタンスを使って独自のデータ型に対して -`Arbitrary`インスタンスを書くことができるのとちょうど同じように、独自の `Coarbitrary`インスタンスを書くこともできます。 -これにより、無作為に生成される関数の定義域として、独自のデータ型を使うことができるようになります。 - -`Tree`型の `Coarbitrary`インスタンスを書いてみましょう。 -枝に格納されている要素の型に `Coarbitrary`インスタンスが必要になります。 - -```haskell -instance Coarbitrary a => Coarbitrary (Tree a) where -``` - -型 `Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があります。 -入力値が `Leaf`であれば、そのままにしておく生成器を返します。 - -```haskell - coarbitrary Leaf = id -``` - -もし木が `Branch`なら、左の部分木、値、右の部分木を使って生成器をかき乱します。 -関数合成を使って独自のかき乱し関数を作ります。 - -```haskell - coarbitrary (Branch l a r) = - coarbitrary l <<< - coarbitrary a <<< - coarbitrary r -``` - -これで、木を引数にとるような関数を引数に含む性質を自由に書くことができるようになりました。 -例えば`Tree`モジュールでは`anywhere`が定義されており、これは述語が引数のどんな部分木についても成り立っているかを調べる関数です。 - -```haskell -anywhere :: forall a. (Tree a -> Boolean) -> Tree a -> Boolean -``` - -これで、この述語関数`anywhere`を無作為に生成できるようになりました。 -例えば、 `anywhere`関数は*ある命題のもとで不変*であることが期待されます。 - -```haskell -quickCheck \f g t -> - anywhere (\s -> f s || g s) t == - anywhere f (treeOfInt t) || anywhere g t -``` - -ここで、 `treeOfInt`関数は木に含まれる値の型を型 `Int`に固定するために使われています。 - -```haskell -treeOfInt :: Tree Int -> Tree Int -treeOfInt = id -``` - -## 副作用のないテスト - -通常、テストの目的ではテストスイートの `main`アクションに`quickCheck`関数の呼び出しが含まれています。 -しかし、副作用を使わない`quickCheckPure`と呼ばれる `quickCheck`関数の亜種もあります。 -`quickCheckPure`は、入力として乱数の種をとり、テスト結果の配列を返す純粋な関数です。 - -PSCiを使用して `quickCheckPure`を試せます。 -ここでは `merge`操作が結合法則を満たすことをテストします。 - -```text -> import Prelude -> import Merge -> import Test.QuickCheck -> import Test.QuickCheck.LCG (mkSeed) - -> :paste -… quickCheckPure (mkSeed 12345) 10 \xs ys zs -> -… ((xs `merge` ys) `merge` zs) == -… (xs `merge` (ys `merge` zs)) -… ^D - -Success : Success : ... -``` - -`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数をとります。 -もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出力されます。 - -`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションのフォームデータ例を無作為に生成するというような状況で便利かもしれません。 - -## 演習 - - 1. (簡単)`Byte`と `Sorted`型構築子についての `Coarbitrary`インスタンスを書いてください。 - 1. (普通)任意の関数 `f`について、 `mergeWith f`関数の結合性を主張する(高階)性質を書いてください。 - `quickCheckPure`を使ってPSCiでその性質をテストしてください。 - 1. (普通)次のデータ型の`Arbitrary`と`Coarbitrary`インスタンスを書いてください。 - - ```haskell - data OneTwoThree a = One a | Two a a | Three a a a - ``` - - *手掛かり*:`Test.QuickCheck.Gen`で定義された `oneOf`関数を使って `Arbitrary`インスタンスを定義してください。 - 1. (普通)`all`を使って `quickCheckPure`関数の結果を単純化してください。 - この新しい関数は型`List Result -> Boolean`を持ち、全てのテストが通れば`true`を、そうでなければ`false`を返します。 - 2. (普通)`quickCheckPure`の結果を単純にする別の手法として、関数`squashResults :: List Result -> Result`を書いてみてください。 - `Data.Maybe.First`の`First`モノイドと共に`foldMap`関数を使うことで、失敗した場合の最初のエラーを保存することを検討してください。 - -## まとめ - -この章では`quickcheck`パッケージに出会いました。 -これを使うと*生成的テスティング*のパラダイムを使って、宣言的な方法でテストを書くことができました。具体的には以下です。 - -- `spago test`を使ってQuickCheckのテストを自動化する方法を見ました。 -- 性質を関数として書く方法とエラーメッセージを改良する ``演算子の使い方を説明しました。 -- `Arbitrary`と - `Coarbitrary`型クラスによって、如何にして定型的なテストコードの自動生成を可能にし、またどうすれば高階な性質関数が可能になるかを見てきました。 -- 独自のデータ型に対して `Arbitrary`と `Coarbitrary`インスタンスを実装する方法を見ました。 diff --git a/text-ja/chapter14.md b/text-ja/chapter14.md deleted file mode 100644 index 96dff977..00000000 --- a/text-ja/chapter14.md +++ /dev/null @@ -1,827 +0,0 @@ -# 領域特化言語 - -## この章の目標 - -この章では多数の標準的な手法を使い、PureScriptにおける*領域特化言語*(または*DSL*)の実装について探求していきます。 - -領域特化言語とは、特定の問題領域での開発に適した言語のことです。 -領域特化言語の構文及び機能は、その領域内の考え方を表現するコードの読みやすさを最大限に発揮すべく選択されます。 -本書の中では、既に領域特化言語の例を幾つか見てきています。 - -- 第11章で開発された `Game`モナドと関連するアクションは、 _テキストアドベンチャーゲーム開発_ - という領域に対しての領域特化言語を構成しています。 -- 第13章で扱った `quickcheck`パッケージは、 _生成的テスティング_ - の領域の領域特化言語です。このコンビネータはテストの性質に対して特に表現力の高い記法を可能にします。 - -この章では、領域特化言語の実装において、幾つかの標準的な技法による構造的な手法に迫ります。 -これがこの話題の完全な説明だということでは決してありませんが、自分の目的に合う具体的なDSLを構築するのには充分な知識をもたらすことでしょう。 - -この章で実行している例は、HTML文書を作成するための領域特化言語です。 -正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装を徐々に改善しつつ進めていきます。 - -## プロジェクトの準備 - -この章で使うプロジェクトには新しい依存性が1つ追加されます。これから使う道具の1つである*Freeモナド*が定義されている `free`ライブラリです。 - -このプロジェクトをPSCiを使って試していきます。 - -## HTMLデータ型 - -このHTMLライブラリの最も基本的なバージョンは -`Data.DOM.Simple`モジュールで定義されています。このモジュールには次の型定義が含まれています。 - -```haskell -newtype Element = Element - { name :: String - , attribs :: Array Attribute - , content :: Maybe (Array Content) - } - -data Content - = TextContent String - | ElementContent Element - -newtype Attribute = Attribute - { key :: String - , value :: String - } -``` - -`Element`型はHTMLの要素を表しています。 -各要素は要素名、属性の対の配列と、要素の内容で構成されています。 -contentプロパティは、`Maybe`タイプを適切に使って、要素が開いている(他の要素やテキストを含む)か閉じているかを示しています。 - -このライブラリの鍵となる機能は次の関数です。 - -```haskell -render :: Element -> String -``` - -この関数はHTML要素をHTML文字列として出力します。 -PSCiで明示的に適当な型の値を構築し、ライブラリのこのバージョンを試してみましょう。 - -```text -$ spago repl - -> import Prelude -> import Data.DOM.Simple -> import Data.Maybe -> import Effect.Console - -> :paste -… log $ render $ Element -… { name: "p" -… , attribs: [ -… Attribute -… { key: "class" -… , value: "main" -… } -… ] -… , content: Just [ -… TextContent "Hello World!" -… ] -… } -… ^D - -

Hello World!

-unit -``` - -現状のライブラリには幾つもの問題があります。 - -- HTML文書の作成に手がかかります。 - 全ての新しい要素に少なくとも1つのレコードと1つのデータ構築子が必要です。 -- 無効な文書を表現できてしまいます。 - - 開発者が要素名の入力を間違えるかもしれません - - 開発者が属性を間違った要素に関連付けることができてしまいます - - 開いた要素が正しい場合に開発者が閉じた要素を使えてしまいます - -残りの章ではとある手法を用いてこれらの問題を解決し、このライブラリーをHTML文書を作成するために使える領域特化言語にしていきます。 - -## スマート構築子 - -最初に導入する手法は方法こそ単純なものですが、とても効果的です。 -モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリストを使ってデータ構築子 `Element`、 `Content`、 -`Attribute`を隠蔽し、正しいことが明らかなデータだけ構築する、いわゆる*スマート構築子*だけをエクスポートします。 - -例を示しましょう。まず、HTML要素を作成するための便利な関数を提供します。 - -```haskell -element :: String -> Array Attribute -> Maybe (Array Content) -> Element -element name attribs content = Element - { name: name - , attribs: attribs - , content: content - } -``` - -次に、欲しいHTML要素を利用者が作れるように、スマート構築子を作成します。 -これには`element`関数を適用します。 - -```haskell -a :: Array Attribute -> Array Content -> Element -a attribs content = element "a" attribs (Just content) - -p :: Array Attribute -> Array Content -> Element -p attribs content = element "p" attribs (Just content) - -img :: Array Attribute -> Element -img attribs = element "img" attribs Nothing -``` - -最後に、正しいデータ構造だけが構築されることがわかっているこれらの関数をエクスポートするように、モジュールエクスポートリストを更新します。 - -```haskell -module Data.DOM.Smart - ( Element - , Attribute(..) - , Content(..) - - , a - , p - , img - - , render - ) where -``` - -モジュールエクスポートリストはモジュール名の直後の括弧内に書きます。 -各モジュールのエクスポートは次の3種類の何れかになります。 - -- 値(ないし関数)。その値の名前により指定されます。 -- 型クラス。クラス名により指定されます。 -- 型構築子と関連するデータ構築子。型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定されます。 - -ここでは、 `Element`の*型*をエクスポートしていますが、データ構築子はエクスポートしていません。 -もしデータ構築子をエクスポートすると、モジュールの使用者が不正なHTML要素を構築できてしまいます。 - -`Attribute`と `Content`型についてはデータ構築子を全てエクスポートしています(エクスポートリストの記号 `..`で示されています)。 -すぐ後で、これらの型にもスマート構築子の手法を適用していきます。 - -既にライブラリに幾つもの大きな改良が加わっていることに注目です。 - -- 不正な名前を持つHTML要素は表現できません(もちろん、ライブラリが提供する要素名に制限されています)。 -- 閉じた要素は構築するときに内容を含められません。 - -`Content`型にとても簡単にこの手法を適用できます。 -単にエクスポートリストから `Content`型のデータ構築子を取り除き、次のスマート構築子を提供します。 - -```haskell -text :: String -> Content -text = TextContent - -elem :: Element -> Content -elem = ElementContent -``` - -`Attribute`型にも同じ手法を適用してみましょう。 -まず、属性のための汎用のスマート構築子を用意します。 -以下は最初の試行です。 - -```haskell -attribute :: String -> String -> Attribute -attribute key value = Attribute - { key: key - , value: value - } - -infix 4 attribute as := -``` - -この定義では元の `Element`型と同じ問題に直面しています。 -存在しなかったり、名前が間違っているような属性を表現できます。 -この問題を解決するために、属性名を表すnewtypeを作成します。 - -```haskell -newtype AttributeKey = AttributeKey String -``` - -これを使えば演算子を次のように変更できます。 - -```haskell -attribute :: AttributeKey -> String -> Attribute -attribute (AttributeKey key) value = Attribute - { key: key - , value: value - } -``` - -`AttributeKey`データ構築子をエクスポートしなければ、明示的にエクスポートされた次のような関数を使う以外に、使用者が型 -`AttributeKey`の値を構築する方法はありません。 -以下に幾つかの例を示します。 - -```haskell -href :: AttributeKey -href = AttributeKey "href" - -_class :: AttributeKey -_class = AttributeKey "class" - -src :: AttributeKey -src = AttributeKey "src" - -width :: AttributeKey -width = AttributeKey "width" - -height :: AttributeKey -height = AttributeKey "height" -``` - -新しいモジュールの最終的なエクスポートリストは次のようになります。 -最早どのデータ構築子も直接エクスポートしていない点に注目です。 - -```haskell -module Data.DOM.Smart - ( Element - , Attribute - , Content - , AttributeKey - - , a - , p - , img - - , href - , _class - , src - , width - , height - - , attribute, (:=) - , text - , elem - - , render - ) where -``` - -PSCiでこの新しいモジュールを試してみると、既にコードの簡潔さにおいて大幅な向上が見て取れます。 - -```text -$ spago repl - -> import Prelude -> import Data.DOM.Smart -> import Effect.Console -> log $ render $ p [ _class := "main" ] [ text "Hello World!" ] - -

Hello World!

-unit -``` - -しかし、基盤をなすデータ表現は変更されなかったので、 `render`関数を変更する必要はなかったことにも注目してください。 -これはスマート構築子による手法の利点のひとつです。 -外部APIの使用者によって認識される表現からモジュールの内部データ表現を分離できるのです。 - -## 演習 - - 1. (簡単)`Data.DOM.Smart`モジュールで `render`を使った新しいHTML文書の作成を試してみましょう。 - 1. (普通)`checked`と `disabled`など、値を要求しないHTML属性がありますが、これらは次のような _空の属性_ - として表示されるかもしれません。 - - ```html - - ``` - - 空の属性を扱えるように `Attribute`の表現を変更してください。 - 要素に空の属性を追加するための`attribute`または`:=`の代わりに使える関数を記述してください。 - -## 幻影型 - -次の手法の動機付けとして、以下のコードを考えます。 - -```text -> log $ render $ img - [ src := "cat.jpg" - , width := "foo" - , height := "bar" - ] - - -unit -``` - -ここでの問題は、 `width`属性と`height`属性に文字列値を提供しているということです。 -ここで与えることができるのはピクセル単位ないしパーセントの数値だけであるべきです。 - -`AttributeKey`型にいわゆる _幻影型_ (phantom type) 引数を導入すると、この問題を解決できます。 - -```haskell -newtype AttributeKey a = AttributeKey String -``` - -定義の右辺に対応する型 `a`の値が存在しないので、この型変数 `a`は*幻影型*と呼ばれています。 -この型 `a`はコンパイル時に追加の情報を提供するためだけに存在しています。 -型`AttributeKey -a`の任意の値は実行時には単なる文字列ですが、コンパイル時はその値の型により、このキーに関連する値で求められる型がわかります。 - -`attribute`関数の型を次のように変更すれば、`AttributeKey`の新しい形式を考慮するようにできます。 - -```haskell -attribute :: forall a. IsValue a => AttributeKey a -> a -> Attribute -attribute (AttributeKey key) value = Attribute - { key: key - , value: toValue value - } -``` - -ここで、幻影型の引数 `a`は、属性キーと属性値が照応する型を持っていることを確認するために使われます。 -使用者は `AttributeKey -a`の型の値を直接作成できないので(ライブラリで提供されている定数を介してのみ得られます)、全ての属性が構築により正しくなります。 - -なお、`IsValue`制約はキーに関連付けられた値の型が何であれその値を文字列に変換し、生成したHTML内に出力できることを保証します。 -`IsValue`型クラスは次のように定義されています。 - -```haskell -class IsValue a where - toValue :: a -> String -``` - -`String`と `Int`型についての型クラスインスタンスも提供しておきます。 - -```haskell -instance IsValue String where - toValue = id - -instance IsValue Int where - toValue = show -``` - -また、これらの型が新しい型変数を反映するように、 `AttributeKey`定数を更新しなければいけません。 - -```haskell -href :: AttributeKey String -href = AttributeKey "href" - -_class :: AttributeKey String -_class = AttributeKey "class" - -src :: AttributeKey String -src = AttributeKey "src" - -width :: AttributeKey Int -width = AttributeKey "width" - -height :: AttributeKey Int -height = AttributeKey "height" -``` - -これで、不正なHTML文書を表現することが不可能になっていることがわかります。 -また、`width`と `height`属性を表現するのに文字列ではなく数を使うことが強制されていることがわかります。 - -```text -> import Prelude -> import Data.DOM.Phantom -> import Effect.Console - -> :paste -… log $ render $ img -… [ src := "cat.jpg" -… , width := 100 -… , height := 200 -… ] -… ^D - - -unit -``` - -## 演習 - - 1. (簡単)ピクセルまたはパーセントの長さの何れかを表すデータ型を作成してください。 - その型について `IsValue`のインスタンスを書いてください。 - この型を使うように `width`と `height`属性を変更してください。 - 1. (難しい)幻影型を使って真偽値 `true`、 `false`用の最上位の表現を定義することで、 `AttributeKey`が - `disabled`や `checked`のような*空の属性*を表現しているかどうかをエンコードできます。 - - ```haskell - data True - data False - ``` - - 幻影型を使って、使用者が `attribute`演算子を空の属性に対して使うことを防ぐように、前の演習の解答を変更してください。 - -## Freeモナド - -APIに施す最後の変更は、 `Content`型をモナドにしてdo記法を使えるようにするために、 _Freeモナド_ -と呼ばれる構造を使うことです。これによって入れ子になった要素がわかりやすくなるようにHTML文書を構造化できます。以下の代わりに…… - -```haskell -p [ _class := "main" ] - [ elem $ img - [ src := "cat.jpg" - , width := 100 - , height := 200 - ] - , text "A cat" - ] -``` - -このように書くことができるようになります。 - -```haskell -p [ _class := "main" ] $ do - elem $ img - [ src := "cat.jpg" - , width := 100 - , height := 200 - ] - text "A cat" -``` - -しかし、do記法だけがFreeモナドの恩恵だというわけではありません。Freeモナドがあれば、モナドのアクションの _表現_ をその _解釈_ -から分離し、同じアクションに _複数の解釈_ を持たせることさえできます。 - -`Free`モナドは `free`ライブラリの `Control.Monad.Free`モジュールで定義されています。 -PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができます。 - -```text -> import Control.Monad.Free - -> :kind Free -(Type -> Type) -> Type -> Type -``` - -`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示しています。 -実は、`Free`モナドを使えば任意の`Functor`を`Monad`にできます。 - -モナドのアクションの*表現*の定義から始めます。 -こうするには、対応する各モナドアクションそれぞれについて、1つのデータ構築子を持つ `Functor`を作成する必要があります。 -今回の場合、2つのモナドのアクションは `elem`と `text`になります。 -実際には、 `Content`型を次のように変更するだけです。 - -```haskell -data ContentF a - = TextContent String a - | ElementContent Element a - -instance Functor ContentF where - map f (TextContent s x) = TextContent s (f x) - map f (ElementContent e x) = ElementContent e (f x) -``` - -ここで、この `ContentF`型構築子は以前の `Content`データ型とよく似ています。 -しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引数として取るように変更されています。 -`Functor`インスタンスでは、単に各データ構築子で型 `a`の構成要素に関数 `f`を適用します。 - -これにより、新しい`Content`モナドを`Free`モナド用の型シノニムとして定義できます。 -これは最初の型引数として `ContentF`型構築子を使うことで構築されます。 - -```haskell -type Content = Free ContentF -``` - -型シノニムの代わりにnewtypeを使用して、使用者に対してライブラリの内部表現を露出することを避けられます。 -`Content`データ構築子を隠すことで、提供しているモナドのアクションだけを使うことを使用者に制限しています。 - -`ContentF`は `Functor`なので、 `Free ContentF`用の`Monad`インスタンスが自動的に手に入ります。 - -`Content`の新しい型引数を考慮するように`Element`データ型を僅かに変更する必要があります。 -モナドの計算の戻り値の型が `Unit`であることだけが必要です。 - -```haskell -newtype Element = Element - { name :: String - , attribs :: Array Attribute - , content :: Maybe (Content Unit) - } -``` - -また、 `Content`モナドについての新しいモナドのアクションになる `elem`と `text`関数を変更する必要があります。 -これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えます。 -この関数の型は次のようになっています。 - -```haskell -liftF :: forall f a. f a -> Free f a -``` - -`liftF`により、何らかの型 `a`について、型 `f a`の値からFreeモナドのアクションを構築できるようになります。 -今回の場合、 `ContentF`型構築子のデータ構築子をそのまま使うだけです。 - -```haskell -text :: String -> Content Unit -text s = liftF $ TextContent s unit - -elem :: Element -> Content Unit -elem e = liftF $ ElementContent e unit -``` - -他にも同じようなコードの変更はありますが、興味深い変更は `render`関数にあります。ここでは、このFreeモナドを _解釈_ -しなければいけません。 - -## モナドの解釈 - -`Control.Monad.Free`モジュールでは、Freeモナドで計算を解釈するための多数の関数が提供されています。 - -```haskell -runFree - :: forall f a - . Functor f - => (f (Free f a) -> Free f a) - -> Free f a - -> a - -runFreeM - :: forall f m a - . (Functor f, MonadRec m) - => (f (Free f a) -> m (Free f a)) - -> Free f a - -> m a -``` - -`runFree`関数は、 _純粋な_ 結果を計算するために使用されます。 -`runFreeM`関数があればFreeモナドのアクションを解釈するためにモナドが使えます。 - -*補足*:厳密には、より強い`MonadRec`制約を満たすモナド `m`を使用するよう制限されています。 -実際には、これはスタックオーバーフローを心配する必要がないことを意味します。 -なぜなら `m`は安全な*末尾再帰モナド*に対応しているからです。 - -まず、アクションを解釈できるモナドを選ばなければなりません。 -`Writer String`モナドを使って、結果のHTML文字列を累積することにします。 - -新しい`render`メソッドが開始すると、補助関数 -`renderElement`に移譲し、`execWriter`を使って`Writer`モナドで計算を走らせます。 - -```haskell -render :: Element -> String -render = execWriter <<< renderElement -``` - -`renderElement`はwhereブロックで定義されます。 - -```haskell - where - renderElement :: Element -> Writer String Unit - renderElement (Element e) = do -``` - -`renderElement`の定義は直感的で、複数の小さな文字列を累積するために `Writer`モナドの `tell`アクションを使っています。 - -```haskell - tell "<" - tell e.name - for_ e.attribs $ \x -> do - tell " " - renderAttribute x - renderContent e.content -``` - -次に、`renderAttribute`関数を定義します。 -こちらも同じくらい単純です。 - -```haskell - where - renderAttribute :: Attribute -> Writer String Unit - renderAttribute (Attribute x) = do - tell x.key - tell "=\"" - tell x.value - tell "\"" -``` - -`renderContent`関数は、もっと興味深いものです。 -ここでは`runFreeM`関数を使い、Freeモナドの内部で計算を解釈しています。 -計算は補助関数 `renderContentItem`に移譲しています。 - -```haskell - renderContent :: Maybe (Content Unit) -> Writer String Unit - renderContent Nothing = tell " />" - renderContent (Just content) = do - tell ">" - runFreeM renderContentItem content - tell "" -``` - -`renderContentItem`の型は `runFreeM`の型シグネチャから推測できます。 -関手 `f`は型構築子 `ContentF`で、モナド `m`は解釈している計算のモナド、つまり `Writer String`です。 -これにより `renderContentItem`は次の型シグネチャだとわかります。 - -```haskell - renderContentItem :: ContentF (Content Unit) -> Writer String (Content Unit) -``` - -`ContentF`の2つのデータ構築子でパターン照合するだけでこの関数を実装できます。 - -```haskell - renderContentItem (TextContent s rest) = do - tell s - pure rest - renderContentItem (ElementContent e rest) = do - renderElement e - pure rest -``` - -それぞれの場合において、式 `rest`は型 `Content Unit`を持っており、解釈計算の残りを表しています。 -`rest`アクションを呼び出すことによってそれぞれの場合を完了できます。 - -できました。 -PSCiで、次のようにすれば新しいモナドのAPIを試すことができます。 - -```text -> import Prelude -> import Data.DOM.Free -> import Effect.Console - -> :paste -… log $ render $ p [] $ do -… elem $ img [ src := "cat.jpg" ] -… text "A cat" -… ^D - -

A cat

-unit -``` - -## 演習 - - 1. (普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメントを出力する新しいアクション - `comment`に対応してください。 - `liftF`を使ってこの新しいアクションを実装してください。 - 新しい構築子を適切に解釈するように、解釈 `renderContentItem`を更新してください。 - -## 言語の拡張 - -全てのアクションが型 `Unit`の何かを返すようなモナドは、さほど興味深いものではありません。 -実際のところ、概ね良くなったと思われる構文は別として、このモナドは `Monoid`以上の機能を何ら追加していません。 - -非自明な結果を返す新しいモナドアクションでこの言語を拡張することで、Freeモナド構造の威力をお見せしましょう。 - -*アンカー*を使用して文書のさまざまな節へのハイパーリンクが含まれているHTML文書を生成するとします。 -これは既に達成できています。 -手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めればよいのです。 -1つはアンカーの定義自身に、もう1つはそれぞれのハイパーリンクにあります。 -しかし、この方法には根本的な問題が幾つかあります。 - -- 開発者が一意なアンカー名の生成をし損なうかもしれません。 -- 開発者がアンカー名を1つ以上の箇所で打ち間違うかもしれません。 - -開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい一意な名前を生成するためのモナドアクションを提供できます。 - -最初の工程は名前の型を新しく追加することです。 - -```haskell -newtype Name = Name String - -runName :: Name -> String -runName (Name n) = n -``` - -繰り返しになりますが、`Name`は -`String`のnewtypeとして定義しているものの、モジュールのエクスポートリスト内でデータ構築子をエクスポートしないように注意する必要があります。 - -次に、属性値として `Name`を使うことができるように、新しい型に`IsValue`型クラスのインスタンスを定義します。 - -```haskell -instance IsValue Name where - toValue (Name n) = n -``` - -また、次のように `a`要素に現れるハイパーリンク用の新しいデータ型を定義します。 - -```haskell -data Href - = URLHref String - | AnchorHref Name - -instance IsValue Href where - toValue (URLHref url) = url - toValue (AnchorHref (Name nm)) = "#" <> nm -``` - -この新しい型により、`href`属性の型の値を変更して、利用者にこの新しい `Href`型の使用を強制できます。 -また、新しい`name`属性も作成でき、要素をアンカーに変換するのに使えます。 - -```haskell -href :: AttributeKey Href -href = AttributeKey "href" - -name :: AttributeKey Name -name = AttributeKey "name" -``` - -残っている問題は、現在モジュールの使用者が新しい名前を生成する方法がないということです。 -`Content`モナドでこの機能を提供できます。まず、 `ContentF`型構築子に新しいデータ構築子を追加する必要があります。 - -```haskell -data ContentF a - = TextContent String a - | ElementContent Element a - | NewName (Name -> a) -``` - -`NewName`データ構築子は型 `Name`の値を返すアクションに対応しています。データ構築子の引数として `Name`を要求するのではなく、型 `Name -> a`の _関数_ を提供するように使用者に要求していることに注意してください。型 `a`は _計算の残り_ を表していることを思い出すと、この関数は、型 `Name`の値が返されたあとで、計算を継続する方法を提供しているのだとわかります。 - -新しいデータ構築子を考慮するよう、次のように`ContentF`用の`Functor`インスタンスを更新する必要もあります。 - -```haskell -instance Functor ContentF where - map f (TextContent s x) = TextContent s (f x) - map f (ElementContent e x) = ElementContent e (f x) - map f (NewName k) = NewName (f <<< k) -``` - -これで、以前と同じように`liftF`関数を使って新しいアクションを構築できます。 - -```haskell -newName :: Content Name -newName = liftF $ NewName id -``` - -`id`関数を継続として提供していることに注意してください。 -これは型 `Name`の結果を変更せずに返すということを意味しています。 - -最後に、新しいアクションを解釈するために解釈関数を更新する必要があります。 -以前は計算を解釈するために `Writer -String`モナドを使っていましたが、このモナドは新しい名前を生成する能力を持っていないので、何か他のものに切り替えなければなりません。 -`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせることができます。 -型注釈を短く保てるように、この解釈モナドを型同義語として定義しておきます。 - -```haskell -type Interp = WriterT String (State Int) -``` - -ここで、`Int`型の状態は増加していくカウンタとして振舞い、一意な名前を生成するのに使われます。 - -`Writer`と `WriterT`モナドはそれらのアクションを抽象化するのに同じ型クラスメンバを使うので、どのアクションも変更する必要がありません。 -必要なのは、 `Writer String`への参照全てを `Interp`で置き換えることだけです。 -しかし、これを計算するために使われる制御子を変更しなければいけません。 -こうなると単なる`execWriter`の代わりに、ここでも`evalState`を使う必要があります。 - -```haskell -render :: Element -> String -render e = evalState (execWriterT (renderElement e)) 0 -``` - -また、新しい `NewName`データ構築子を解釈するために、 `renderContentItem`に新しい場合を追加しなければいけません。 - -```haskell -renderContentItem (NewName k) = do - n <- get - let fresh = Name $ "name" <> show n - put $ n + 1 - pure (k fresh) -``` - -ここで、型 `Name -> Content a`の継続 `k`が与えられているので、型 `Content a`の解釈を構築しなければいけません。 -この解釈は単純です。 -`get`を使って状態を読み、その状態を使って一意な名前を生成し、それから `put`で状態に1だけ足すのです。 -最後に、継続にこの新しい名前を渡して、計算を完了します。 - -以上をもって、この新しい機能をPSCiで試すことができます。 -これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンクのリンク先の両方として使います。 - -```text -> import Prelude -> import Data.DOM.Name -> import Effect.Console - -> :paste -… render $ p [ ] $ do -… top <- newName -… elem $ a [ name := top ] $ -… text "Top" -… elem $ a [ href := AnchorHref top ] $ -… text "Back to top" -… ^D - -

TopBack to top

-unit -``` - -複数回の `newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめられます。 - -## 演習 - - 1. (普通)使用者から `Element`型を隠蔽すると、更にAPIを簡素にできます。 - 次の手順に従って、これらの変更を加えてください。 - - `p`や `img`のような(返る型が `Element`の)関数を `elem`アクションと結合して、型 `Content - Unit`を返す新しいアクションを作ってください。 - - `Element`の代わりに型`Content Unit`の引数を受け付けるように`render`関数を変更してください。 - 1. (普通)型同義語の代わりに`newtype`を使うことによって`Content`モナドの実装を隠してください。 - `newtype`用のデータ構築子はエクスポートすべきではありません。 - 1. (難しい)`ContentF`型を変更して以下の新しいアクションに対応してください。 - - ```haskell - isMobile :: Content Boolean - ``` - - このアクションは、この文書がモバイルデバイス上での表示のためにレンダリングされているかどうかを示す真偽値を返します。 - - *手掛かり*:`ask`アクションと`ReaderT`モナド変換子を使って、このアクションを解釈してください。 - あるいは、`RWS`モナドを使うほうが好みの人もいるかもしれません。 - -## まとめ - -この章では、幾つかの標準的な技術を使って、素朴な実装を段階的に改善することにより、HTML文書を作成するための領域特化言語を開発しました。 - -- _スマート構築子_ を使ってデータ表現の詳細を隠し、利用者には _構築により正しい_ 文書だけを作ることを許しました。 -- *独自に定義された中置2引数演算子*を使い、言語の構文を改善しました。 -- _幻影型_ を使ってデータの型の中に追加の情報を折り込みました。これにより利用者が誤った型の属性値を与えることを防いでいます。 -- _Freeモナド_ - を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。それからこの表現を新しいモナドアクションに対応するよう拡張し、標準モナド変換子を使ってモナドの計算を解釈しました。 - -これらの手法は全て、使用者が間違いを犯すのを防いだり領域特化言語の構文を改良したりするために、PureScriptのモジュールと型システムを活用しています。 - -関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野ですが、幾つかの簡単な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言語で作業することの威力を示すことができていれば幸いです。 diff --git a/text-ja/chapter2.md b/text-ja/chapter2.md index 2166389b..31854009 100644 --- a/text-ja/chapter2.md +++ b/text-ja/chapter2.md @@ -28,7 +28,14 @@ PureScriptを書く上で(例えば本書の演習を解くなど)お好み git clone https://github.com/purescript-contrib/purescript-book.git ``` -本のリポジトリにはPureScriptのコード例とそれぞれの章に付属する演習のための単体テストが含まれます。演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準備ができます。この工程は`resetSolutions.sh`スクリプトを使えば簡単にできます。また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくのもよいでしょう(これらのアンカーはコードスニペットを本の変換後のMarkdownにコピーするために使われており、自分のローカルリポジトリではこのアンカーで散らかっていないほうがよいでしょう)。 +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 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): ```sh cd purescript-book @@ -55,15 +62,19 @@ spago test All 2 tests passed! 🎉 ``` -なお、`answer`関数(`src/Euler.purs`にあります)は、任意の整数以下の3と5の倍数を見付けるように変更されています。 -この`answer`関数のためのテストスート(`test/Main.purs`にあります)ははじめの手引きの冒頭にあるテストよりも網羅的です。 -はじめの章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い詰めなくて大丈夫です。 +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 +(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. 本の残りの部分には多くの演習が含まれます。 `Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、提供されているテストスートを使って確認できます。 -テスト駆動開発のスタイルでこの次の演習を一緒に進めてみましょう。 +Let's work through this next exercise together in a test-driven-development +style. ## 演習 @@ -71,9 +82,9 @@ All 2 tests passed! 🎉 ## 解法 -この演習のテストを有効にするところから始めます。 -以下に示すようにブロックコメントの開始を数行下に下げてください。 -ブロックコメントは`{-`から始まり`-}`で終わります。 +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 +`{-` and end with `-}`: ```hs {{#include ../exercises/chapter2/test/Main.purs:diagonalTests}} @@ -93,7 +104,8 @@ at test/Main.purs:21:27 - 21:35 (line 21, column 27 - line 21, column 35) Unknown value diagonal ``` -まずは、この関数が欠陥のあるバージョンになっているときに何が起こるのか見てみましょう。以下のコードを`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`: ```hs import Data.Number (sqrt) @@ -147,14 +159,21 @@ All 4 tests passed! 🎉 この章ではPureScriptコンパイラとSpagoツールをインストールしました。 演習の解答の書き方と正しさの確認方法も学びました。 -この先の章にはもっと沢山の演習があり、それらに取り組むうちに学習の助けになっているでしょう。 -演習のどこかでお手上げになったら、この本の[困ったときは](chapter1.ja.md#getting-help)の節に挙げられているコミュニティの資料のどれかを見てみたり、この[本のリポジトリ](https://github.com/purescript-contrib/purescript-book/issues)にイシューを報告したりできます。 -こうした演習の敷居を下げることに繋がる読者のフィードバックが、本の向上の助けになっています。 - -章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べられます。 -ただしカンニングしてはだめで、これらの演習を誠実に自力で解く労力を払わないことがないようにしてください。 -そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるようにしてください。 -演習のネタバレをするよりも、小さな手掛かりをあげたいからです。 -もっとエレガントな解法(とはいえ本の内容で押さえられている知識のみを必要とするもの)を見つけたときはPRを送ってください。 +There will be many more exercises in the chapters ahead, and working through +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. + +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. 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 only requires knowledge of the covered content), +please send us a PR. リポジトリは継続して改訂されているため、それぞれの新しい章を始める前に更新を確認するようにしてください。 diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md deleted file mode 100644 index 3e9e8037..00000000 --- a/text-ja/chapter3.md +++ /dev/null @@ -1,849 +0,0 @@ -# 関数とレコード - -## この章の目標 - -この章では、関数及びレコードというPureScriptプログラムの2つの構成要素を導入します。更に、どのようにPureScriptプログラムを構造化するのか、どのように型をプログラム開発に役立てるかを見ていきます。 - -連絡先のリストを管理する簡単な住所録アプリケーションを作成していきます。 -このコード例により、PureScriptの構文から幾つかの新しい概念を導入します。 - -このアプリケーションのフロントエンドは対話式モードであるPSCiを使うようにしていますが、このコードを土台にJavaScriptでフロントエンドを書くこともできるでしょう。 -実際に後の章で、フォームの検証と保存及び復元の機能を追加します。 - -## プロジェクトの準備 - -この章のソースコードは `src/Data/AddressBook.purs`というファイルに含まれています。 -このファイルは次のようなモジュール宣言とインポート一覧から始まります。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:imports}} -``` - -ここでは、幾つかのモジュールをインポートします。 - -- `Control.Plus`モジュールには`empty`値が定義されています。 -- `Data.List`モジュールは`lists`パッケージで提供されておりSpagoを使ってインストールできます。 - 連結リストを使うために必要な幾つかの関数が含まれています。 -- `Data.Maybe`モジュールは、オプショナルな値を扱うためのデータ型と関数を定義しています。 - -訳者注:ダブルドット (`..`) を使用すると、 -指定された型コンストラクタのすべてのデータコンストラクタをインポートできます。 - -このモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください。明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。 - -ソースコードリポジトリをクローンしたと仮定すると、この章のプロジェクトは次のコマンドでSpagoを使用して構築できます。 - -```text -$ cd chapter3 -$ spago build -``` - -## 単純な型 - -JavaScriptのプリミティブ型に対応する組み込みデータ型として、PureScriptでは数値型と文字列型、真偽型の3つが定義されています。 -これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポートされます。 -これらはそれぞれ `Number`、 `String`、 -`Boolean`と呼ばれており、PSCiで`:type`コマンドを使うと簡単な値の型を表示させて確認できます。 - -```text -$ spago repl - -> :type 1.0 -Number - -> :type "test" -String - -> :type true -Boolean -``` - -PureScriptには他にも、整数、文字、配列、レコード、関数といった組み込み型が定義されています。 - -小数点以下を省くと整数になり、型 `Number`の浮動小数点数の値と区別されます。 - -```text -> :type 1 -Int -``` - -二重引用符を使用する文字列直値とは異なり、文字直値は一重引用符で囲みます。 - -```text -> :type 'a' -Char -``` - -配列はJavaScriptの配列に対応していますが、JavaScriptの配列とは異なり、PureScriptの配列の全ての要素は同じ型を持つ必要があります。 - -```text -> :type [1, 2, 3] -Array Int - -> :type [true, false] -Array Boolean - -> :type [1, false] -Could not match type Int with type Boolean. -``` - -最後の例で起きているエラーは型検証器によって報告されたもので、配列の2つの要素の型を*単一化*(Unification、等価にする意)しようとして失敗したことを示しています。 - -レコードはJavaScriptのオブジェクトに対応しており、レコード直値はJavaScriptのオブジェクト直値と同じ構文になっています。 - -```text -> author = { name: "Phil", interests: ["Functional Programming", "JavaScript"] } - -> :type author -{ name :: String -, interests :: Array String -} -``` - -この型が示しているのは、指定されたオブジェクトは、 `String`型のフィールド `name` と `Array String`つまり -`String`の配列の型のフィールド `interests` という2つの _フィールド_ (field) を持っているということです。 - -ドットに続けて参照したいフィールドのラベルを書くとレコードのフィールドを参照できます。 - -```text -> author.name -"Phil" - -> author.interests -["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 -``` - -ファイルのトップレベルでは、等号の直前に引数を指定することで関数を定義できます。 - -```haskell -add :: Int -> Int -> Int -add x y = x + y -``` - -バックスラッシュに続けて空白文字で区切られた引数名のリストを書くことで、関数をインラインでも定義できます。 -PSCiで複数行の宣言を入力するには、 `:paste`コマンドを使用して「貼り付けモード」に入ります。 -このモードでは、*Control-D*キーシーケンスを使用して宣言を終了します。 - -```text -> :paste -… add :: Int -> Int -> Int -… add = \x y -> x + y -… ^D -``` - -PSCiでこの関数が定義されていると、次のように関数の隣に2つの引数を空白で区切って書くことで、関数をこれらの引数に*適用* (apply) できます。 - -```text -> add 10 20 -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コードです。 - -```haskell -add x y z = x + - y + z -``` - -しかし、次は正しいコードではありません。 - -```haskell -add x y z = x + -y + z -``` - -後者では、PureScriptコンパイラはそれぞれの行ごとに1つ、つまり*2つ*の宣言であると構文解析します。 - -一般に、同じブロック内で定義された宣言は同じ深さで字下げする必要があります。 -例えばPSCiでlet文の宣言は同じ深さで字下げしなければなりません。 -次は正しいコードです。 - -```text -> :paste -… x = 1 -… y = 2 -… ^D -``` - -しかし、これは正しくありません。 - -```text -> :paste -… x = 1 -… y = 2 -… ^D -``` - -PureScriptの幾つかの予約語(例えば `where`や `of`、 -`let`)は新たなコードのまとまりを導入しますが、そのコードのまとまり内の宣言はそれより深く字下げされている必要があります。 - -```haskell -example x y z = foo + bar - where - foo = x * y - bar = y * z -``` - -ここで `foo`や `bar`の宣言は `example`の宣言より深く字下げされていることに注意してください。 - -ただし、ソースファイルの先頭、最初の `module`宣言における予約語 `where`だけは、この規則の唯一の例外になっています。 - -## 独自の型の定義 - -PureScriptで新たな問題に取り組むときは、まずはこれから扱おうとする値の型の定義を書くことから始めるのがよいでしょう。最初に、住所録に含まれるレコードの型を定義してみます。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}} -``` - -これは `Entry`という*型同義語*(type synonym、型シノニム)を定義しています。 -型 `Entry`は等号の右辺と同じ型ということです。 -レコードの型は何れも文字列である `firstName`、 `lastName`、 `phone`という3つのフィールドからなります。 -前者の2つのフィールドは型 `String`を持ち、 `address`は以下のように定義された型 `Address`を持っています。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Address}} -``` - -なお、レコードには他のレコードを含めることができます。 - -それでは、3つめの型同義語も定義してみましょう。住所録のデータ構造としては、単に項目の連結リストとして格納することにします。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}} -``` - -`List Entry`は `Array Entry`とは同じではないということに注意してください。 `Array Entry`は住所録の項目の -_配列_ を意味しています。 - -## 型構築子と種 - -`List`は*型構築子*(type constructor、型コンストラクタ)の一例になっています。`List`そのものは型ではなく、何らかの型 -`a`があるとき `List a`が型になっています。つまり、 `List`は _型引数_ (type argument) `a`をとり、新たな型 -`List a`を _構築_ するのです。 - -ちょうど関数適用と同じように、型構築子は他の型に並べることで適用されることに注意してください。型 `List Entry`は実は型構築子 -`List`が型 `Entry`に _適用_ されたものです。これは住所録項目のリストを表しています。 - -もし間違って(型注釈演算子 `::`を使って)型 `List`の値を定義しようとすると、今まで見たことのない種類のエラーが表示されるでしょう。 - -```text -> import Data.List -> Nil :: List -In a type-annotated expression x :: t, the type t must have kind Type -``` - -これは*種エラー*です。値がその*型*で区別されるのと同じように、型はその*種*によって区別されます。間違った型の値が*型エラー*になるように、*間違った種*の型は*種エラー*を引き起こします。 - -`Number`や `String`のような、値を持つ全ての型の種を表す `Type`と呼ばれる特別な種があります。 - -型構築子にも種があります。 -例えば種 `Type -> Type`はちょうど `List`のような型から型への関数を表しています。 -ここでエラーが発生したのは、値が種 `Type`であるような型を持つと期待されていたのに、 `List`は種 `Type -> Type`を持っているためです。 - -PSCiで型の種を調べるには、 `:kind`命令を使用します。例えば次のようになります。 - -```text -> :kind Number -Type - -> import Data.List -> :kind List -Type -> Type - -> :kind List String -Type -``` - -PureScriptの _種システム_ は他にも面白い種に対応していますが、それらについては本書の他の部分で見ていくことになるでしょう。 - -## 住所録の項目の表示 - -それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。 -まずは関数に型を与えることから始めます。 -型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくようにすると良いでしょう。 -実際、トップレベルの宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。 -型宣言は関数の名前とその型を `::`記号で区切るようにして書きます。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_signature}} -``` - -`showEntry`は引数として `Entry`を取り `String`を返す関数であるということを、この型シグネチャは言っています。 -`showEntry`のコードは次の通りです。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_implementation}} -``` - -この関数は`Entry`レコードの3つのフィールドを連結し、単一の文字列にします。 -ここで使用される`showAddress`関数は`address`フィールド中のレコードを文字列に変えます。 -`showAddress`の定義は次の通りです。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showAddress}} -``` - -関数定義は関数の名前で始まり、引数名のリストが続きます。関数の結果は等号の後ろに定義します。フィールドはドットに続けてフィールド名を書くことで参照できます。PureScriptでは、文字列連結はJavaScriptのような単一のプラス記号ではなく、ダイアモンド演算子(`<>`)を使用します。 - -## はやめにテスト、たびたびテスト - -PSCi対話式モードでは反応を即座に得られるので、素早い試作開発に向いています。 -それではこの最初の関数が正しく動作するかをPSCiを使用して確認してみましょう。 - -まず、これまでに書いたコードをビルドします。 - -```text -$ spago build -``` - -次に、PSCiを起動し、この新しいモジュールをインポートするために `import`命令を使います。 - -```text -$ spago repl - -> import Data.AddressBook -``` - -レコード直値を使うと、住所録の項目を作成できます。レコード直値はJavaScriptの無名オブジェクトと同じような構文で名前に束縛します。 - -```text -> address = { street: "123 Fake St.", city: "Faketown", state: "CA" } -``` - -それでは、この例に関数を適用してみてください。 - -```text -> showAddress address - -"123 Fake St., Faketown, CA" -``` - -`showEntry`も、住所の例を含む住所録項目レコードを作って試しましょう。 - -```text -> entry = { firstName: "John", lastName: "Smith", address: address } -> showEntry entry - -"Smith, John: 123 Fake St., Faketown, CA" -``` - -## 住所録の作成 - -今度は住所録の操作を支援する関数を幾つか書いてみましょう。 -空の住所録を表す値が必要ですが、これには空のリストを使います。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:emptyBook}} -``` - -既存の住所録に値を挿入する関数も必要でしょう。この関数を `insertEntry`と呼ぶことにします。関数の型を与えることから始めましょう。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}} -``` - -この型シグネチャに書かれているのは、最初の引数として `Entry`、第二引数として `AddressBook`を取り、新しい -`AddressBook`を返すということです。 - -既存の `AddressBook`を直接変更することはしません。 -その代わりに、同じデータが含まれている新しい `AddressBook`を返すようにします。 -このように、 `AddressBook`は*不変データ構造*の一例となっています。 -これはPureScriptにおける重要な考え方です。 -変更はコードの副作用であり、効率の良いコードの挙動を考えるときの妨げになります。 -そのため、可能な限り純粋な関数や不変のデータにする方が好ましいのです。 - -`insertEntry`を実装するのに`Data.List`の`Cons`関数が使えます。 -この関数の型を見るには、PSCiを起動し `:type`コマンドを使います。 - -```text -$ spago repl - -> import Data.List -> :type Cons - -forall a. a -> List a -> List a -``` - -この型シグネチャで書かれているのは、`Cons`が何らかの型`a`の値と型`a`を要素に持つリストを引数に取り、同じ型の要素を持つ新しいリストを返すということです。 -`a`を`Entry`型として特殊化してみましょう。 - -```haskell -Entry -> List Entry -> List Entry -``` - -しかし、 `List Entry`はまさに `AddressBook`ですから、次と同じになります。 - -```haskell -Entry -> AddressBook -> AddressBook -``` - -今回の場合、既に適切な入力があります。 -`Entry`と `AddressBook`に `Cons`を適用すると、新しい `AddressBook`を得ることができます。 -これこそがまさに求めていた関数です。 - -`insertEntry`の実装は次のようになります。 - -```haskell -insertEntry entry book = Cons entry book -``` - -等号の左側にある2つの引数`entry`と`book`がスコープに導入されますから、これらに `Cons`関数を適用して結果の値を作成しています。 - -## カリー化された関数 - -PureScriptでは、関数は常に1つの引数だけを取ります。`insertEntry`関数は2つの引数を取るように見えますが、これは実際には*カリー化された関数*の一例となっています。 - -`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。 - -```haskell -Entry -> (AddressBook -> AddressBook) -``` - -すなわち、 `insertEntry`は関数を返す関数である、ということです。 -この関数は単一の引数 `Entry`を取り、それから単一の引数 `AddressBook`を取り新しい -`AddressBook`を返す新しい関数を返すのです。 - -これは例えば、最初の引数だけを与えると `insertEntry`を _部分適用_ (partial application) -できることを意味します。PSCiでこの結果の型を見てみましょう。 - -```text -> :type insertEntry entry - -AddressBook -> AddressBook -``` - -期待した通り、戻り値の型は関数になっていました。 -この結果の関数に2つ目の引数も適用できます。 - -```text -> :type (insertEntry entry) emptyBook -AddressBook -``` - -ここで括弧は不要であることにも注意してください。次の式は同等です。 - -```text -> :type insertEntry entry emptyBook -AddressBook -``` - -これは関数適用が左結合であるためで、なぜ空白で区切った引数を関数に指定するだけでいいのかの説明にもなっています。 - -関数の型の`->`演算子は関数の*型構築子*です。 -この演算子は2つの型引数を取ります。 -左右の被演算子はそれぞれ関数の引数の型と返り値の型です。 - -本書では今後、「2引数の関数」というように表現することがあることに注意してください。 -しかしそれはカリー化された関数を意味していると考えるべきで、その関数は最初の引数を取り2つ目の引数を取る別の関数を返すのです。 - -今度は `insertEntry`の定義について考えてみます。 - -```haskell -insertEntry :: Entry -> AddressBook -> AddressBook -insertEntry entry book = Cons entry book -``` - -もし式の右辺に明示的に括弧をつけるなら、 `(Cons entry) book`となります。 -`insertEntry entry`はその引数が単に関数 `(Cons entry)`に渡されるような関数だということです。 -でもこの2つの関数はどんな入力についても同じ結果を返しますから、つまりこれらは同じ関数です。 -よって、両辺から引数 `book`を削除できます。 - -```haskell -insertEntry :: Entry -> AddressBook -> AddressBook -insertEntry entry = Cons entry -``` - -しかし今や同様の議論により、両辺から `entry`も削除できます。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}} -``` - -この処理は _イータ変換_ (eta conversion) と呼ばれ、(その他の技法を併用して)引数を参照することなく関数を定義する -_ポイントフリー形式_ (point-free form) へと関数を書き換えるのに使うことができます。 - -`insertEntry`の場合には、イータ変換によって「`insertEntry`は単にリストに対するconsだ」となり、関数の定義はとても明確になりました。しかし、一般的にポイントフリー形式のほうがいいのかどうかには議論の余地があります。 - -## プロパティ取得子 - -よくあるパターンの1つとして、レコード中の個別のフィールド(または「プロパティ」)を取得することがあります。 -`Entry`から`Address`を取り出すインライン関数は次のように書けます。 - -```haskell -\entry -> entry.address -``` - -PureScriptでは[_プロパティ取得子_](https://github.com/purescript/documentation/blob/master/language/Syntax.md#property-accessors)という略記が使えます。この略記では下線文字は無名関数の引数として振舞うため、上記のインライン関数は次と等価です。 - -```haskell -_.address -``` - -これは何段階のプロパティでも動くため、`Entry`に関連する街を取り出す関数は次のように書けます。 - -```haskell -_.address.city -``` - -以下は一例です。 - -```text -> address = { street: "123 Fake St.", city: "Faketown", state: "CA" } -> entry = { firstName: "John", lastName: "Smith", address: address } -> _.lastName entry -"Smith" - -> _.address.city entry -"Faketown" -``` - -## 住所録に問い合わせる - -最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索し適切な -`Entry`を返すものです。これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるでしょう。 - -まずは住所録を絞り込み、該当する姓名を持つ項目だけを保持するようにするのがいいでしょう。それから、結果のリストの先頭の (head) -要素を返すだけです。 - -この大まかな仕様に従って、この関数の型を計算できます。まずPSCiを起動し、 `filter`関数と `head`関数の型を見てみましょう。 - -```text -$ spago repl - -> import Data.List -> :type filter - -forall a. (a -> Boolean) -> List a -> List a - -> :type head - -forall a. List a -> Maybe a -``` - -型の意味を理解するために、これらの2つの型の一部を取り出してみましょう。 - -`filter`はカリー化された2引数の関数です。 -最初の引数は、リストの要素を取り `Boolean`値を結果として返す関数です。 -第2引数は要素のリストで、返り値は別のリストです。 - -`head`は引数としてリストを取り、 `Maybe a`という今まで見たことがないような型を返します。 -`Maybe a`は型 `a`のオプショナルな値、つまり -`a`の値を持つか持たないかのどちらかの値を示しており、JavaScriptのような言語で値がないことを示すために使われる -`null`の型安全な代替手段を提供します。 -これについては後の章で詳しく扱います。 - -`filter`と `head`の全称量化された型は、PureScriptコンパイラによって次のように _特殊化_ (specialized) -されます。 - -```haskell -filter :: (Entry -> Boolean) -> AddressBook -> AddressBook - -head :: AddressBook -> Maybe Entry -``` - -検索する関数の引数として姓と名前を渡す必要があるのもわかっています。 - -`filter`に渡す関数も必要になることもわかります。この関数を `filterEntry`と呼ぶことにしましょう。 `filterEntry`は `Entry -> Boolean`という型を持っています。 `filter filterEntry`という関数適用の式は、 `AddressBook -> AddressBook`という型を持つでしょう。もしこの関数の結果を `head`関数に渡すと、型 `Maybe Entry`の結果を得ることになります。 - -これまでのことを纏めると、関数の妥当な型シグネチャは次のようになります。`findEntry`と呼ぶことにしましょう。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_signature}} -``` - -この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び`AddressBook`を引数に取り、`Entry`のオプション型の値を結果として返すということです。 -オプショナルな結果は名前が住所録で発見された場合にのみ値を持ちます。 - -そして、 `findEntry`の定義は次のようになります。 - -```haskell -findEntry firstName lastName book = head (filter filterEntry book) - where - filterEntry :: Entry -> Boolean - filterEntry entry = entry.firstName == firstName && entry.lastName == lastName -``` - -一歩ずつこのコードを調べてみましょう。 - -`findEntry`は、どちらも文字列型である `firstName`と `lastName`、`AddressBook`型の -`book`という3つの名前をスコープに導入します。 - -定義の右辺では `filter`関数と `head`関数が組み合わされています。 -まず項目のリストを絞り込み、その結果に `head`関数を適用しています。 - -真偽型を返す関数 `filterEntry`は `where`節の内部で補助的な関数として定義されています。 -このため、 `filterEntry`関数はこの定義の内部では使用できますが、外部では使用できません。 -また、`filterEntry`はそれを包む関数の引数に依存でき、 `filterEntry`は指定された `Entry`を絞り込むために引数 -`firstName`と `lastName`を使用しているので、 `filterEntry`が -`findEntry`の内部にあることは必須になっています。 - -最上位での宣言と同じように、必ずしも -`filterEntry`の型シグネチャを指定しなくてもよいことに注意してください。ただし、ドキュメントとしても役に立つので型シグネチャを書くことは推奨されています。 - -## 中置の関数適用 - -これまでお話しした関数のほとんどは _前置_ 関数適用でした。関数名が引数の _前_ -に置かれていたということです。例えば`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`関数の中置別称として定義されています。 - -```haskell -infix 4 eq as == -``` - -したがって`filterEntry`中の`entry.firstName == firstName`は`eq entry.firstName -firstName`で置き換えられます。この節の後のほうで中置演算子を定義する例にもう少し触れます。 - -前置関数を演算子としての中置の位置に置くとより読みやすいコードになる場面があります。 -その一例が`mod`関数です。 - -```text -> mod 8 3 -2 -``` - -上の用例は正しく動きますが、読みづらいです。 -より馴染みのある表現の仕方は「8 mod 3」ですが、バックスラッシュ (\`) の中に前置関数を包めばこのように書けます。 - -```text -> 8 `mod` 3 -2 -``` - -同様に、`insertEntry`をバックスラッシュで包むと中置演算子に変わります。 -例えば以下の`book1`と`book2`は等価です。 - -```haskell -book1 = insertEntry john emptyBook -book2 = john `insertEntry` emptyBook -``` - -複数回`insertEntry`を適用することで複数の項目がある`AddressBook`を作ることができますが、以下のように前置関数 -(`book3`) として適用するか中置演算子 (`book4`) として適用するかの2択があります。 - -```haskell -book3 = insertEntry john (insertEntry peggy (insertEntry ned emptyBook)) -book4 = john `insertEntry` (peggy `insertEntry` (ned `insertEntry` emptyBook)) -``` - -`insertEntry`には中置演算子別称(または同義語)も定義できます。 -この演算子の名前に適当に`++`を選び、[優先度](https://github.com/purescript/documentation/blob/master/language/Syntax.md#precedence)を`5`にし、そして`infixr`を使って右[結合](https://github.com/purescript/documentation/blob/master/language/Syntax.md#associativity)とします。 - -```haskell -infixr 5 insertEntry as ++ -``` - -この新しい演算子で上の`book4`の例を次のように書き直せます。 - -```haskell -book5 = john ++ (peggy ++ (ned ++ emptyBook)) -``` - -そして新しい`++`演算子が右結合なので意味を変えずに括弧を除去できます。 - -```haskell -book6 = john ++ peggy ++ ned ++ emptyBook -``` - -括弧を消去する他のよくある技法は、いつもの前置関数と一緒に`apply`の中置演算子`$`を使うというものです。 - -例えば前の`book3`の例は以下のように書き直せます。 - -```haskell -book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook -``` - -括弧を`$`で置き換えるのは大抵入力しやすくなりますし(議論の余地がありますが)読みやすくなります。 -この記号の意味を覚えるための記憶術として、ドル記号を2つの括弧に打ち消し線が引かれたものと見ることで、これで括弧が不必要になったのだと推測できるという方法があります。 - -なお、`($)`は言語にハードコードされた特別な構文ではありません。 -単に`apply`という名前の通常の関数のための中置演算子であって、`Data.Function`で以下のように定義されています。 - -```haskell -apply :: forall a b. (a -> b) -> a -> b -apply f x = f x - -infixr 0 apply as $ -``` - -`apply`関数は、他の関数(型は`(a -> b)`)を最初の引数に、値(型は`a`)を2つ目の引数に取って、その値に対して関数を呼びます。 -この関数が何ら意味のあることをしていないようだと思ったら、全くもって正しいです。 -この関数がなくてもプログラムは論理的に同一です([参照透過性](https://en.wikipedia.org/wiki/Referential_transparency)も見てください)。 -この関数の構文的な利便性はその中置演算子に割り当てられた特別な性質からきています。 -`$`は右結合 (`infixr`) で低い優先度 (`0`) の演算子ですが、これにより深い入れ子になった適用から括弧の束を削除できるのです。 - -さらなる`$`演算子を使った括弧退治のチャンスは以前の`findEntry`関数にあります。 - -```haskell -findEntry firstName lastName book = head $ filter filterEntry book -``` - -この行をより簡潔に書き換える方法を次節の「関数合成」で見ていきます。 - -名前の短い中置演算子を前置関数として使いたければ括弧で囲むことができます。 - -```text -> 8 + 3 -11 - -> (+) 8 3 -11 -``` - -その代わりの手段として演算子は部分適用でき、これには式を括弧で囲んで[演算子節](https://github.com/purescript/documentation/blob/master/language/Syntax.md#operator-sections)中の引数として`_`を使います。これは簡単な無名関数を作るより便利な方法として考えることができます(以下の例ではそこから無名関数を名前に束縛しているので、もはや別に無名とも言えなくなっていますが)。 - -```text -> add3 = (3 + _) -> add3 2 -5 -``` - -纏めると、以下は引数に`5`を加える関数の等価な定義です。 - -```haskell -add5 x = 5 + x -add5 x = add 5 x -add5 x = (+) 5 x -add5 x = 5 `add` x -add5 = add 5 -add5 = \x -> 5 + x -add5 = (5 + _) -add5 x = 5 `(+)` x -- よおポチ、中置に目がないっていうから、中置の中に中置を入れといたぜ -``` - -## 関数合成 - -イータ変換を使うと `insertEntry`関数を簡略化できたのと同じように、引数をよく考察すると `findEntry`の定義を簡略化できます。 - -なお、引数 `book`は関数 `filter filterEntry`に渡され、この適用の結果が `head`に渡されます。これは言いかたを変えれば、 -`filter filterEntry`と `head`の _合成_ (composition) に `book`が渡されるということです。 - -PureScriptの関数合成演算子は `<<<`と `>>>`です。前者は「逆方向の合成」であり、後者は「順方向の合成」です。 - -何れかの演算子を使用して `findEntry`の右辺を書き換えることができます。 -逆順の合成を使用すると、右辺は次のようになります。 - -```haskell -(head <<< filter filterEntry) book -``` - -この形式なら最初の定義にイータ変換の技を適用でき、 `findEntry`は最終的に次のような形式に到達します。 - -```haskell -{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_implementation}} - ... -``` - -右辺を次のようにしても同じく妥当です。 - -```haskell -filter filterEntry >>> head -``` - -どちらにしても、これは「`findEntry`は絞り込み関数と`head`関数の合成である」という -`findEntry`関数のわかりやすい定義を与えます。 - -どちらの定義のほうがわかりやすいかの判断はお任せしますが、このように関数を部品として捉えると有用なことがよくあります。関数は1つの役目だけをこなし、機能を関数合成で組み立てるというように。 - -## 演習 - - 1. (簡単)`findEntry`関数の定義の主な部分式の型を書き下し、 `findEntry`関数についてよく理解しているか試してみましょう。 - 例えば`findEntry`の定義の中にある `head`関数の型は `AddressBook -> Maybe - Entry`と特殊化されています。 - *補足*:この問題にはテストがありません。 - 1. (普通)関数`findEntryByStreet :: String -> AddressBook -> Maybe - Entry`を書いてください。 - この関数は与えられた通りの住所から`Entry`を見付け出します。 - *手掛かり*:`findEntry`にある既存のコードを再利用してください。 - 実装した関数をPSCiと`spago test`を走らせてテストしてください。 - 1. (普通)`filterEntry`を(`<<<`や`>>>`を使った)合成で置き換えて、`findEntryByStreet`を書き直してください。 - 合成の対象は、プロパティ取得子(`_.`記法を使います)と、与えられた文字列引数が与えられた通りの住所に等しいかを判定する関数です。 - 1. (普通)指定された名前が `AddressBook`に存在するかどうかを調べて真偽値で返す関数`isInBook`を書いてみましょう。 - *手掛かり*:リストが空かどうかを調べる `Data.List.null`関数の型をPSCiで調べてみてみましょう。 - 1. (難しい)「重複」している項目を住所録から削除する関数 `removeDuplicates`を書いてみましょう。 - 項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複していると考えます。 - *手掛かり*:関数 `Data.List.nubBy`の型を、PSCiを使用して調べてみましょう。 - この関数は値同士の等価性を定義する述語関数に基づいてリストから重複要素を削除します。 - なお、それぞれの重複する項目の集合における最初の要素(リストの先頭に最も近い)が保持する項目です。 - -## まとめ - -この章では、関数型プログラミングの新しい概念を幾つも導入しました。 - -- 対話的モードのPSCiを使用して、関数を調べるなどの思いついたことを試す方法 -- 検証や実装の道具としての型の役割 -- 多引数関数を表現する、カリー化された関数の使用 -- 関数合成で小さな部品を組み合わせてのプログラムの構築 -- `where`節を利用したコードの構造化 -- `Maybe`型を使用してnull値を回避する方法 -- イータ変換や関数合成のような手法を利用した、よりわかりやすいコードへの再構成 - -次の章からは、これらの考えかたに基づいて進めていきます。 diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md deleted file mode 100644 index 2a89ea8a..00000000 --- a/text-ja/chapter4.md +++ /dev/null @@ -1,732 +0,0 @@ -# 再帰、マップ、畳み込み - -## この章の目標 - -この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて見ていきましょう。再帰は関数型プログラミングの基本的な手法であり、この本の全体に亙って使われます。 - -また、PureScriptの標準ライブラリから標準的な関数を幾つか取り扱います。 -`map`や`fold`といった関数だけでなく、`filter`や`concatMap`といった特別な場合において便利なものについても見ていきます。 - -この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用います。この章で学ぶ手法を応用して、擬似的なファイルシステムによって表されるファイルのプロパティを計算する関数を記述します。 - -## プロジェクトの準備 - -この章のソースコードは`src/Data/Path.purs`と`test/Examples.purs`に含まれています。 -`Data.Path`モジュールは仮想ファイルシステムのモデルを含みます。 -このモジュールの内容を変更する必要はありません。 -演習への解答は`Test.MySolutions`モジュールに実装してください。 -それぞれの演習を完了させつつ都度`Test.Main`モジュールにある対応するテストを有効にし、`spago -test`を走らせることで解答を確認してください。 - -このプロジェクトには以下の依存関係があります。 - -- `maybe`: `Maybe`型構築子が定義されています。 -- `arrays`: 配列を扱うための関数が定義されています。 -- `strings`: JavaScriptの文字列を扱うための関数が定義されています。 -- `foldable-traversable`: 配列やその他のデータ構造を畳み込む関数が定義されています。 -- `console`: コンソールへの出力を扱うための関数が定義されています。 - -## 導入 - -再帰は一般のプログラミングでも重要な手法ですが、特に純粋関数型プログラミングでは当たり前のように用いられます。この章で見ていくように、再帰はプログラムの変更可能な状態を減らすために役立つからです。 - -再帰は*分割統治*戦略と密接な関係があります。 -分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分ごとの答えから最終的な答えを組み立てるということです。 - -それでは、PureScriptにおける再帰の簡単な例を幾つか見てみましょう。 - -次に示すのは*階乗関数*のありふれた例です。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:factorial}} -``` - -部分問題へ問題を分割することによって階乗関数がどのように計算されるかがわかります。より小さい数へと階乗を計算していくということです。ゼロに到達すると、答えは直ちに求まります。 - -次は、 _フィボナッチ関数_ (Fibonacci function) を計算するという、これまたよくある例です。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:fib}} -``` - -やはり、部分問題の解決策を考えることで全体を解決していることがわかります。 -このとき、`fib (n - 1)`と`fib (n - 2)`という式に対応した、2つの部分問題があります。 -これらの2つの部分問題が解決されていれば、この部分的な答えを加算することで、全体の答えを組み立てることができます。 - -なお上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。パターン照合の技法は後の章でお話しします。 - -## 配列上での再帰 - -再帰関数の定義は`Int`型だけに限定されるものではありません。 -本書の後半で*パターン照合*を扱うときに、いろいろなデータ型の上での再帰関数について見ていきますが、ここでは数と配列に限っておきます。 - -入力がゼロでないかどうかについて分岐するのと同じように、配列の場合も、配列が空でないかどうかについて分岐していきます。再帰を使用して配列の長さを計算する次の関数を考えてみます。 - -```haskell -import Prelude - -import Data.Array (null, tail) -import Data.Maybe (fromMaybe) - -{{#include ../exercises/chapter4/test/Examples.purs:length}} -``` - -この関数では配列が空かどうかで分岐するために`if ... then ... else`式を使っています。 -この`null`関数は配列が空のときに`true`を返します。 -空の配列の長さはゼロであり、空でない配列の長さは配列の先頭を取り除いた残りの部分の長さより1大きいというわけです。 - -`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返します。配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。`fromMaybe`関数は既定値と`Maybe`値を取ります。後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返します。 - -JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえませんが、次の演習を完遂するための手がかりとしては充分でしょう。 - -## 演習 - - 1. (簡単)入力が偶数であるとき、かつそのときに限り`true`に返すような再帰関数を書いてみましょう。 - 2. (少し難しい)配列内の偶数の数を数える再帰関数`countEven`を書いてみましょう。 - *手掛かり*:`Data.Array`モジュールの`head`関数を使うと、空でない配列の最初の要素を見つけることができます。 - -## マップ - -`map`関数は配列に対する再帰関数の1つです。この関数を使うと、配列の各要素に順番に関数を適用することで、配列の要素を変換できます。そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存されます。 - -本書の後半で _型クラス_ (type class) -の内容を押さえるとき、`map`関数が形状保存関数のより一般的な様式の一例であることを見ていきます。これは _関手_ (functor) -と呼ばれる型構築子のクラスを変換するものです。 - -それでは、PSCiで`map`関数を試してみましょう。 - -```text -$ spago repl - -> import Prelude -> map (\n -> n + 1) [1, 2, 3, 4, 5] -[2, 3, 4, 5, 6] -``` - -`map`がどのように使われているかに注目してください。 -最初の引数には配列上で「写す」関数、第2引数には配列そのものを渡します。 - -## 中置演算子 - -バッククォートで関数名を囲むと、写す関数と配列の間に、`map`関数を書くことができます。 - -```text -> (\n -> n + 1) `map` [1, 2, 3, 4, 5] -[2, 3, 4, 5, 6] -``` - -この構文は _中置関数適用_ と呼ばれ、どんな関数でもこのように中置できます。普通は2引数の関数に対して使うのが最適でしょう。 - -配列を扱うときは、`map`関数と等価な`<$>`という演算子が存在します。この演算子は他の二項演算子と同じように中置で使用できます。 - -```text -> (\n -> n + 1) <$> [1, 2, 3, 4, 5] -[2, 3, 4, 5, 6] -``` - -それでは`map`の型を見てみましょう。 - -```text -> :type map -forall a b f. Functor f => (a -> b) -> f a -> f b -``` - -実は`map`の型は、この章で必要とされているものよりも一般的な型になっています。今回の目的では、`map`は次のようなもっと具体的な型であるかのように考えるとよいでしょう。 - -```text -forall a b. (a -> b) -> Array a -> Array b -``` - -この型では、`map`関数に適用するときには`a`と`b`という2つの型を自由に選ぶことができる、ということも示されています。 -`a`は元の配列の要素の型で、`b`は目的の配列の要素の型です。 -もっと言えば、`map`が配列の要素の型を保存する必要があるわけではありません。 -例えば`map`を使用すると数値を文字列に変換できます。 - -```text -> show <$> [1, 2, 3, 4, 5] - -["1","2","3","4","5"] -``` - -中置演算子`<$>`は特別な構文のように見えるかもしれませんが、実はPureScriptの普通の関数の別称です。 -中置構文を使用した単なる*適用*にすぎません。 -実際、括弧でその名前を囲むと、この関数を通常の関数のように使用できます。 -これは、`map`代わりに、括弧で囲まれた`(<$>)`という名前を使って配列に関数を適用できるということです。 - -```text -> (<$>) show [1, 2, 3, 4, 5] -["1","2","3","4","5"] -``` - -中置関数は既存の関数名の別称として定義されます。 -例えば`Data.Array`モジュールでは次のように`range`関数の同義語として中置演算子`(..)`を定義しています。 - -```haskell -infix 8 range as .. -``` - -この演算子は次のように使うことができます。 - -```text -> import Data.Array - -> 1 .. 5 -[1, 2, 3, 4, 5] - -> show <$> (1 .. 5) -["1","2","3","4","5"] -``` - -*補足*:独自の中置演算子は、自然な構文を備える領域特化言語を定義する上で優れた手段になりえます。ただし、乱用すると初心者が読めないコードになることがありますから、新たな演算子の定義には慎重になるのが賢明です。 - -上記の例では、`1 .. 5`という式は括弧で囲まれていましたが、実際にはこれは必要ありません。 -なぜなら、`Data.Array`モジュールは、`<$>`に割り当てられた優先順位より高い優先順位を`..`演算子に割り当てているからです。 -上の例では、`..`の優先順位は、予約語`infix`のあとに書かれた数の`8` と定義されていました。 -ここでは`<$>`の優先順位よりも高い優先順位を`..`に割り当てており、このため括弧を付け加える必要がないということです。 - -```text -> show <$> 1 .. 5 -["1","2","3","4","5"] -``` - -中置演算子に(左または右の)*結合性*を与えたい場合は、代わりに予約語`infixl`と`infixr`を使います。`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。 - -## 配列の絞り込み - -`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供しています。 -この関数は、述語関数に適合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。 - -例えば1から10までの数で、偶数であるような数の配列を計算したいとします。 -これは次のようにできます。 - -```text -> import Data.Array - -> filter (\n -> n `mod` 2 == 0) (1 .. 10) -[2,4,6,8,10] -``` - -## 演習 - - 1. (簡単)`map`関数や`<$>`関数を使用して、 配列に格納された数のそれぞれの平方を計算する関数`squared`を書いてみましょう。 - *手掛かり*:`map`や`<$>`といった関数を使ってください。 - 1. (簡単)`filter`関数を使用して、数の配列から負の数を取り除く関数`keepNonNegative`を書いてみましょう。 - *手掛かり*:`filter`関数を使ってください。 - 1. (普通) - - `filter`の中置同義語`<$?>`を定義してください。 - *補足*:中置同義語はREPLでは定義できないかもしれませんが、ファイルでは定義できます。 - - 関数`keepNonNegativeRewrite`を書いてください。この関数は`filter`を独自の新しい中置演算子`<$?>`で置き換えたところ以外、`keepNonNegative`と同じです。 - - PSCiで独自の演算子の優先度合いと結合性を試してください。 - *補足*:この問題のための単体試験はありません。 - -## 配列の平坦化 - -配列に関する標準的な関数として`Data.Array`で定義されているものには、`concat`関数もあります。`concat`は配列の配列を1つの配列へと平坦化します。 - -```text -> import Data.Array - -> :type concat -forall a. Array (Array a) -> Array a - -> concat [[1, 2, 3], [4, 5], [6]] -[1, 2, 3, 4, 5, 6] -``` - -関連する関数として、`concat`と`map`を組み合わせたような`concatMap`と呼ばれる関数もあります。`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それに対して`concatMap`は値から値の配列への関数を取ります。 - -実際に動かして見てみましょう。 - -```text -> import Data.Array - -> :type concatMap -forall a b. (a -> Array b) -> Array a -> Array b - -> concatMap (\n -> [n, n * n]) (1 .. 5) -[1,1,2,4,3,9,4,16,5,25] -``` - -ここでは、数をその数とその数の平方の2つの要素からなる配列に写す関数`\n -> [n, n * n]`を引数に`concatMap`を呼び出しています。 -結果は10個の整数の配列です。 -配列は1から5の数とそのそれぞれの数の平方からなります。 - -`concatMap`がどのように結果を連結しているのかに注目してください。渡された関数を元の配列のそれぞれの要素について一度ずつ呼び出し、その関数はそれぞれ配列を生成します。最後にそれらの配列を単一の配列に押し潰したものが結果となります。 - -`map`と`filter`、`concatMap`は、「配列内包表記」(array comprehensions) -と呼ばれる、配列に関するあらゆる関数の基盤を形成します。 - -## 配列内包表記 - -数`n`の2つの因数を見つけたいとしましょう。 -こうするための簡単な方法としては、総当りで調べる方法があります。 -つまり、`1`から`n`の数の全ての組み合わせを生成し、それを乗算してみるわけです。 -もしその積が`n`なら、`n`の因数の組み合わせを見つけたということになります。 - -配列内包表記を使用するとこれを計算できます。 -PSCiを対話式の開発環境として使用し、1つずつこの手順を進めていきましょう。 - -最初の工程では`n`以下の数の組み合わせの配列を生成しますが、これには`concatMap`を使えばよいです。 - -`1 .. n`のそれぞれの数を配列`1 .. n`へとマッピングすることから始めましょう。 - -```text -> pairs n = concatMap (\i -> 1 .. n) (1 .. n) -``` - -この関数をテストしてみましょう。 - -```text -> pairs 3 -[1,2,3,1,2,3,1,2,3] -``` - -これは求めているものとは全然違います。 -単にそれぞれの組み合わせの2つ目の要素を返すのではなく、対全体を保持できるように、内側の`1 .. n`の複製について関数を対応付ける必要があります。 - -```text -> :paste -… pairs' n = -… concatMap (\i -> -… map (\j -> [i, j]) (1 .. n) -… ) (1 .. n) -… ^D - -> pairs' 3 -[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]] -``` - -いい感じになってきました。 -しかし、`[1, 2]`と`[2, 1]`の両方があるように、重複した組み合わせが生成されています。 -`j`を`i`から`n`の範囲に限定することで、2つ目の場合を取り除くことができます。 - -```text -> :paste -… pairs'' n = -… concatMap (\i -> -… map (\j -> [i, j]) (i .. n) -… ) (1 .. n) -… ^D -> pairs'' 3 -[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]] -``` - -すばらしいです。 -因数の候補の全ての組み合わせを手に入れたので、`filter`を使えば、その積が`n`であるような組み合わせを選び出すことができます。 - -```text -> import Data.Foldable - -> factors n = filter (\pair -> product pair == n) (pairs'' n) - -> factors 10 -[[1,10],[2,5]] -``` - -このコードでは、`foldable-traversable`ライブラリの`Data.Foldable`モジュールにある`product`関数を使っています。 - -うまくいきました。 -因数の組み合わせの正しい集合を重複なく見つけることができました。 - -## do記法 - -しかし、このコードの可読性は大幅に向上できます。`map`や`concatMap`は基本的な関数であり、 _do記法_ (do notation) -と呼ばれる特別な構文の基礎になっています(もっと厳密にいえば、それらの一般化である`map`と`bind`が基礎をなしています)。 - -*補足*:`map`と`concatMap`が _配列内包表記_ を書けるようにしているように、もっと一般的な演算子である`map`と`bind`は -_モナド内包表記_ (monad comprehensions) と呼ばれているものを書けるようにします。本書の後半では _モナド_ (monad) -の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。 - -do記法を使うと、先ほどの`factors`関数を次のように書き直すことができます。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:factors}} -``` - -キーワード`do`はdo記法を使うコードのブロックを導入します。このブロックは幾つかの種類の式で構成されています。 - -- 配列の要素を名前に束縛する式。 - これは後ろ向きの矢印`<-`で示されていて、その左側は名前、右側は配列の型を持つ式です。 -- 名前に配列の要素を束縛しない式。 - `do`の _結果_ はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されています。 -- `let`キーワードを使用し、式に名前を与える式。 - -この新しい記法を使うと、アルゴリズムの構造がわかりやすくなることがあります。 -頭の中で`<-`を「選ぶ」という単語に置き換えるとすると、「1からnの間の要素`i`を選び、それからiからnの間の要素`j`を選び、`[i, j]`を返す」というように読むことができるでしょう。 - -最後の行では、`pure`関数を使っています。この関数はPSCiで評価できますが、型を明示する必要があります。 - -```text -> pure [1, 2] :: Array (Array Int) -[[1, 2]] -``` - -配列の場合、`pure`は単に1要素の配列を作成します。 -実際、`factors`関数を変更して、`pure`の代わりにこの形式も使うようにできます。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:factorsV2}} -``` - -そして、結果は同じになります。 - -## ガード - -`factors`関数を更に改良する方法としては、このフィルタを配列内包表記の内側に移動するというものがあります。 -これは`control`ライブラリにある`Control.Alternative`モジュールの`guard`関数を使用することで可能になります。 - -```haskell -import Control.Alternative (guard) - -{{#include ../exercises/chapter4/test/Examples.purs:factorsV3}} -``` - -`pure`と同じように、どのように動作するかを理解するために、PSCiで`guard`関数を適用して調べてみましょう。 -`guard`関数の型は、ここで必要とされるものよりもっと一般的な型になっています。 - -```text -> import Control.Alternative - -> :type guard -forall m. Alternative m => Boolean -> m Unit -``` - -今回の場合は、PSCiは次の型を報告するものと考えてください。 - -```haskell -Boolean -> Array Unit -``` - -目的からすると、次の計算の結果から配列における`guard`関数について今知りたいことは全てわかります。 - -```text -> import Data.Array - -> length $ guard true -1 - -> length $ guard false -0 -``` - -つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返すのです。もし式が`false`と評価された場合は、その結果は空です。 - -ガードが失敗した場合、配列内包表記の現在の分岐は、結果なしで早めに終了されることを意味します。 -これは、`guard`の呼び出しが、途中の配列に対して`filter`を使用するのと同じだということです。 -実践の場面にもよりますが、`filter`の代わりに`guard`を使いたいことは多いでしょう。 -これらが同じ結果になることを確認するために、`factors`の2つの定義を試してみてください。 - -## 演習 - - 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²` です。 - *手掛かり*:配列内包表記で`guard`関数を使ってください。 - 1. (難しい)`factors`関数を使用して、数`n`の[素因数分解](https://www.mathsisfun.com/prime-factorization.html)を求める関数`primeFactors`を定義してみましょう。 - 数`n`の素因数分解とは、素数の積が`n`であるような整数の配列のことです。 - *手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してください。 - 最初の因数を探し、それから残りの因数を探すのです。 - -## 畳み込み - -配列における左右の畳み込みは、再帰を用いて実装される別の興味深い一揃いの関数を提供します。 - -PSCiを使って、`Data.Foldable`モジュールをインポートし、`foldl`と`foldr`関数の型を調べることから始めましょう。 - -```text -> import Data.Foldable - -> :type foldl -forall a b f. Foldable f => (b -> a -> b) -> b -> f a -> b - -> :type foldr -forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b -``` - -これらの型は、現在興味があるものよりも一般化されています。 -この章の目的に対して、PSCiは以下の(より具体的な)答えをくれていると考えておきましょう。 - -```text -> :type foldl -forall a b. (b -> a -> b) -> b -> Array a -> b - -> :type foldr -forall a b. (a -> b -> b) -> b -> Array a -> b -``` - -どちらの型でも、`a`は配列の要素の型に対応しています。 -型`b`は、配列を走査 (traverse) したときの結果を累積する「累積器」(accumulator) の型だと考えることができます。 - -`foldl`関数と`foldr`関数の違いは走査の方向です。 -`foldr`が「右から」配列を畳み込むのに対して、`foldl`は「左から」配列を畳み込みます。 - -実際にこれらの関数の動きを見てみましょう。`foldl`を使用して数の配列の和を求めてみます。型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。ここでは、次の要素を累積器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累積器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。最初の引数としては、加算演算子を使用できますし、累積器の初期値はゼロになります。 - -```text -> foldl (+) 0 (1 .. 5) -15 -``` - -この場合では、引数が逆になっていても`(+)`関数は同じ結果を返すので、`foldl`と`foldr`のどちらでも問題ありません。 - -```text -> foldr (+) 0 (1 .. 5) -15 -``` - -`foldl`と`foldr`の違いを説明するために、畳み込み関数の選択が影響する例も書いてみましょう。 -加算関数の代わりに、文字列連結を使用して文字列を作ってみます。 - -```text -> foldl (\acc n -> acc <> show n) "" [1,2,3,4,5] -"12345" - -> foldr (\n acc -> acc <> show n) "" [1,2,3,4,5] -"54321" -``` - -これは、2つの関数の違いを示しています。左畳み込み式は、以下の関数適用と同等です。 - -```text -((((("" <> show 1) <> show 2) <> show 3) <> show 4) <> show 5) -``` - -それに対し、右畳み込みは以下に相当します。 - -```text -((((("" <> show 5) <> show 4) <> show 3) <> show 2) <> show 1) -``` - -## 末尾再帰 - -再帰はアルゴリズムを定義するための強力な手法ですが、問題も抱えています。 -JavaScriptで再帰関数を評価するとき、入力が大きすぎるとスタックオーバーフローでエラーを起こす可能性があるのです。 - -PSCiで次のコードを入力すると、この問題を簡単に検証できます。 - -```text -> :paste -… f n = -… if n == 0 -… then 0 -… else 1 + f (n - 1) -… ^D - -> f 10 -10 - -> f 100000 -RangeError: Maximum call stack size exceeded -``` - -これは問題です。関数型プログラミングの基本的な手法として再帰を採用しようとするなら、境界がない可能性がある再帰でも扱える方法が必要です。 - -PureScriptは _末尾再帰最適化_ (tail recursion optimization) -の形でこの問題に対する部分的な解決策を提供しています。 - -*補足*:この問題へのより完全な解決策としては、いわゆる*トランポリン*を使用したライブラリで実装する方法がありますが、それはこの章で扱う範囲を超えています。 -この内容に興味のある読者は[`free`](https://pursuit.purescript.org/packages/purescript-free)や[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec)パッケージのドキュメントを参照してみてください。 - -末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 _末尾位置_ (tail position) -にある関数の再帰的な呼び出しは、スタックフレームが確保されない _ジャンプ_ -に置き換えることができます。関数が戻るより前の最後の呼び出しであるとき、呼び出しが _末尾位置_ -にあるといいます。なぜこの例でスタックオーバーフローが見られたのかはこれが理由です。この`f`の再帰呼び出しは、末尾位置 _ではない_ からです。 - -実際には、PureScriptコンパイラは再帰呼び出しをジャンプに置き換えるのではなく、再帰的な関数全体を _whileループ_ に置き換えます。 - -以下は全ての再帰呼び出しが末尾位置にある再帰関数の例です。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}} -``` - -`fact`への再帰呼び出しは、この関数の中で起こる最後のものである、つまり末尾位置にあることに注意してください。 - -## 累積器 - -末尾再帰ではない関数を末尾再帰関数に変える一般的な方法としては、 _累積器引数_ (accumulator parameter) -を使用する方法があります。累積器引数は関数に追加される余剰の引数で返り値を _累積_ -するものです。これは結果を累積するために返り値を使うのとは対称的です。 - -例えば章の初めに示した`length`関数を再考しましょう。 - -```haskell -length :: forall a. Array a -> Int -length arr = - if null arr - then 0 - else 1 + (length $ fromMaybe [] $ tail arr) -``` - -この実装は末尾再帰ではないので、大きな入力配列に対して実行されると、生成されたJavaScriptはスタックオーバーフローを発生させるでしょう。 -しかし代わりに、結果を蓄積するための2つ目の引数を関数に導入することで、これを末尾再帰に変えることができます。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}} -``` - -ここでは、配列を逆転させる作業を補助関数`length'`に委譲しています。`length'`は末尾再帰です。その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。これは、生成されたコードが -_whileループ_ となり、大きな入力でもスタックが溢れないことを意味します。 - -`lengthTailRec`の実装を理解するために補助関数`length'`に着目しましょう。この関数は必然的に累積器引数を使って追加の状態……これは部分的な結果です……を保持しています。0から始まり、入力の配列中の全ての要素それぞれについて1ずつ足されて大きくなっていきます。 - -累積器を「状態」と考えることもできますが、直接には変更されているわけではないことにも注意してください。 - -## 明示的な再帰より畳み込みを選ぼう - -末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けることができるので、全ての関数をこの形で書こうとする誘惑にかられます。 -しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書くことができることを忘れがちです。 -`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、コードの単純さという利点があります。 -これらの部品はよく知られており、明示的な再帰よりもアルゴリズムの*意図*をよりはっきりとさせるのです。 - -例えば`foldr`を使って配列を反転できます。 - -```text -> import Data.Foldable - -> :paste -… reverse :: forall a. Array a -> Array a -… reverse = foldr (\x xs -> xs <> [x]) [] -… ^D - -> reverse [1, 2, 3] -[3,2,1] -``` - -`foldl`を使って`reverse`を書くことは、読者への課題として残しておきます。 - -## 演習 - - 1. (簡単)`foldl`を使って真偽値配列の値が全て真か検査する関数`allTrue`を書いてください。 - 2. (普通。テストなし)関数`foldl (==) false xs`が真を返すような配列`xs`とはどのようなものか説明してください。 - 言い換えると、「関数は`xs`が……を含むときに`true`を返す」という文を完成させることになります。 - 3. (普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`を書いてください。 - *手掛かり*:累積器引数を使ってください。 - 4. (普通)`foldl`を使って`reverse`を書いてみましょう。 - -## 仮想ファイルシステム - -この節では、これまで学んだことを応用して、模擬的なファイルシステムで動作する関数を書いていきます。 -事前に定義されたAPIで動作するように、マップ、畳み込み、及びフィルタを使用します。 - -`Data.Path`モジュールでは、次のように仮想ファイルシステムのAPIが定義されています。 - -- ファイルシステム内のパスを表す型`Path`があります。 -- ルートディレクトリを表すパス`root`があります。 -- `ls`関数はディレクトリ内のファイルを列挙します。 -- `filename`関数は`Path`のファイル名を返します。 -- `size`関数は`Path`が示すファイルの大きさを返します。 -- `isDirectory`関数はファイルかディレクトリかを調べます。 - -型について言うと、次のような型定義があります。 - -```haskell -root :: Path - -ls :: Path -> Array Path - -filename :: Path -> String - -size :: Path -> Maybe Int - -isDirectory :: Path -> Boolean -``` - -PSCiでこのAPIを試してみましょう。 - -```text -$ spago repl - -> import Data.Path - -> root -/ - -> isDirectory root -true - -> ls root -[/bin/,/etc/,/home/] -``` - -`Test.Examples`モジュールでは`Data.Path`APIを使用する関数を定義しています。 -`Data.Path`モジュールを変更したり定義を理解したりする必要はありません。 -全て`Test.Examples`モジュールだけで作業します。 - -## 全てのファイルの一覧 - -それでは、ディレクトリの中身を含めた全てのファイルを列挙する関数を書いてみましょう。この関数は以下のような型を持つでしょう。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:allFiles_signature}} -``` - -再帰を使ってこの関数を定義できます。まずは`ls`を使用してディレクトリの直接の子を列挙します。それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返ってくるでしょう。同時に`concatMap`を適用すると、この結果を平坦にできます。 - -最後に、cons演算子`:`を使って現在のファイルも含めます。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:allFiles_implementation}} -``` - -*補足*:実はcons演算子`:`は、不変な配列に対して効率性が悪いので、一般的には推奨されません。 -連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させることができます。 - -それではPSCiでこの関数を試してみましょう。 - -```text -> import Test.Examples -> import Data.Path - -> allFiles root - -[/,/bin/,/bin/cp,/bin/ls,/bin/mv,/etc/,/etc/hosts, ...] -``` - -すばらしいです。 -do記法で配列内包表記を使ってもこの関数を書くことができるので見ていきましょう。 - -逆向きの矢印は配列から要素を選択するのに相当することを思い出してください。 -最初の工程は引数の直接の子から要素を選択することです。 -それから、単にそのファイルに対してこの再帰関数を呼びします。 -do記法を使用しているので、再帰的な結果を全て連結する`concatMap`が暗黙に呼び出されています。 - -新しいバージョンは次のようになります。 - -```haskell -{{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}} -``` - -PSCiで新しいコードを試してみてください。同じ結果が返ってくるはずです。どちらのほうがわかりやすいかの選定はお任せします。 - -## 演習 - - 1. (簡単)ディレクトリの全てのサブディレクトリの中にある(ディレクトリを除く)全てのファイルを返すような関数`onlyFiles`を書いてみてください。 - 2. (普通)ファイルを名前で検索する関数`whereIs`を書いてください。 - この関数は型`Maybe Path`の値を返すものとします。 - この値が存在するなら、そのファイルがそのディレクトリに含まれているということを表します。 - この関数は次のように振る舞う必要があります。 - - ```text - > whereIs root "ls" - Just (/bin/) - - > whereIs root "cat" - Nothing - ``` - - *手掛かり*:この関数をdo記法を使った配列内包表記で書いてみましょう。 - 3. (難しい)`Path`を取って`Path`に最大のファイルと最小のファイルを1つずつ含む配列を返す関数`largestSmallest`を書いてください。 - *補足*:空配列や1要素の配列を返すことで、`Path`にゼロか1個のファイルがある場合についても考慮してください。 - -## まとめ - -この章では、アルゴリズムを簡潔に表現する手段として、PureScriptでの再帰の基本を説明しました。 -また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関数、及びこれらの概念を組み合わせた配列内包表記を導入しました。 -最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累積器引数を使用して末尾再帰形に関数を変換する方法を示しました。 diff --git a/text-ja/chapter5.md b/text-ja/chapter5.md deleted file mode 100644 index 3afe1547..00000000 --- a/text-ja/chapter5.md +++ /dev/null @@ -1,643 +0,0 @@ -# パターン照合 - -## この章の目標 - -この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱います。 - -パターン照合は関数型プログラミングにおける一般的な手法で、複数の場合に実装を分解することにより、開発者は水面下では複雑な動作をする関数を簡潔に書くことができます。 - -代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等の水準の表現力を可能にしています。パターン照合とも密接に関連しています。 - -この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラフィックスを描画し操作するためのライブラリを書くことです。 - -## プロジェクトの準備 - -この章のソースコードはファイル `src/Data/Picture.purs`で定義されています。 - -`Data.Picture`モジュールは、簡単な図形を表すデータ型 `Shape`や、図形の集合である型 -`Picture`、及びこれらの型を扱うための関数を定義しています。 - -このモジュールでは、データ構造の畳込みを行う関数を提供する `Data.Foldable`モジュールもインポートします。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:module_picture}} -``` - -`Data.Picture`モジュールは`Number`モジュールもインポートしますが、こちらは`as`キーワードを使います。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:picture_import_as}} -``` - -こうすると型や関数をモジュール内で使用できるようになりますが、`Number.max`のように*修飾名*を使ったときに限定されます。重複したインポートを避けたり、どのモジュールからインポートされたのかを明らかにするのに役立ちます。 - -*補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありません。 -`import Math as M`などのより短い名前にできますし、かなりよく見掛けます。 - -## 単純なパターン照合 - -それではコード例を見ることから始めましょう。 -パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになります。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcd}} -``` - -このアルゴリズムはユークリッドの互除法と呼ばれています。 -その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が見つかるでしょう。 -パターン照合の利点の1つは、上記のようにコードを場合分けして定義でき、数学関数の定義と似たような簡潔で宣言型なコードを書くことができることです。 - -パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作します。 -この定義の各行は*選択肢*や*場合*と呼ばれています。 -等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ以上のパターンで構成されています。 -場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなければならない条件を表現しています。 -それぞれの場合は上からこの順番に試されていき、最初に入力に適合した場合が返り値を決定します。 - -例えば`gcd`関数は次の手順で評価されます。 - -- まず最初の場合が試されます。 - 第2引数がゼロの場合、関数は `n`(最初の引数)を返します。 -- そうでなければ、2番目の場合が試されます。 - 最初の引数がゼロの場合、関数は `m`(第2引数)を返します。 -- それ以外の場合、関数は最後の行の式を評価して返します。 - -なお、パターンでは値を名前に束縛できます。 -この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛しています。 -さまざまな種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力の引数から名前を選ぶさまざまな方法に対応することがわかるでしょう。 - -## 単純なパターン - -上記のコード例では、2種類のパターンを示しました。 - -- `Int`型の値が正確に一致する場合にのみ適合する、整数直値パターン -- 引数を名前に束縛する、変数パターン - -単純なパターンには他にも種類があります。 - -- `Number`、`String`、`Char`、そして`Boolean`といった直値 -- どんな引数とも適合するが名前に束縛はしない、アンダースコア (`_`) で表されるワイルドカードパターン - -ここではこれらの単純なパターンを使用して、もう2つ例を示します。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:fromString}} - -{{#include ../exercises/chapter5/src/ChapterExamples.purs:toString}} -``` - -PSCiでこれらの関数を試してみてください。 - -## ガード - -ユークリッドの互除法の例では、`m > n`のときと `m <= n`のときの2つに分岐するために `if .. then .. else`式を使っていました。こういうときには他に _ガード_ (guard) を使うという選択肢もあります。 - -ガードはパターンによる制約に加えて満たされなくてはいけない真偽値の式です。 -ガードを使用してユークリッドの互除法を書き直すと、次のようになります。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcdV2}} -``` - -この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を付け加えています。最後の行でのガードは式`otherwise`を使っており、キーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。 - -```text -> :type otherwise -Boolean - -> otherwise -true -``` - -この例が示すように、ガードは等号の左側に現れ、パイプ文字 (`|`) でパターンのリストと区切られています。 - -## 演習 - -1. (簡単)パターン照合を使用して、階乗関数`factorial`を書いてみましょう。 - *手掛かり*:入力がゼロのときとゼロでないときの、2つの特殊な場合を考えてみてください。 - *補足*:これは前の章の例の反復ですが、ここでは自力で書き直せるかやってみてください。 -1. (普通)\\( (1 + x) ^ n \\)を多項式展開した式にある\\( x ^ k - \\)の項の係数を求める関数`binomial`を書いてください。 - これは`n`要素の集合から`k`要素の部分集合を選ぶ方法の数と同じです。 - 数式\\( n! / k! (n - k)! \\)を使ってください。 - ここで \\( ! \\) は前に書いた階乗関数です。 - *手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。 - 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、もっと使用例を追加してみてください。 -1. (普通)[_パスカルの法則_](https://en.wikipedia.org/wiki/Pascal%27s_rule)を使って前の演習と同じ2項係数を計算する関数`pascal`を書いてください。 - -## 配列パターン - -*配列直値パターン*は、固定長の配列に対して照合する方法を提供します。 -例えば空の配列であるか判定する関数`isEmpty`を書きたいとします。 -最初の選択肢に空の配列パターン (`[]`) を用いるとこれを実現できます。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}} -``` - -次の関数では、長さ5の配列と適合し、配列の5つの要素をそれぞれ違った方法で束縛しています。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:takeFive}} -``` - -最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にのみ適合します。 -その場合、関数は第3要素と第4要素の積を返します。 -それ以外の場合は、関数は0を返します。 -例えばPSCiで試してみると次のようになります。 - -```text -> :paste -… takeFive [0, 1, a, b, _] = a * b -… takeFive _ = 0 -… ^D - -> takeFive [0, 1, 2, 3, 4] -6 - -> takeFive [1, 2, 3, 4, 5] -0 - -> takeFive [] -0 -``` - -配列の直値パターンでは、固定長の配列と一致させることはできますが、PureScriptは不特定の長さの配列を照合させる手段を提供していません。 -そのような方法で不変な配列を分解すると、実行速度が低下する可能性があるためです。 -このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めします。 -その他の操作について、より優れた漸近性能を提供するデータ構造も存在します。 - -## レコードパターンと行多相 - -*レコードパターン*は(ご想像の通り)レコードに照合します。 - -レコードパターンはレコード直値にほぼ見た目が似ていますが、コロンの右に値を置くのではなく、それぞれのフィールドで束縛子を指定します。 - -例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレコードに照合し、これらのフィールドの値はそれぞれ `x`と -`y`という名前に束縛されます。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:showPerson}} -``` - -レコードパターンはPureScriptの型システムの興味深い機能である*行多相*の良い例となっています。 -もし上の`showPerson`を型シグネチャなしで定義していたとすると、この型はどのように推論されるのでしょうか。 -面白いことに、推論される型は上で与えた型とは同じではありません。 - -```text -> showPerson { first: x, last: y } = y <> ", " <> x - -> :type showPerson -forall r. { first :: String, last :: String | r } -> String -``` - -この型変数 `r`は何でしょうか。 -PSCiで`showPerson`を使ってみると、面白いことがわかります。 - -```text -> showPerson { first: "Phil", last: "Freeman" } -"Freeman, Phil" - -> showPerson { first: "Phil", last: "Freeman", location: "Los Angeles" } -"Freeman, Phil" -``` - -レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま動作するのです。レコードに少なくとも型が`String`であるようなフィールド -`first`と `last`が含まれていれば、関数適用は正しく型付けされます。しかし、フィールドが _不足_ していると、 -`showPerson`の呼び出しは _不正_ となります。 - -```text -> showPerson { first: "Phil" } - -Type of expression lacks required label "last" -``` - -`showPerson`の新しい型シグネチャを読むと、「`String`な`first`と`last`フィールド _と他のフィールドを何でも_ -持つあらゆるレコードを取り、`String`を返す」となります。なお、この挙動は元の`showPerson`のものとは異なります。行変数`r`がなければ`showPerson`は -_厳密に_ `first`と`last`フィールドしかないレコードのみを受け付けます。 - -なお、次のように書くこともできます。 - -```haskell -> showPerson p = p.last <> ", " <> p.first -``` - -この場合も、 PSCiは先ほどと同じ型を推論するでしょう。 - -## レコード同名利用 - -`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と -`y`という名前の値に束縛していたのでした。別の方法として、フィールド名自体を再利用するだけで、このようなパターン照合を次のように単純化できます。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:showPersonV2}} -``` - -ここでは、プロパティの名前のみを指定し、名前に導入したい値を指定する必要はありません。これは _レコード同名利用_ (record pun) -と呼ばれます。 - -レコード同名利用はレコードの*構築*にも使用できます。 -例えば、スコープに `first`と `last`という名前の値があれば、`{ first, last }`を使って人物レコードを作ることができます。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:unknownPerson}} -``` - -こうすると、状況によってはコードの可読性向上に役立ちます。 - -## 入れ子になったパターン - -配列パターンとレコードパターンはどちらも小さなパターンを組み合わせることで大きなパターンを構成しています。これまでの例ではほとんどの場合で配列パターンとレコードパターンの内部に単純なパターンを使用していましたが、パターンを自由に*入れ子*にできることも知っておくのが大切です。入れ子になったパターンを使うと、潜在的に複雑なデータ型に対して条件分岐を用いて関数を定義できるようになります。 - -例えばこのコードは2つのレコードパターンを組み合わせています。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:livesInLA}} -``` - -## 名前付きパターン - -入れ子のパターンを使う場合、パターンには*名前を付け*てスコープに名前を追加で持ち込むことができます。 -任意のパターンに名前を付けるには、 `@`記号を使います。 - -例えば次の関数は2要素配列を整列するもので、2つの要素に名前を付けていますが、配列自身にも名前を付けています。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}} -``` - -このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。なおもし入力の配列が _厳密に_ -2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返しています。 - -## 演習 - -1. (簡単)レコードパターンを使って、2つの `Person`レコードが同じ都市にいるか調べる関数 `sameCity`を定義してみましょう。 -1. (普通)行多相を考慮すると、 `sameCity`関数の最も一般的な型は何でしょうか。 - 先ほど定義した`livesInLA`関数についてはどうでしょうか。 - *補足*:この演習にテストはありません。 -1. (普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数`fromSingleton`を書いてみましょう。1要素だけを持つ配列でない場合、関数は指定された既定値を返します。この関数は - `forall a. a -> Array a -> a`という型を持っています。 - -## Case式 - -パターンは最上位にある関数宣言だけに現れるわけではありません。`case`式を使って計算の途中の値に対してパターン照合を使うことができます。case式には無名関数に似たような便利さがあります。関数に名前を与えることがいつも望ましいわけではないように、パターン照合を使いたいためだけに関数に名前をつけるようなことを避けられるようになります。 - -例を示しましょう。 -次の関数は、配列の「最長ゼロ末尾」(和がゼロであるような、最も長い配列の末尾)を計算します。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:lzsImport}} - -{{#include ../exercises/chapter5/src/ChapterExamples.purs:lzs}} -``` - -以下は一例です。 - -```text -> lzs [1, 2, 3, 4] -[] - -> lzs [1, -1, -2, 3] -[-1, -2, 3] -``` - -この関数は場合ごとの分析によって動作します。もし配列が空なら、唯一の選択肢は空の配列を返すことです。配列が空でない場合は、更に2つの場合に分けるためにまず -`case`式を使用します。配列の合計がゼロであれば、配列全体を返します。そうでなければ、配列の残りに対して再帰します。 - -## パターン照合の失敗と部分関数 - -case式のパターンを順番に照合していって、もし選択肢の何れの場合も入力が適合しなかった時は何が起こるのでしょうか。 -この場合、*パターン照合失敗*によって、case式は実行時に失敗します。 - -簡単な例でこの動作を見てみましょう。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:unsafePartialImport}} - -{{#include ../exercises/chapter5/src/ChapterExamples.purs:partialFunction}} -``` - -この関数は単一の場合しか含んでおらず、単一の入力である`true`にのみ照合します。このファイルをコンパイルしてPSCiでそれ以外の値を与えてテストすると、実行時エラーが発生します。 - -```text -> partialFunction false - -Failed pattern match -``` - -どんな入力の組み合わせに対しても値を返すような関数は _全関数_ (total function) と呼ばれ、そうでない関数は _部分的_ -(partial) であると呼ばれます。 - -一般的には、可能な限り全関数として定義したほうが良いと考えられています。 -もし関数が何らかの妥当な入力の集合について結果を返さないことがわかっているなら、大抵は失敗であることを示すことができる値を返すほうがよいでしょう。 -例えば何らかの`a`についての型`Maybe a`で、妥当な結果を返せないときは`Nothing`を使います。 -この方法なら、型安全な方法で値の有無を示すことができます。 - -PureScriptコンパイラは、パターンマッチが不完全で関数が全関数ではないことを検出するとエラーを生成します。 -部分関数が安全である場合、`unsafePartial`関数を使ってこれらのエラーを抑制できます(その部分関数が安全だと言い切れるなら)。 -もし上記の `unsafePartial`関数の呼び出しを取り除くと、コンパイラは次のエラーを生成します。 - -```text -A case expression could not be determined to cover all inputs. -The following additional cases are required to cover all inputs: - - false -``` - -これは値`false`が、定義されたどのパターンとも一致しないことを示しています。 -一般にこれらの警告には、複数の不一致な場合が含まれることがあります。 - -上記の型シグネチャも省略した場合は、次のようになります。 - -```haskell -partialFunction true = true -``` - -このとき、PSCiは興味深い型を推論します。 - -```text -> :type partialFunction - -Partial => Boolean -> Boolean -``` - -本書ではのちに`=>`記号を含むいろいろな型を見ることになります(これらは*型クラス*に関連しています)。しかし、今のところは、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。 - -コンパイラは、定義されたパターンが _冗長_ であることを検出した場合(前の方に定義されたパターンのみに一致する場合)でも警告を生成します。 - -```haskell -redundantCase :: Boolean -> Boolean -redundantCase true = true -redundantCase false = false -redundantCase false = false -``` - -このとき、最後の場合は冗長であると正しく検出されます。 - -```text -A case expression contains unreachable cases: - - false -``` - -*補足*:PSCiは警告を表示しないので、この例を再現するには、この関数をファイルとして保存し、 `pulp build`を使ってコンパイルします。 - -## 代数的データ型 - -この節では _代数的データ型_ (algebraic data type, _ADT_) -と呼ばれる、PureScriptの型システムの機能を導入します。この機能はパターン照合と地続きの関係があります。 - -しかしまずは切り口となる例について考えていきます。この例では単純なベクターグラフィックスライブラリの実装というこの章の課題を解決する基礎を与えます。 - -直線、矩形、円、テキストなどの単純な図形の種類を表現する型を定義したいとします。 -オブジェクト指向言語では、恐らくインターフェースもしくは抽象クラス -`Shape`を定義し、使いたいそれぞれの図形について具体的なサブクラスを定義するでしょう。 - -しかし、この方針は大きな欠点を1つ抱えています。 -`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に把握し、`Shape`インターフェースに定義する必要があるのです。 -このため、モジュール性を壊さずに新しい操作を追加することが難しくなります。 - -もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決する型安全な方法を提供します。モジュール性のある方法で -`Shape`に新たな操作を定義し、型安全性を維持できます。 - -代数的データ型としてどのように`Shape`が表現されるかを次に示します。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:Shape}} - -{{#include ../exercises/chapter5/src/Data/Picture.purs:Point}} -``` - -この宣言では`Shape`をそれぞれの構築子の直和として定義しており、各構築子では含まれるデータを指定します。 -`Shape`は、中央 `Point`と半径(数値)を持つ `Circle`か、`Rectangle`、 `Line`、 `Text`の何れかです。 -他に`Shape`型の値を構築する方法はありません。 - -代数的データ型の定義はキーワード `data`から始まり、それに新しい型の名前と任意個の型引数が続きます。その型の構築子(あるいは _データ構築子_ -(data constructor))は等号の後に定義され、パイプ文字 (`|`) -で区切られます。ADTの構築子が持つデータは原始型に限りません。構築子にはレコード、配列、また他のADTさえも含むことができます。 - -それではPureScriptの標準ライブラリから別の例を見てみましょう。 -オプショナルな値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。 -`maybe`パッケージでは `Maybe`を次のように定義しています。 - -```haskell -data Maybe a = Nothing | Just a -``` - -この例では型引数 `a`の使用方法を示しています。パイプ文字を「または」と読むことにすると、この定義は「`Maybe a`型の値は、無い -(`Nothing`) か、ただの (`Just`) 型 `a`の値だ」とほぼ英語のように読むことができます。 - -なおデータ定義のどこにも構文`forall a`を使っていません。 -`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義するときは使われません。 - -データ構築子は再帰的なデータ構造を定義するためにも使用できます。更に例を挙げると、要素が型 -`a`の単方向連結リストのデータ型の定義はこのようになります。 - -```haskell -data List a = Nil | Cons a (List a) -``` - -この例は `lists`パッケージから持ってきました。 -ここで `Nil`構築子は空のリストを表しており、`Cons`は先頭となる要素と尾鰭から空でないリストを作成するために使われます。 -`Cons`の2つ目のフィールドでデータ型 `List a`を使用しており、再帰的なデータ型になっていることに注目してください。 - -## ADTの使用 - -代数的データ型の構築子を使用して値を構築するのはとても簡単です。 -対応する構築子に含まれるデータに応じた引数を用意し、その構築子を単に関数のように適用するだけです。 - -例えば、上で定義した `Line`構築子は2つの `Point`を必要としていますので、`Line`構築子を使って `Shape`を構築するには、型 -`Point`の2つの引数を与えなければなりません。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:exampleLine}} -``` - -さて、代数的データ型で値を構築することは簡単ですが、これをどうやって使ったらよいのでしょうか。 -ここで代数的データ型とパターン照合との重要な接点が見えてきます。 -代数的データ型の値を消費する唯一の方法は構築子に照合するパターンを使うことです。 - -例を見てみましょう。 -`Shape`を `String`に変換したいとします。 -`Shape`を構築するのにどの構築子が使用されたかを調べるには、パターン照合を使用しなければなりません。 -これには次のようにします。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:showShape}} - -{{#include ../exercises/chapter5/src/Data/Picture.purs:showPoint}} -``` - -各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できます。 -`showShape`の最初の場合を考えてみましょう。 -もし `Shape`が `Circle`構築子に適合した場合、2つの変数パターン `c`と -`r`を使って`Circle`の引数(中心と半径)がスコープに導入されます。その他の場合も同様です。 - -## 演習 - -1. (簡単)`Circle`(型は`Shape`)を構築する関数`circleAtOrigin`を書いてください。 - 中心は原点にあり、半径は`10.0`です。 -1. (普通)`Shape`を原点を中心として`2.0`倍に拡大する関数`doubleScaleAndCenter`を書いてみましょう。 -1. (普通)`Shape`からテキストを抽出する関数`shapeText`を書いてください。 - この関数は`Maybe - String`を返しますが、もし入力が`Text`を使用して構築されたのでなければ、返り値には`Nothing`構築子を使ってください。 - -## Newtype - -代数的データ型の特殊な場合として、 _newtype_ と呼ばれるものがあります。newtypeはキーワード `data`の代わりにキーワード -`newtype`を使用して導入します。 - -newtype宣言では*過不足なく1つだけの*構築子を定義しなければならず、その構築子は*過不足なく1つだけの*引数を取る必要があります。 -つまり、newtype宣言は既存の型に新しい名前を与えるものなのです。 -実際、newtypeの値は、元の型と同じ実行時表現を持ってるので、実行時性能のオーバーヘッドがありません。 -しかし、これらは型システムの観点から区別されます。 -型安全性に追加の層を与えるのです。 - -例として、ボルト、アンペア、オームのような単位を表現するために、`Number`の型レベルの別名を定義したくなる場合があるかもしれません。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:electricalUnits}} -``` - -それからこれらの型を使う関数と値を定義します。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:calculateCurrent}} -``` - -これによりつまらないミスを防ぐことができます。例えば電源 _なし_ に _2つ_ の電球により生み出される電流を計算しようとするなどです。 - -```haskell -current :: Amp -current = calculateCurrent lightbulb lightbulb -{- -TypesDoNotUnify: - current = calculateCurrent lightbulb lightbulb - ^^^^^^^^^ - Could not match type - Ohm - with type - Volt --} -``` - -もし`newtype`なしに単なる`Number`を使っていたら、コンパイラはこのミスを捕捉できません。 - -```haskell --- これもコンパイルできますが、型安全ではありません。 -calculateCurrent :: Number -> Number -> Number -calculateCurrent v r = v / r - -battery :: Number -battery = 1.5 - -lightbulb :: Number -lightbulb = 500.0 - -current :: Number -current = calculateCurrent lightbulb lightbulb -- 捕捉されないミス -``` - -なお、newtypeは単一の構築子しかとれず、構築子は単一の値でなくてはなりませんが、newtypeは任意の数の型変数を取ることが*できます*。 -例えば以下のnewtypeは妥当な定義です(`err`と`a`は型変数で、`CouldError`構築子は型`Either err -a`の*単一*の値を期待します)。 - -```Haskell -newtype CouldError err a = CouldError (Either err a) -``` - -また、newtypeの構築子はよくnewtype自身と同じ名前を持つことがあります。ただこれは必須ではありません。例えば別個の名前であっても妥当です。 - -```haskell -{{#include ../exercises/chapter5/src/ChapterExamples.purs:Coulomb}} -``` - -この場合`Coulomb`は*型構築子*(引数はゼロ)で`MakeCoulomb`は _データ構築子_ -です。これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名前に一意性があります。これは全てのADTについて言えることです。なお、型構築子とデータ構築子は異なる名前を持つことができますが、実際には同じ名前を共有するのが普通です。前述の`Amp`と`Volt`の場合がこれです。 - -newtypeの別の応用は、実行時表現を変えることなく、既存の型に異なる _挙動_ を加えることです。その利用例については次章で _型クラス_ -をお話しするときに押さえます。 - -## 演習 - -1. (簡単)`Watt`を`Number`の`newtype`として定義してください。それからこの新しい`Watt`型と前述の`Amp`と`Volt`の定義を使って`calculateWattage`関数を定義してください。 - -```haskell -calculateWattage :: Amp -> Volt -> Watt -``` - -`Watt`中のワット数は与えられた`Amp`中の電流と与えられた`Volt`の電圧の積で計算できます。 - -## ベクターグラフィックスライブラリ - -これまで定義してきたデータ型を使って、ベクターグラフィックスを扱う簡単なライブラリを作成していきましょう。 - -ただの `Shape`の配列であるような、 `Picture`という型同義語を定義しておきます。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:Picture}} -``` - -デバッグしていると `Picture`を `String`として表示できるようにしたくなることもあるでしょう。これはパターン照合を使用して定義された -`showPicture`関数でできます。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:showPicture}} -``` - -試してみましょう。 -モジュールを `spago build`でコンパイルし、 `spago repl`でPSCiを開きます。 - -```text -$ spago build -$ spago repl - -> import Data.Picture - -> showPicture [ Line { x: 0.0, y: 0.0 } { x: 1.0, y: 1.0 } ] - -["Line [start: (0.0, 0.0), end: (1.0, 1.0)]"] -``` - -## 外接矩形の算出 - -このモジュールのコード例には、 `Picture`の最小外接矩形を計算する関数 `bounds`が含まれています。 - -`Bounds`型は外接矩形を定義します。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:Bounds}} -``` - -`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累積するため、`bounds`には `Data.Foldable`の -`foldl`関数を使用しています。 - -```haskell -{{#include ../exercises/chapter5/src/Data/Picture.purs:bounds}} -``` - -基底の場合では、空の -`Picture`の最小外接矩形を求める必要がありますが、`emptyBounds`で定義される空の外接矩形がその条件を満たしています。 - -累積関数 `combine`は `where`ブロックで定義されています。`combine`は -`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`を引数にとり、ユーザ定義の演算子 -`union`を使って2つの外接矩形の和を計算しています。`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。 - -## 演習 - -1. (普通)ベクターグラフィックライブラリを拡張し、`Shape`の面積を計算する新しい操作 `area`を追加してください。 - この演習の目的上は、線分やテキストの面積は0であるものとしてください。 -1. (難しい)`Shape`型を新しいデータ構築子 `Clipped`で拡張してください。 - `Clipped`は他の `Picture`を矩形に切り抜きます。 - 切り抜かれた図形の境界を計算できるよう、`shapeBounds`関数を拡張してください。 - なお、これにより`Shape`は再帰的なデータ型になります。 - *手掛かり* :コンパイラは必要に応じて他の関数を拡張するのに付き添ってくれるでしょう。 - -## まとめ - -この章では、関数型プログラミングから基本的ながら強力なテクニックであるパターン照合を扱いました。複雑なデータ構造の一部分と照合するために、簡単なパターンの使い方だけではなく、配列パターンやレコードパターンを使った深さのあるデータ構造の一部分との照合方法を見てきました。 - -また、この章ではパターン照合に密接に関連する代数的データ型を紹介しました。代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上でモジュール性のある方法がもたらされることを見てきました。 - -最後に強力な抽象化である _行多相_ を扱いました。これにより多くの既存のJavaScript関数に型を与えられます。 - -本書では今後も代数的データ型とパターン照合をいろんなところで使用するので、今のうちにこれらに習熟しておくと後で実を結ぶことでしょう。これ以外にも独自の代数的データ型を作成し、パターン照合を使用してそれらの型を使う関数を書いてみてください。 diff --git a/text-ja/chapter6.md b/text-ja/chapter6.md deleted file mode 100644 index e2c79526..00000000 --- a/text-ja/chapter6.md +++ /dev/null @@ -1,896 +0,0 @@ -# 型クラス - -## この章の目標 - -この章では、PureScriptの型システムによって可能になる強力な抽象化の手法である、型クラスを導入します。 - -この章ではデータ構造をハッシュ化するためのライブラリを題材に説明していきます。データ自身の構造について直接考えることなく複雑な構造のデータのハッシュ値を求める上で、型クラスの仕組みがどのようにして働くのかを見ていきます。 - -また、PureScriptのPreludeや標準ライブラリに含まれる、標準的な型クラスも見ていきます。PureScriptのコードは概念を簡潔に表現するために型クラスの強力さに大きく依存しているので、これらのクラスに慣れておくと役に立つでしょう。 - -オブジェクト指向の方面から入って来た方は、「クラス」という単語がそれまで馴染みのあるものとこの文脈とでは _かなり_ -異なるものを意味していることに注意してください。 - -## プロジェクトの準備 - -この章のソースコードは、ファイル `src/data/Hashable.purs`で定義されています。 - -このプロジェクトには以下の依存関係があります。 - -- `maybe`: オプショナルな値を表す `Maybe`データ型が定義されています。 -- `tuples`: 値の組を表す `Tuple`データ型が定義されています。 -- `either`: 非交和を表す `Either`データ型が定義されています。 -- `strings`: 文字列を操作する関数が定義されています。 -- `functions`: PureScriptの関数を定義するための補助関数が定義されています。 - -モジュール `Data.Hashable`では、これらのパッケージによって提供されるモジュールの幾つかをインポートしています。 - -## 見せて! - -型クラスの最初の簡単な例は、既に何回か見たことがある関数で提供されています。 -`show`は何らかの値を取り、文字列として表示する関数です。 - -`show`は `Prelude`モジュールの `Show`と呼ばれる型クラスで次のように定義されています。 - -```haskell -class Show a where - show :: a -> String -``` - -このコードでは、型変数 `a`でパラメータ化された、`Show`という新しい _型クラス_ (type class) を宣言しています。 - -型クラス _インスタンス_ には、型クラスで定義された関数の、その型に特殊化された実装が含まれています。 - -例えば、Preludeにある `Boolean`値に対する `Show`型クラスインスタンスの定義は次の通りです。 - -```haskell -instance Show Boolean where - show true = "true" - show false = "false" -``` - -このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。 -PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインスタンスに名前をつけます。このとき、 -_`Boolean`型は `Show`型クラスに属している_ といいます。 - -PSCiで、いろいろな型の値を`Show`型クラスを使って表示してみましょう。 - -```text -> import Prelude - -> show true -"true" - -> show 1.0 -"1.0" - -> show "Hello World" -"\"Hello World\"" -``` - -この例ではさまざまなプリミティブ型の値を `show`しましたが、もっと複雑な型を持つ値も`show`できます。 - -```text -> import Data.Tuple - -> show (Tuple 1 true) -"(Tuple 1 true)" - -> import Data.Maybe - -> show (Just "testing") -"(Just \"testing\")" -``` - -`show`の出力は、REPLに(あるいは`.purs`ファイルに)もう一度貼り付ければ、表示されたものを再作成できるような文字列であるべきです。以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出して、引用符なしに文字列を表示するものです。`unit`の表示は無視してください。第8章で`Effect`を調べるときに押さえます。`Effect`を持つものには`log`などがあります。 - -```text -> import Effect.Console - -> logShow (Tuple 1 true) -(Tuple 1 true) -unit - -> logShow (Just "testing") -(Just "testing") -unit -``` - -型 `Data.Either`の値を表示しようとすると、興味深いエラーメッセージが表示されます。 - -```text -> import Data.Either -> show (Left 10) - -The inferred type - - forall a. Show a => String - -has type variables which are not mentioned in the body of the type. Consider adding a type annotation. -``` - -ここでの問題は `show`しようとしている型に対する -`Show`インスタンスが存在しないということではなく、PSCiがこの型を推論できなかったということです。このエラーメッセージで _未知の型_ -`a`と表示されているのがそれです。 - -`::`演算子を使って式に対して型注釈を加えると、PSCiが正しい型クラスインスタンスを選ぶことができるようになります。 - -```text -> show (Left 10 :: Either Int String) -"(Left 10)" -``` - -`Show`インスタンスを全く持っていない型もあります。 -関数の型 `->`がその一例です。 -`Int`から `Int`への関数を `show`しようとすると、型検証器によってその旨のエラーメッセージが表示されます。 - -```text -> import Prelude -> show $ \n -> n + 1 - -No type class instance was found for - - Data.Show.Show (Int -> Int) -``` - -型クラスインスタンスは次の2つのうち何れかの形で定義されます。 -型クラスが定義されている同じモジュールで定義するか、型クラスに「属して」いる型と同じモジュールで定義するかです。 -これらとは別の場所で定義されるインスタンスは[「孤立インスタンス」](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#orphan-instances)と呼ばれ、PureScriptコンパイラでは許されていません。 -この章の演習の幾つかでは、その型の型クラスインスタンスを定義できるように、型の定義を自分の`MySolutions`モジュールに複製する必要があります。 - -## 演習 - -1. (簡単)`Show`インスタンスを`Point`に定義してください。 - 前の章の`showPoint`関数と同じ出力に一致するようにしてください。 - *補足*:`Point`はここでは(`type`同義語ではなく)`newtype`です。 - そのため`show`の仕方を変えられます。 - こうでもしないとレコードへの既定の`Show`インスタンスから逃れられません。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Point}} - ``` - -## よく見かける型クラス - -この節では、Preludeや標準ライブラリで定義されている標準的な型クラスを幾つか見ていきましょう。 -これらの型クラスはPureScript特有の抽象化をする上で多くのよくあるパターンの基礎を形成しています。 -そのため、これらの関数の基本についてよく理解しておくことを強くお勧めします。 - -### Eq - -`Eq`型クラスは、2つの値が等しいかどうかを調べる`eq`関数を定義しています。 -等値演算子 (`==`) は`eq`の別名にすぎません。 - -```haskell -class Eq a where - eq :: a -> a -> Boolean -``` - -なお、異なる型の2つの値を比較しても意味がありませんから、等しいにせよ等しくないにせよ2つの引数は同じ型を持つ必要があります。 - -PSCiで `Eq`型クラスを試してみましょう。 - -```text -> 1 == 2 -false - -> "Test" == "Test" -true -``` - -### Ord - -`Ord`型クラスは順序付け可能な型に対して2つの値を比較する `compare`関数を定義します。比較演算子 `<`、 `>`と、その仲間の厳密な大小比較ではない`<=`、 `>=`も、`compare`を使って定義されます。 - -*補足*:以下の例ではクラスシグネチャに`<=`が含まれています。 -この文脈での`<=`の使われ方はEqがOrdの上位クラスであり、比較演算子としての`<=`の用途を表す意図はありません。 -後述の[上位クラス](#上位クラス)の節を参照してください。 - -```haskell -data Ordering = LT | EQ | GT - -class Eq a <= Ord a where - compare :: a -> a -> Ordering -``` - -`compare`関数は2つの値を比較して `Ordering`の3つの値のうち何れかを返します。 - -- `LT`- 最初の引数が2番目の値より小さいとき -- `EQ`- 最初の引数が2番目の値と等しい(または比較できない)とき -- `GT`- 最初の引数が2番目の値より大きいとき - -ここでも`compare`関数についてPSCiで試してみましょう。 - -```text -> compare 1 2 -LT - -> compare "A" "Z" -LT -``` - -### Field - -`Field`型クラスは加算、減算、乗算、除算などの数値演算子が使える型を示します。必要に応じて再利用できるように、これらの演算子を抽象化するわけです。 - -*補足*:型クラス `Eq`や `Ord`のクラスとちょうど同じように、`Field`型のクラスはPureScriptコンパイラで特別に扱われ、`1 + -2 * 3`のような単純な式は単純なJavaScriptへと変換されます。 -型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。 - -```haskell -class EuclideanRing a <= Field a -``` - -`Field`型クラスは、幾つかのより抽象的な*上位クラス* (Super Class) が組み合わさってできています。 -これは、その型は`Field`型クラスの操作の全てを提供しているわけではないが、その一部を提供する、というように抽象的に説明できます。 -例えば、自然数の型は加算及び乗算については閉じていますが、減算については閉じていません。 -そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタンスですが、`Ring`や`Field`のインスタンスではありません。 - -上位クラスについては、この章の後半で詳しく説明します。 -しかし、全ての[数値型クラスの階層](https://a-guide-to-the-purescript-numeric-hierarchy.readthedocs.io/en/latest/introduction.html)([チートシート](https://harry.garrood.me/numeric-hierarchy-overview/))について述べるのはこの章の目的から外れています。 -この内容に興味のある読者は`prelude`内の `Field`に関するドキュメントを参照してください。 - -### 半群とモノイド - -`Semigroup`(半群)型クラスは、2つの値を連結する演算子 `append`を提供する型を示します。 - -```haskell -class Semigroup a where - append :: a -> a -> a -``` - -文字列は普通の文字列連結について半群をなし、同様に配列も半群をなします。その他の標準的なインスタンスの幾つかは、 -`prelude`パッケージで提供されています。 - -以前に見た `<>`連結演算子は、 `append`の別名として提供されています。 - -(`prelude`パッケージで提供されている)`Monoid`型クラスには`mempty`という名前の空の値の概念があり、`Semigroup`型クラスを拡張します。 - -```haskell -class Semigroup m <= Monoid m where - mempty :: m -``` - -ここでも文字列や配列はモノイドの簡単な例になっています。 - -`Monoid`型クラスインスタンスでは、「空」の値から始めて新たな値を合成していき、その型で*累積*した結果を返すにはどうするかを記述する型クラスです。 -例えば、畳み込みを使って幾つかのモノイドの値の配列を連結する関数を書くことができます。 -PSCiで試すと次のようになります。 - -```haskell -> import Prelude -> import Data.Monoid -> import Data.Foldable - -> foldl append mempty ["Hello", " ", "World"] -"Hello World" - -> foldl append mempty [[1, 2, 3], [4, 5], [6]] -[1,2,3,4,5,6] -``` - -`prelude`パッケージにはモノイドと半群の多くの例を提供しており、以降もこれらを本書で扱っていきます。 - -### Foldable - -`Monoid`型クラスが畳み込みの結果になるような型を示す一方、`Foldable`型クラスは畳み込みの元のデータとして使えるような型構築子を示しています。 - -また、 `Foldable`型クラスは配列や -`Maybe`などの幾つかの標準的なコンテナのインスタンスを含む`foldable-traversable`パッケージで提供されています。 - -`Foldable`クラスに属する関数の型シグネチャは、これまで見てきたものよりも少し複雑です。 - -```haskell -class Foldable f where - foldr :: forall a b. (a -> b -> b) -> b -> f a -> b - foldl :: forall a b. (b -> a -> b) -> b -> f a -> b - foldMap :: forall a m. Monoid m => (a -> m) -> f a -> m -``` - -この定義は `f`を配列の型構築子として特殊化して考えてみるとわかりやすくなります。 -この場合、全ての `a`について `f a`を `Array a`に置き換える事ができますが、`foldl`と -`foldr`の型が、最初に見た配列に対する畳み込みの型になるとわかります。 - -`foldMap`についてはどうでしょうか。 -これは `forall a m. Monoid m => (a -> m) -> Array a -> m`になります。 -この型シグネチャは、型 `m`が `Monoid`型クラスのインスタンスであればどんな型でも返り値の型として選ぶことができると言っています。 -配列の要素をそのモノイドの値へと変換する関数を与えれば、そのモノイドの構造を利用して配列を畳み込み、1つの値にして返すことができます。 - -それではPSCiで `foldMap`を試してみましょう。 - -```text -> import Data.Foldable - -> foldMap show [1, 2, 3, 4, 5] -"12345" -``` - -ここでは繋ぎ合わせるためのモノイドとして文字列を、そして`Int`を文字列として表示する -`show`関数を選びました。そうして数の配列を渡すと、それぞれの数を `show`して1つの文字列へと連結した結果が出力されました。 - -しかし畳み込み可能な型は配列だけではありません。`foldable-traversable`では `Maybe`や `Tuple`のような型の -`Foldable`インスタンスが定義されており、`lists`のような他のライブラリでは、そのライブラリのそれぞれのデータ型に対して -`Foldable`インスタンスが定義されています。`Foldable`は _順序付きコンテナ_ (ordered container) -の概念を見据えたものなのです。 - -### 関手と型クラス則 - -PureScriptで副作用を伴う関数型プログラミングのスタイルを可能にするための`Functor`と `Applicative`、 -`Monad`といった型クラスがPreludeでは定義されています。これらの抽象化については後ほど本書で扱いますが、まずは`map`関数の形で既に見てきた`Functor`型クラスの定義を見てみましょう。 - -```haskell -class Functor f where - map :: forall a b. (a -> b) -> f a -> f b -``` - -`map`関数(別名`<$>`)は関数をそのデータ構造まで「持ち上げる」(lift) ことができます。 -ここで「持ち上げ」という言葉の具体的な定義は問題のデータ構造に依りますが、既に幾つかの単純な型についてその動作を見てきました。 - -```text -> import Prelude - -> map (\n -> n < 3) [1, 2, 3, 4, 5] -[true, true, false, false, false] - -> import Data.Maybe -> import Data.String (length) - -> map length (Just "testing") -(Just 7) -``` - -`map`演算子は様々な構造の上でそれぞれ異なる挙動をしますが、 `map`演算子の意味はどのように理解すればいいのでしょうか。 - -直感的には、 `map`演算子はコンテナのそれぞれの要素へ関数を適用し、その結果から元のデータと同じ形状を持った新しいコンテナを構築するものとできます。 -しかし、この着想を精密にするにはどうしたらいいでしょうか。 - -`Functor`の型クラスのインスタンスは、*関手則*と呼ばれる法則を順守するものと期待されています。 - -- `map identity xs = xs` -- `map g (map f xs) = map (g <<< f) xs` - -最初の法則は _恒等射律_ (identity law) -です。これは、恒等関数(引数を変えずに返す関数)をその構造まで持ち上げると、元の構造をそのまま返すという意味です。恒等関数は入力を変更しませんから、これは理にかなっています。 - -第二の法則は _合成律_ (composition law) -です。構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。 - -「持ち上げ」の一般的な意味が何であれ、データ構造に対する持ち上げ関数の正しい定義はこれらの法則に従っていなければなりません。 - -標準の型クラスの多くには、このような法則が付随しています。 -一般に、型クラスに与えられた法則は、型クラスの関数に構造を与え、普遍的にインスタンスについて調べられるようにします。 -興味のある読者は、既に見てきた標準の型クラスに属する法則について調べてみてもよいでしょう。 - -### インスタンスの導出 - -インスタンスを手作業で描く代わりに、ほとんどの作業をコンパイラにさせることができます。 -この[型クラス導出手引き](https://github.com/purescript/documentation/blob/master/guides/Type-Class-Deriving.md)を見てください。 -そちらの情報が以下の演習を解く手助けになることでしょう。 - -## 演習 - -(簡単)次のnewtypeは複素数を表します。 - -```haskell -{{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Complex}} -``` - -1. (簡単)`Complex`に`Show`インスタンスを定義してください。 - 出力の形式はテストで期待される形式と一致させてください(例:`1.2+3.4i`、`5.6-7.7i`など)。 - -2. (簡単)`Eq`インスタンスを`Complex`に導出してください。 - *補足*:代わりにこのインスタンスを手作業で書いてもよいですが、しなくていいのになぜすることがありましょう。 - -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`に導出してください。 - *補足*:代わりにこのインスタンスを手作業で書くこともできますが、そう手軽にはできません。 - - 以下は前章からの`Shape`のADTです。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Shape}} - ``` - -5. (普通)(`Generic`を介して)`Show`インスタンスを`Shape`に導出してください。 - コードの量はどのくらいになりましたか。 - また、前の章の`showShape`と比較して`String`の出力はどうなりましたか。 - *手掛かり*:[型クラス導出](https://github.com/purescript/documentation/blob/master/guides/Type-Class-Deriving.md)手引きの[`Generic`から導出する](https://github.com/purescript/documentation/blob/master/guides/Type-Class-Deriving.md#deriving-from-generic)節を見てください。 - -## 型クラス制約 - -型クラスを使うと、関数の型に制約を加えることができます。 -例を示しましょう。 -`Eq`型クラスのインスタンスで定義された等値性を使って、3つの値が等しいかどうかを調べる関数を書きたいとします。 - -```haskell -threeAreEqual :: forall a. Eq a => a -> a -> a -> Boolean -threeAreEqual a1 a2 a3 = a1 == a2 && a2 == a3 -``` - -この型宣言は `forall`を使って定義された通常の多相型のようにも見えます。 -しかし、二重線矢印 `=>`で型の残りの部分から区切られた、型クラス制約 (type class constraint) `Eq a`があります。 - -インポートされたモジュールのどれかに `a`に対する `Eq`インスタンスが存在するなら、どんな型 `a`を選んでも -`threeAsEqual`を呼び出すことができる、とこの型は言っています。 - -制約された型には複数の型クラスインスタンスを含めることができますし、インスタンスの型は単純な型変数に限定されません。 `Ord`と -`Show`のインスタンスを使って2つの値を比較する例を次に示します。 - -```haskell -showCompare :: forall a. Ord a => Show a => a -> a -> String -showCompare a1 a2 | a1 < a2 = - show a1 <> " is less than " <> show a2 -showCompare a1 a2 | a1 > a2 = - show a1 <> " is greater than " <> show a2 -showCompare a1 a2 = - show a1 <> " is equal to " <> show a2 -``` - -`=>`シンボルを複数回使って複数の制約を指定できることに注意してください。 -複数の引数のカリー化された関数を定義するのと同様です。 -しかし、2つの記号を混同しないように注意してください。 - -- `a -> b`は _型_ `a`から _型_ `b`への関数の型を表します。 -- 一方で、`a => b`は _制約_ `a`を型`b`に適用します。 - -PureScriptコンパイラは、型の注釈が提供されていない場合、制約付きの型を推論しようとします。これは、関数に対してできる限り最も一般的な型を使用したい場合に便利です。 - -PSCiで `Semiring`のような標準の型クラスの何れかを使って、このことを試してみましょう。 - -```text -> import Prelude - -> :type \x -> x + x -forall a. Semiring a => a -> a -``` - -ここで、この関数には`Int -> Int`または`Number -> Number`と注釈を付けることが考えられますが、最も一般的な型が`Semiring`で動作するため、PSCiでは`Int`と `Number`の両方で関数を実行させることができます。 - -## インスタンスの依存関係 - -制約された型を使うと関数の実装が型クラスインスタンスに依存できるように、型クラスインスタンスの実装は他の型クラスインスタンスに依存できます。これにより、型を使ってプログラムの実装を推論するという、プログラム推論の強力な形式を提供します。 - -`Show`型クラスを例に考えてみましょう。 -それぞれの要素を `show`する方法がある限り、その要素の配列を `show`する型クラスインスタンスを書くことができます。 - -```haskell -instance Show a => Show (Array a) where - ... -``` - -型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置く必要があります。 - -```haskell -instance (Show a, Show b) => Show (Either a b) where - ... -``` - -これらの2つの型クラスインスタンスは `prelude`ライブラリにあります。 - -プログラムがコンパイルされると、`Show`の正しい型クラスのインスタンスは `show`の引数の推論された型に基づいて選ばれます。 -選択されたインスタンスが沢山のそうしたインスタンスの関係に依存しているかもしれませんが、このあたりの複雑さに開発者が関与することはありません。 - -## 演習 - -1. (簡単)以下の宣言では型 `a`の要素の空でない配列の型を定義しています。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:NonEmpty}} - ``` - - `Eq a`と`Eq (Array a)`のインスタンスを再利用し、型`NonEmpty`に`Eq`インスタンスを書いてください。 - *補足*:代わりに`Eq`インスタンスも導出できます。 - -1. (普通)`Array`の`Semigroup`インスタンスを再利用して、`NonEmpty`への`Semigroup`インスタンスを書いてください。 - -1. (普通)`NonEmpty`に`Functor`インスタンスを書いてください。 - -1. (普通)`Ord`のインスタンス付きの任意の型`a`が与えられているとすると、新しくそれ以外のどんな値よりも大きい「無限の」値を付け加えられます。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Extended}} - ``` - - `a`への`Ord`インスタンスを再利用して、`Extended a`に`Ord`インスタンスを書いてください。 - -1. (難しい)`NonEmpty`に`Foldable`インスタンスを書いてください。 - *手掛かり*:配列への`Foldable`インスタンスを再利用してください。 - -1. (難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持っている)ような型構築子 - `f`が与えられたとき、追加の要素を先頭に含めるような新たなコンテナ型を作ることができます。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:OneMore}} - ``` - - このコンテナ `OneMore f`もまた順序を持っています。 - ここで、新しい要素は任意の `f`の要素よりも前にきます。 - この `OneMore f`の `Foldable`インスタンスを書いてみましょう。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:OneMore_Foldable}} - ... - ``` - -1. (普通)`nubEq`関数を使い、配列から重複する`Shape`を削除する`dedupShapes :: Array Shape -> Array - Shape`関数を書いてください。 - -1. (普通)`dedupShapesFast`関数を書いてください。 - `dedupShapes`とほぼ同じですが、より効率の良い`nub`関数を使います。 - -## 多変数型クラス - -型クラスは必ずしも1つの型だけを型変数としてとるわけではありません。型変数が1つだけなのが最も一般的ですが、実際には型クラスは*ゼロ個以上の*型変数を持つことができます。 - -それでは2つの型引数を持つ型クラスの例を見てみましょう。 - -```haskell -module Stream where - -import Data.Array as Array -import Data.Maybe (Maybe) -import Data.String.CodeUnits as String - -class Stream stream element where - uncons :: stream -> Maybe { head :: element, tail :: stream } - -instance Stream (Array a) a where - uncons = Array.uncons - -instance Stream String Char where - uncons = String.uncons -``` - -この `Stream`モジュールでは、要素のストリームのような型を示すクラス `Stream`が定義されています。 -`uncons`関数を使ってストリームの先頭から要素を取り出すことができます。 - -`Stream`型クラスは、ストリーム自身の型だけでなくその要素の型も型変数として持っていることに注意してください。これによって、ストリームの型が同じでも要素の型について異なる型クラスインスタンスを定義できます。 - -このモジュールでは2つの型クラスインスタンスが定義されています。 -`uncons`がパターン照合で配列の先頭の要素を取り除くような配列のインスタンスと、文字列から最初の文字を取り除くような文字列のインスタンスです。 - -任意のストリーム上で動作する関数を記述できます。例えば、ストリームの要素に基づいて `Monoid`に結果を累積する関数は次のようになります。 - -```haskell -import Prelude -import Data.Monoid (class Monoid, mempty) - -foldStream :: forall l e m. Stream l e => Monoid m => (e -> m) -> l -> m -foldStream f list = - case uncons list of - Nothing -> mempty - Just cons -> f cons.head <> foldStream f cons.tail -``` - -PSCiで使って、異なる `Stream`の型や異なる `Monoid`の型について `foldStream`を呼び出してみましょう。 - -## 関数従属性 - -多変数型クラスは非常に便利ですが、混乱しやすい型や型推論の問題にも繋がります。 -簡単な例として、上記の `Stream`クラスを使って汎用的な`tail`関数をストリームに書くことを考えてみましょう。 - -```haskell -genericTail xs = map _.tail (uncons xs) -``` - -これはやや複雑なエラーメッセージを出力します。 - -```text -The inferred type - - forall stream a. Stream stream a => stream -> Maybe stream - -has type variables which are not mentioned in the body of the type. Consider adding a type annotation. -``` - -エラーは、 `genericTail`関数が `Stream`型クラスの定義で言及された -`element`型を使用しないので、その型は未解決のままであることを指しています。 - -更に残念なことに、特定の型のストリームに`genericTail`を適用できません。 - -```text -> map _.tail (uncons "testing") - -The inferred type - - forall a. Stream String a => Maybe String - -has type variables which are not mentioned in the body of the type. Consider adding a type annotation. -``` - -ここでは、コンパイラが `streamString`インスタンスを選択することを期待しています。 -結局のところ、 `String`は `Char`のストリームであり、他の型のストリームであってはなりません。 - -コンパイラは自動的にそう推論できず、`streamString`インスタンスを割り当てることができません。 -しかし、型クラス定義に手掛かりを追加すると、コンパイラを助けることができます。 - -```haskell -class Stream stream element | stream -> element where - uncons :: stream -> Maybe { head :: element, tail :: stream } -``` - -ここで、 `stream -> element`は _関数従属性_ (functional dependency) と呼ばれます。関数従属性は、多変数型クラスの型引数間の関数関係を宣言します。この関数の依存関係は、ストリーム型から(一意の)要素型への関数があることをコンパイラに伝えるので、コンパイラがストリーム型を知っていれば要素の型を割り当てられます。 - -この手掛かりがあれば、コンパイラが上記の汎用的な尾鰭関数の正しい型を推論するのに充分です。 - -```text -> :type genericTail -forall stream element. Stream stream element => stream -> Maybe stream - -> genericTail "testing" -(Just "esting") -``` - -多種の型のクラスを使用して何らかのAPIを設計する場合、関数従属性は非常に有用です。 - -## 型変数のない型クラス - -ゼロ個の型変数を持つ型クラスさえも定義できます。 -これらは関数に対するコンパイル時のアサーションに対応しており、型システム内のコードの大域的な性質を把握できます。 - -重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあります。`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。なので配列が空のときに失敗する可能性があります。 - -```haskell -head :: forall a. Partial => Array a -> a - -tail :: forall a. Partial => Array a -> Array a -``` - -`Partial`モジュールの `Partial`型クラスのインスタンスを定義していないことに注意してください。 -こうすると目的を達成できます。 -このままの定義では `head`関数を使用しようとすると型エラーになるのです。 - -```text -> head [1, 2, 3] - -No type class instance was found for - - Prim.Partial -``` - -代わりに、これらの部分関数を利用する全ての関数で `Partial`制約を再発行できます。 - -```haskell -secondElement :: forall a. Partial => Array a -> a -secondElement xs = head (tail xs) -``` - -前章で見た`unsafePartial`関数を使用し、部分関数を通常の関数として(不用心に)扱うことができます。この関数は -`Partial.Unsafe`モジュールで定義されています。 - -```haskell -unsafePartial :: forall a. (Partial => a) -> a -``` - -`Partial`制約は関数の矢印の左側の括弧の中に現れますが、外側の `forall`では現れません。 -つまり、 `unsafePartial`は部分的な値から通常の値への関数です。 - -```text -> unsafePartial head [1, 2, 3] -1 - -> unsafePartial secondElement [1, 2, 3] -2 -``` - -## 上位クラス - -インスタンスを別のインスタンスに依存させることによって型クラスのインスタンス間の関係を表現できるように、いわゆる*上位クラス*を使って型クラス間の関係を表現できます。 - -あるクラスのどんなインスタンスも、別のクラスのインスタンスである必要があるとき、後者の型クラスは前者の型クラスの上位クラスであるといいます。 -そしてクラス定義で逆向きの太い矢印 (`<=`) を使って上位クラス関係を示します。 - -[既に上位クラスの関係の例を目にしました](#ord)。 -`Eq`クラスは `Ord`の上位クラスですし、`Semigroup`クラスは`Monoid`の上位クラスです。 -`Ord`クラスの全ての型クラスインスタンスについて、その同じ型に対応する `Eq`インスタンスが存在しなければなりません。 -これは理に適っています。 -`compare`関数が2つの値の大小を付けられないと報告した時は、それらが実は同値であるかどうかを判定するために -`Eq`クラスを使いたいことが多いでしょうから。 - -一般に、下位クラスの法則が上位クラスのメンバに言及しているとき、上位クラス関係を定義するのは筋が通っています。 -例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インスタンスの下で同値であるなら、`compare`関数は -`EQ`を返すはずだと見做すのは理に適っています。 -言い換えれば、`a == b`が真であるのはちょうど`compare a b`が`EQ`に評価されるときなのです。 -法則のレベルでのこの関係は`Eq`と`Ord`の間の上位クラス関係の正当性を示します。 - -上位クラス関係を定義する別の理由となるのは、この2つのクラスの間に明らかに "is-a" の関係があることです。 -下位クラスの全てのメンバは、上位クラスのメンバでもあるということです。 - -## 演習 - -1. (普通)部分関数`unsafeMaximum :: Partial => Array Int -> - Int`を定義してください。この関数は空でない整数の配列の最大値を求めます。`unsafePartial`を使ってPSCiで関数をテストしてください。*手掛かり*:`Data.Foldable`の - `maximum`関数を使います。 - -1. (普通)次の `Action`クラスは、ある型の別の型での動作 (action) を定義する、多変数型クラスです。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Action}} - ``` - - *動作*はモノイドな値を使って他の型の値を変更する方法を決めるやり方を記述する関数です。`Action`型クラスには2つの法則があります。 - - - `act mempty a = a` - - `act (m1 <> m2) a = act m1 (act m2 a)` - - 空の動作を提供しても何も起こりません。 - そして2つの動作を連続で適用することは結合した動作を適用することと同じです。 - つまり、動作は`Monoid`クラスで定義される操作に倣っています。 - - 例えば自然数は乗算のもとでモノイドを形成します。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Multiply}} - - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:semigroupMultiply}} - - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:monoidMultiply}} - ``` - - この動作を実装するインスタンスを書いてください。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Multiply_Action}} - ... - ``` - - インスタンスが上で挙げた法則を見たさなくてはならないことを思い出してください。 - -1. (難しい)実は`Action Multiply Int`のインスタンスを実装するには複数の方法があります。 - どれだけ思い付きますか。 - PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える必要があります。 - *補足*:テストでは4つの実装を押さえています。 - -1. (普通)入力の文字列を何回か繰り返す`Action`インスタンスを書いてください。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:actionMultiplyString}} - ... - ``` - - *手掛かり*:Pursuitでシグネチャが[`String -> Int -> String`](https://pursuit.purescript.org/search?q=String%20-%3E%20Int%20-%3E%20String)の補助関数を検索してください。 - なお`String`は(`Monoid`のような)より汎用的な型として現れます。 - - このインスタンスは上に挙げた法則を満たすでしょうか。 - -1. (普通)インスタンス `Action m a => Action m (Array a)`を書いてみましょう。 - ここで、 配列上の動作はそれぞれの要素を独立に実行するものとして定義されます。 - -1. (難しい)以下のnewtypeが与えらえているとき、`Action m (Self m)`のインスタンスを書いてください。 - ここでモノイド`m`はそれ自体が持つ`append`を用いて動作します。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Self}} - ``` - - *補足*:テストフレームワークでは`Self`と`Multiply`型に`Show`と`Eq`インスタンスが必要になります。 - 手作業でこれらのインスタンスを書いてもよいですし、[`derive newtype instance`](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#derive-from-newtype)と書くだけでコンパイラに取り仕切ってもらうこともできます。 - -1. (難しい)多変数型のクラス `Action`の引数は、何らかの関数従属性によって関連づけられるべきですか。 - なぜそうすべき、あるいはそうすべきでないでしょうか。 - *補足*:この演習にはテストがありません。 - -## ハッシュの型クラス - -この最後の節では、章の残りを使ってデータ構造をハッシュ化するライブラリを作ります。 - -なお、このライブラリの説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は目的としていません。 - -ハッシュ関数に期待される性質とはどのようなものでしょうか。 - -- ハッシュ関数は決定的でなくてはなりません。 - つまり、同じ値には同じハッシュ値を対応させなければなりません。 -- ハッシュ関数はいろいろなハッシュ値の集合で結果が一様に分布しなければなりません。 - -最初の性質はまさに型クラスの法則のように見える一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型システムによって確実に強制できるようなものではなさそうです。 -しかし、これは型クラスについて次のような直感的理解を与えるはずです。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:Hashable}} -``` - -これに、 `a == b`ならば `hash a == hash b`を示唆するという関係性の法則が付随しています。 - -この節の残りの部分を費やして、`Hashable`型クラスに関連付けられているインスタンスと関数のライブラリを構築していきます。 - -決定的な方法でハッシュ値を結合する方法が必要になります。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:combineHashes}} -``` - -`combineHashes`関数は2つのハッシュ値を混ぜて結果を0-65535の間に分布します。 - -それでは、入力の種類を制限する `Hashable`制約を使う関数を書いてみましょう。 -ハッシュ関数を必要とするよくある目的としては、2つの値が同じハッシュ値にハッシュ化されるかどうかを決定することです。 -`hashEqual`関係はそのような機能を提供します。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashEqual}} -``` - -この関数はハッシュコードの等値性を利用したハッシュ同値性を定義するために`Data.Function`の -`on`関数を使っていますが、これはハッシュ同値性の宣言的な定義として読めるはずです。 -つまり、それぞれの値が `hash`関数に渡されたあとで2つの値が等しいなら、それらの値は「ハッシュ同値」です。 - -原始型の `Hashable`インスタンスを幾つか書いてみましょう。 -まずは整数のインスタンスです。 -`HashCode`は実際には単なる梱包された整数なので、これは簡単です。 -`hashCode`補助関数を使うことができます。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashInt}} -``` - -パターン照合を使うと、`Boolean`値の単純なインスタンスも定義できます。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashBoolean}} -``` - -整数のインスタンスでは、`Data.Char`の `toCharCode`関数を使うと`Char`をハッシュ化するインスタンスを作成できます。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashChar}} -``` - -(要素型が `Hashable`のインスタンスでもあるならば)配列の要素に `hash`関数を -`map`してから、`combineHashes`関数を使って結果のハッシュを左側に畳み込むことで、配列のインスタンスを定義します。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashArray}} -``` - -既に書いたものより単純なインスタンスを使用して、新たなインスタンスを構築しているやり方に注目してください。 -`String`を`Char`の配列に変換し、この新たな`Array`インスタンスを使って`String`のインスタンスを定義しましょう。 - -```haskell -{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashString}} -``` - -これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証明するにはどうしたらいいでしょうか。 -同じ値が等しいハッシュ値を持っていることを確認する必要があります。 -`Int`、 `Char`、 `String`、 -`Boolean`の場合は、`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しないので簡単です。 - -もっと面白い型についてはどうでしょうか。 -この場合、配列の長さに関する帰納を使うと、型クラスの法則を証明できます。 -長さゼロの唯一の配列は `[]`です。 -配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じで配列の残りの部分が等しいとき、またその時に限り等しくなります。 -この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし `Hashable -a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値をもつことがわかります。 -したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型クラス法則を満たしています。 - -この章のソースコードには、 `Maybe`と `Tuple`型のインスタンスなど、他にも `Hashable`インスタンスの例が含まれています。 - -## 演習 - - 1. (簡単)PSCiを使って、定義した各インスタンスのハッシュ関数をテストしてください。 - *補足*:この演習には単体試験がありません。 - 1. (普通)ハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうかを調べる関数`arrayHasDuplicates`を書いてください。 - まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対が見付かったら`==`で値の同値性を確認してください。 - *手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるでしょう。 - 1. (普通)型クラスの法則を満たす、次のnewtypeの `Hashable`インスタンスを書いてください。 - - ```haskell - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Hour}} - - {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:eqHour}} - ``` - - newtypeの `Hour`とその `Eq`インスタンスは、12を法とする整数の型を表します。 - したがって、例えば1と13は等しいと見なされます。 - そのインスタンスが型クラスの法則を満たしていることを証明してください。 - 1. (難しい)`Maybe`、`Either`そして`Tuple`への`Hashable`インスタンスについて型クラスの法則を証明してください。 - *補足*:この演習にテストはありません。 - -## まとめ - -この章では、型に基づく抽象化で、コードの再利用のための強力な形式化を可能にする _型クラス_ -を導入しました。PureScriptの標準ライブラリから標準の型クラスを幾つか見てきました。また、ハッシュ値を計算する型クラスに基づく独自のライブラリを定義しました。 - -この章では型クラス法則の考え方も導入しましたが、これは抽象化に型クラスを使うコードについての性質を証明する手法でした。 -型クラス法則は*等式推論*と呼ばれる大きな分野の一部であり、プログラミング言語の性質と型システムがプログラムを論理的に推論するために使われています。 -これは重要な考え方で、本書では今後あらゆる箇所で立ち返る話題となるでしょう。 diff --git a/text-ja/chapter7.md b/text-ja/chapter7.md deleted file mode 100644 index 3f8adef9..00000000 --- a/text-ja/chapter7.md +++ /dev/null @@ -1,805 +0,0 @@ -# アプリカティブによる検証 - -## この章の目標 - -この章では、`Applicative`型クラスによって表現される _アプリカティブ関手_ (applicative functor) -という重要な抽象化と新たに出会うことになります。名前が難しそうに思えても心配しないでください。フォームデータの検証という実用的な例を使ってこの概念の動機付けをします。アプリカティブ関手を使うと、通常であれば大量の決まり文句を伴うようなコードを、簡潔で宣言的な記述へと変えることができるようになります。 - -また、*巡回可能関手*を表現する`Traversable`という別の型クラスにも出会います。現実の問題への解決策からこの概念が自然に生じることがわかるでしょう。 - -この章では第3章に引き続き住所録を例として扱います。 -今回は住所録のデータ型を拡張し、これらの型の値を検証する関数を書きます。 -これらの関数は、例えばデータ入力フォームの一部で、使用者へエラーを表示するwebユーザインターフェースで使われると考えてください。 - -## プロジェクトの準備 - -この章のソースコードは、2つのファイル`src/Data/AddressBook.purs`、及び`src/Data/AddressBook/Validation.purs`で定義されています。 - -このプロジェクトには多くの依存関係がありますが、その大半は既に見てきたものです。 -新しい依存関係は2つです。 - -- `control` - `Applicative`のような、型クラスを使用して制御フローを抽象化する関数が定義されています。 -- `validation` - この章の主題である _アプリカティブによる検証_ のための関手が定義されています。 - -`Data.AddressBook`モジュールには、このプロジェクトのデータ型とそれらの型に対する`Show`インスタンスが定義されており、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれています。 - -## 関数適用の一般化 - -_アプリカティブ関手_ の概念を理解するために、以前扱った型構築子`Maybe`について考えてみましょう。 - -このモジュールのソースコードでは、次のような型を持つ`address`関数が定義されています。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook.purs:address_anno}} -``` - -この関数は、通りの名前、市、州という3つの文字列から型`Address`の値を構築するために使います。 - -この関数は簡単に適用できますので、PSCiでどうなるか見てみましょう。 - -```text -> import Data.AddressBook - -> address "123 Fake St." "Faketown" "CA" -{ street: "123 Fake St.", city: "Faketown", state: "CA" } -``` - -しかし、通り、市、州の3つ全てが必ずしも入力されないものとすると、3つの場合がそれぞれ省略可能であることを示すために`Maybe`型を使用したくなります。 - -考えられる場合としては、市が省略されている場合があるでしょう。 -もし`address`関数を直接適用しようとすると、型検証器からエラーが表示されます。 - -```text -> import Data.Maybe -> address (Just "123 Fake St.") Nothing (Just "CA") - -Could not match type - - Maybe String - -with type - - String -``` - -`address`は`Maybe String`型ではなく文字列型の引数を取るので、もちろんこれは期待通り型エラーになります。 - -しかし、もし`address`関数を「持ち上げる」ことができれば、`Maybe`型で示される省略可能な値を扱うことができるはずだという予想は理に適っています。実際それは可能で、`Control.Apply`で提供されている関数`lift3`が、まさに求めているものです。 - -```text -> import Control.Apply -> lift3 address (Just "123 Fake St.") Nothing (Just "CA") - -Nothing -``` - -このとき、引数の1つ(市)が欠落していたので、結果は`Nothing`になります。 -もし3つの引数全てに`Just`構築子を使ったものが与えられたら、結果は値を含むことになります。 - -```text -> lift3 address (Just "123 Fake St.") (Just "Faketown") (Just "CA") - -Just ({ street: "123 Fake St.", city: "Faketown", state: "CA" }) -``` - -`lift3`という関数の名前は、3引数の関数を持ち上げるために使えることを示しています。関数を持ち上げる同様の関数で、引数の数が異なるものが`Control.Apply`で定義されています。 - -## 任意個の引数を持つ関数の持ち上げ - -これで、`lift2`や`lift3`のような関数を使えば、引数が2個や3個の関数を持ち上げることができるのはわかりました。 -でも、これを任意個の引数の関数へと一般化できるのでしょうか。 - -`lift3`の型を見てみるとわかりやすいでしょう。 - -```text -> :type lift3 -forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d -``` - -上の`Maybe`の例では型構築子`f`は`Maybe`ですから、`lift3`は次のように特殊化されます。 - -```haskell -forall a b c d. (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -``` - -この型が言っているのは、3引数の任意の関数を取り、その関数を引数と返り値が`Maybe`で包まれた新しい関数へと持ち上げる、ということです。 - -もちろんどんな型構築子`f`についても持ち上げができるわけではないのですが、それでは`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。 -さて、先ほどの型の特殊化では、`f`に対する型クラス制約から`Apply`型クラスを取り除いていました。 -`Apply`はPreludeで次のように定義されています。 - -```haskell -class Functor f where - map :: forall a b. (a -> b) -> f a -> f b - -class Functor f <= Apply f where - apply :: forall a b. f (a -> b) -> f a -> f b -``` - -`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`の型は`map`の型と実によく似ています。 -`map`と`apply`の違いは、`map`がただの関数を引数に取るのに対し、`apply`の最初の引数は型構築子`f`で包まれているという点です。 -これをどのように使うのかはこれからすぐに見ていきますが、その前にまず`Maybe`型について`Apply`型クラスをどう実装するのかを見ていきましょう。 - -```haskell -instance Functor Maybe where - map f (Just a) = Just (f a) - map f Nothing = Nothing - -instance Apply Maybe where - apply (Just f) (Just x) = Just (f x) - apply _ _ = Nothing -``` - -この型クラスのインスタンスで書かれているのは、任意のオプショナルな値にオプショナルな関数を適用でき、その両方が定義されている時に限り結果も定義される、ということです。 - -それでは、`map`と`apply`を一緒に使い、引数が任意個の関数を持ち上げる方法を見ていきましょう。 - -1引数の関数については、`map`をそのまま使うだけです。 - -2引数関数については、型`a -> b -> c`のカリー化された関数`g`があるとします。これは型`a -> (b -> c)`と同じですから、`Functor`インスタンス付きのあらゆる型構築子`f`について、`map`を`f`に適用すると型`f a -> f (b -> c)`の新たな関数を得ることになります。持ち上げられた(型`f a`の)最初の引数にその関数を部分適用すると、型`f (b -> c)`の新たな包まれた関数が得られます。`f`に`Apply`インスタンスもあるなら、そこから、2番目の持ち上げられた(型`f b`の)引数へ`apply`を適用でき、型`f c`の最終的な値を得ます。 - -纏めると、`x :: f a`と`y :: f b`があるとき、式`(g <$> x) <*> y`の型は`f c`になります(この式は`apply (map g x) y`と同じ意味だということを思い出しましょう)。Preludeで定義された優先順位の規則に従うと、`g <$> x <*> y`というように括弧を外すことができます。 - -一般的には、最初の引数に`<$>`を使い、残りの引数に対しては`<*>`を使います。`lift3`で説明すると次のようになります。 - -```haskell -lift3 :: forall a b c d f - . Apply f - => (a -> b -> c -> d) - -> f a - -> f b - -> f c - -> f d -lift3 f x y z = f <$> x <*> y <*> z -``` - -この式の型がちゃんと整合しているかの確認は、読者への演習として残しておきます。 - -例として、`<$>`と`<*>`をそのまま使うと、`Maybe`上に`address`関数を持ち上げることができます。 - -```text -> address <$> Just "123 Fake St." <*> Just "Faketown" <*> Just "CA" -Just ({ street: "123 Fake St.", city: "Faketown", state: "CA" }) - -> address <$> Just "123 Fake St." <*> Nothing <*> Just "CA" -Nothing -``` - -同様にして、引数が異なる他のいろいろな関数を`Maybe`上に持ち上げてみてください。 - -この代わりにお馴染の _do記法_ に似た見た目の _アプリカティブdo記法_ が同じ目的で使えます。以下では`lift3`に -_アプリカティブdo記法_ -を使っています。なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で`in`が使われています。 - -```haskell -lift3 :: forall a b c d f - . Apply f - => (a -> b -> c -> d) - -> f a - -> f b - -> f c - -> f d -lift3 f x y z = ado - a <- x - b <- y - c <- z - in f a b c -``` - -## アプリカティブ型クラス - -関連する`Applicative`という型クラスが存在しており、次のように定義されています。 - -```haskell -class Apply f <= Applicative f where - pure :: forall a. a -> f a -``` - -`Applicative`は`Apply`の下位クラスであり、`pure`関数が定義されています。 -`pure`は値を取り、その型の型構築子`f`で包まれた値を返します。 - -`Maybe`についての`Applicative`インスタンスは次のようになります。 - -```haskell -instance Applicative Maybe where - pure x = Just x -``` - -アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、`pure`は引数のない関数の持ち上げだというように考えることができます。 - -## アプリカティブに対する直感的理解 - -PureScriptの関数は純粋であり、副作用は持っていません。Applicative関手は、関手`f`によって表現されるある種の副作用を提供するような、より大きな「プログラミング言語」を扱えるようにします。 - -例えば関手`Maybe`はオプショナルな値の副作用を表現しています。 -その他の例としては、型`err`のエラーの可能性の副作用を表す`Either err`や、大域的な構成を読み取る副作用を表すArrow関手 (arrow functor) `r ->`があります。 -ここでは`Maybe`関手についてのみ考えることにします。 - -もし関手`f`が作用を持つ、より大きなプログラミング言語を表すとすると、`Apply`と`Applicative`インスタンスは小さなプログラミング言語 -(PureScript) から新しい大きな言語へと値や関数を持ち上げることを可能にします。 - -`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数については上で述べた通り`map`と`apply`を使うことができます。 - -ここで疑問が生まれます。 -もしPureScriptの関数と値を新たな言語へ埋め込むのに`Applicative`が使えるなら、どうやって新たな言語は大きくなっているというのでしょうか。 -この答えは関手`f`に依存します。 -もしなんらかの`x`について`pure x`で表せないような型`f -a`の式を見つけたなら、その式はそのより大きな言語だけに存在する項を表しているということです。 - -`f`が`Maybe`のときは、式`Nothing`がその例になっています。 -どんな`x`があっても`Nothing`を`pure x`というように書くことはできません。 -したがって、PureScriptは値の欠落を表す新しい項`Nothing`を含むように拡大されたと考えることができます。 - -## もっと作用を - -様々な`Applicative`関手へと関数を持ち上げる例をもっと見ていきましょう。 - -以下は、PSCiで定義された3つの名前を結合して完全な名前を作る簡単な関数の例です。 - -```text -> import Prelude - -> fullName first middle last = last <> ", " <> first <> " " <> middle - -> fullName "Phillip" "A" "Freeman" -Freeman, Phillip A -``` - -この関数は、クエリパラメータとして与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装であるとしましょう。 -使用者が3つの引数全てを与えたことを確かめたいので、引数が存在するかどうかを表す`Maybe`型を使うことになるでしょう。 -`fullName`を`Maybe`の上へ持ち上げると、省略された引数を確認するwebサービスを実装できます。 - -```text -> import Data.Maybe - -> fullName <$> Just "Phillip" <*> Just "A" <*> Just "Freeman" -Just ("Freeman, Phillip A") - -> fullName <$> Just "Phillip" <*> Nothing <*> Just "Freeman" -Nothing -``` - -または*アプリカティブdo*で次のようにします。 - -```text -> import Data.Maybe - -> :paste… -… ado -… f <- Just "Phillip" -… m <- Just "A" -… l <- Just "Freeman" -… in fullName f m l -… ^D -(Just "Freeman, Phillip A") - -… ado -… f <- Just "Phillip" -… m <- Nothing -… l <- Just "Freeman" -… in fullName f m l -… ^D -Nothing -``` - -この持ち上げた関数は、引数の何れかが`Nothing`なら`Nothing`を返すことに注意してください。 - -これで、もし引数が不正ならWebサービスからエラー応答を送信できるので、なかなかいい感じです。 -しかし、どのフィールドが間違っていたのかを応答で示せると、もっと良くなるでしょう。 - -`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エラーメッセージを返すことができるようになります。 -まずは`Either String`を使ってオプショナルな入力をエラーを発信できる計算に変換する演算子を書きましょう。 - -```text -> import Data.Either -> :paste -… withError Nothing err = Left err -… withError (Just a) _ = Right a -… ^D -``` - -*補足*:`Either err`アプリカティブ関手において、`Left`構築子は失敗を表しており、`Right`構築子は成功を表しています。 - -これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラーメッセージを提供できるようになります。 - -```text -> :paste -… fullNameEither first middle last = -… fullName <$> (first `withError` "First name was missing") -… <*> (middle `withError` "Middle name was missing") -… <*> (last `withError` "Last name was missing") -… ^D -``` - -または*アプリカティブdo*で次のようにします。 - -```text -> :paste -… fullNameEither first middle last = ado -… f <- first `withError` "First name was missing" -… m <- middle `withError` "Middle name was missing" -… l <- last `withError` "Last name was missing" -… in fullName f m l -… ^D - -> :type fullNameEither -Maybe String -> Maybe String -> Maybe String -> Either String String -``` - -これでこの関数は`Maybe`の3つの省略可能な引数を取り、`String`のエラーメッセージか`String`の結果のどちらかを返します。 - -いろいろな入力でこの関数を試してみましょう。 - -```text -> fullNameEither (Just "Phillip") (Just "A") (Just "Freeman") -(Right "Freeman, Phillip A") - -> fullNameEither (Just "Phillip") Nothing (Just "Freeman") -(Left "Middle name was missing") - -> fullNameEither (Just "Phillip") (Just "A") Nothing -(Left "Last name was missing") -``` - -このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラーメッセージが表示されます。 -しかし、もし複数の入力が省略されているとき、最初のエラーしか見ることができません。 - -```text -> fullNameEither Nothing Nothing Nothing -(Left "First name was missing") -``` - -これでも充分なときもありますが、エラー時に*全ての*省略されたフィールドの一覧がほしいときは、`Either -String`よりも強力なものが必要です。この章の後半で解決策を見ていきます。 - -## 作用の結合 - -抽象的にアプリカティブ関手を扱う例として、アプリカティブ関手`f`によって表現された副作用を一般的に組み合わせる関数を書く方法をこの節では示します。 - -これはどういう意味でしょうか。 -何らかの`a`について型`f a`で包まれた引数のリストがあるとしましょう。 -それは型`List (f a)`のリストがあるということです。 -直感的には、これは`f`によって追跡される副作用を持つ、返り値の型が`a`の計算のリストを表しています。 -これらの計算の全てを順番に実行できれば、`List a`型の結果のリストを得るでしょう。 -しかし、まだ`f`によって追跡される副作用が残ります。 -つまり、元のリストの中の作用を「結合する」ことにより、型`List (f a)`の何かを型`f (List a)`の何かへと変換できると考えられます。 - -任意の固定長リストの長さ`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)`を得ることができます。 -しかし、いかなる`n`についてもこれが可能なので、いかなる引数の*リスト*についても同じように持ち上げられることが確かめられます。 - -したがって、次のような関数を書くことができるはずです。 - -```haskell -combineList :: forall f a. Applicative f => List (f a) -> f (List a) -``` - -この関数は副作用を持つかもしれない引数のリストを取り、それぞれの副作用を適用することで、`f`に包まれた単一のリストを返します。 - -この関数を書くためには、引数のリストの長さについて考えます。 -リストが空の場合はどんな作用も実行する必要がありませんから、`pure`を使用して単に空のリストを返すことができます。 - -```haskell -combineList Nil = pure Nil -``` - -実際のところこれがたった1つのできることです。 - -入力のリストが空でないならば、型`f a`の包まれた引数である先頭要素と、型`List (f a)`の尾鰭について考えます。 -また、再帰的にリストの残りを結合すると、型`f (List a)`の結果が得られます。 -それから`<$>`と`<*>`を使うと、`Cons`構築子を先頭と新しい尾鰭の上に持ち上げることができます。 - -```haskell -combineList (Cons x xs) = Cons <$> x <*> combineList xs -``` - -繰り返しになりますが、これは与えられた型に基づいている唯一の妥当な実装です。 - -`Maybe`型構築子を例にとって、PSCiでこの関数を試してみましょう。 - -```text -> import Data.List -> import Data.Maybe - -> combineList (fromFoldable [Just 1, Just 2, Just 3]) -(Just (Cons 1 (Cons 2 (Cons 3 Nil)))) - -> combineList (fromFoldable [Just 1, Nothing, Just 2]) -Nothing -``` - -`Meybe`へ特殊化して考えると、リストの全ての要素が`Just`であるときに限りこの関数は`Just`を返しますし、そうでなければ`Nothing`を返します。 -これはオプショナルな値に対応する、より大きな言語に取り組む上での直感から一貫しています。 -オプショナルな結果を返す計算のリストは、全ての計算が結果を持っているならばそれ自身の結果のみを持つのです。 - -しかし、`combineList`関数はどんな`Applicative`に対しても機能します。 -`Either err`を使ってエラーを発信する可能性を持たせたり、`r ->`を使って大域的な状態を読み取る計算を連鎖させるときにも使えるのです。 - -`combineList`関数については、後ほど`Traversable`関手について考えるときに再訪します。 - -## 演習 - - 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`を書いてください。 - この関数は副作用をもつオプショナルな計算をとり、オプショナルな結果をもつ副作用のある計算を返します。 - -## アプリカティブによる検証 - -この章のソースコードでは住所録アプリケーションで使うことのできるいろいろなデータ型が定義されています。 -詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされる重要な関数は次のような型を持っています。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook.purs:address_anno}} - -{{#include ../exercises/chapter7/src/Data/AddressBook.purs:phoneNumber_anno}} - -{{#include ../exercises/chapter7/src/Data/AddressBook.purs:person_anno}} -``` - -ここで、`PhoneType`は次のような代数的データ型として定義されています。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook.purs:PhoneType}} -``` - -これらの関数は住所録の項目を表す`Person`を構築するのに使えます。 -例えば、`Data.AddressBook`には次のような値が定義されています。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook.purs:examplePerson}} -``` - -PSCiでこれらの値を試してみましょう(結果は整形されています)。 - -```text -> import Data.AddressBook - -> examplePerson -{ firstName: "John" -, lastName: "Smith" -, homeAddress: - { street: "123 Fake St." - , city: "FakeTown" - , state: "CA" - } -, phones: - [ { type: HomePhone - , number: "555-555-5555" - } - , { type: CellPhone - , number: "555-555-0000" - } - ] -} -``` - -前の章では型`Person`のデータ構造を検証する上で`Either -String`関手の使い方を見ました。例えば、データ構造の2つの名前を検証する関数が与えられたとき、データ構造全体を次のように検証できます。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:nonEmpty1}} - -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson1}} -``` - -または*アプリカティブdo*で次のようにします。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson1Ado}} -``` - -最初の2行では`nonEmpty`関数を使って空文字列でないことを検証しています。 -もし入力が空なら`nonEMpty`はエラーを返し(`Left`構築子で示されています)、そうでなければ`Right`構築子を使って値を包んで返します。 - -最後の2行では何の検証も実行せず、単に`address`フィールドと`phones`フィールドを残りの引数として`person`関数へと提供しています。 - -この関数はPSCiでうまく動作するように見えますが、以前見たような制限があります。 - -```text -> validatePerson $ person "" "" (address "" "" "") [] -(Left "Field cannot be empty") -``` - -`Either String`アプリカティブ関手は遭遇した最初のエラーだけを返します。 -でもこの入力では、名前の不足と姓の不足という2つのエラーがわかるようにしたくなるでしょう。 - -`validation`ライブラリでは別のアプリカティブ関手も提供されています。 -これは単に`V`と呼ばれていて、何らかの*半群*でエラーを返す機能があります。 -例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、`String`の配列をエラーとして返すことができます。 - -`Data.Validation`モジュールは`Data.AddressBook`モジュールのデータ構造を検証するために`V (Array -String)`アプリカティブ関手を使っています。 - -`Data.AddressBook.Validation`モジュールから取材した検証器の例は次のようになります。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:Errors}} - -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:nonEmpty}} - -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:lengthIs}} - -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validateAddress}} -``` - -または*アプリカティブdo*で次のようにします。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validateAddressAdo}} -``` - -`validateAddress`は`Address`の構造を検証します。 -`street`と`city`が空でないかどうか、`state`の文字列の長さが2であるかどうかを検証します。 - -`nonEmpty`と`lengthIs`の2つの検証関数が何れも、`Data.Validation`モジュールで提供されている`invalid`関数をエラーを示すために使っているところに注目してください。 -`Array String`半群を扱っているので、`invalid`は引数として文字列の配列を取ります。 - -PSCiでこの関数を試しましょう。 - -```text -> import Data.AddressBook -> import Data.AddressBook.Validation - -> validateAddress $ address "" "" "" -(invalid [ "Field 'Street' cannot be empty" - , "Field 'City' cannot be empty" - , "Field 'State' must have length 2" - ]) - -> validateAddress $ address "" "" "CA" -(invalid [ "Field 'Street' cannot be empty" - , "Field 'City' cannot be empty" - ]) -``` - -これで、全ての検証エラーの配列を受け取ることができるようになりました。 - -## 正規表現検証器 - -`validatePhoneNumber`関数では引数の形式を検証するために正規表現を使っています。重要なのは`matches`検証関数で、この関数は`Data.String.Regex`モジュールで定義されている`Regex`を使って入力を検証しています。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:matches}} -``` - -繰り返しになりますが、`pure`は常に成功する検証を表しており、エラーの配列の伝達には`invalid`が使われています。 - -これまでと同様に、`validatePhoneNumber`は`matches`関数から構築されています。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePhoneNumber}} -``` - -または*アプリカティブdo*で次のようにします。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePhoneNumberAdo}} -``` - -また、PSCiでいろいろな有効な入力や無効な入力に対して、この検証器を実行してみてください。 - -```text -> validatePhoneNumber $ phoneNumber HomePhone "555-555-5555" -pure ({ type: HomePhone, number: "555-555-5555" }) - -> validatePhoneNumber $ phoneNumber HomePhone "555.555.5555" -invalid (["Field 'Number' did not match the required format"]) -``` - -## 演習 - - 1. (簡単)正規表現`stateRegex :: Regex`を書いて文字列が2文字のアルファベットであることを確かめてください。 - *手掛かり*:`phoneNumberRegex`のソースコードを参照してみましょう。 - 1. (普通)文字列全体が空白でないことを検査する正規表現`nonEmptyRegex :: Regex`を書いてください。 - *手掛かり*:この正規表現を開発するのに手助けが必要なら、[RegExr](https://regexr.com)をご確認ください。 - 素晴しい早見表と対話的なお試し環境があります。 - 1. (普通)`validateAddress`に似ていますが、上の`stateRegex`を使って`state`フィールドを検証し、`nonEmptyRegex`を使って`street`と`city`フィールドを検証する関数`validateAddressImproved`を書いてください。 - *手掛かり*:`matches`の用例については`validatePhoneNumber`のソースを見てください。 - -## 巡回可能関手 - -残った検証器は`validatePerson`です。 -これはこれまで見てきた検証器と以下の新しい`validatePhoneNumbers`関数を組み合わせて`Person`全体を検証するものです。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePhoneNumbers}} - -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson}} -``` - -または*アプリカティブdo*で次のようにします。 - -```haskell -{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePersonAdo}} -``` - -`validatePhoneNumbers`はこれまでに見たことのない新しい関数、`traverse`を使います。 - -`traverse`は`Data.Traversable`モジュールの`Traversable`型クラスで定義されています。 - -```haskell -class (Functor t, Foldable t) <= Traversable t where - traverse :: forall a b m. Applicative m => (a -> m b) -> t a -> m (t b) - sequence :: forall a m. Applicative m => t (m a) -> m (t a) -``` - -`Traversable`は _巡回可能関手_ -の型クラスを定義します。これらの関数の型は少し難しそうに見えるかもしれませんが、`validatePerson`は良いきっかけとなる例です。 - -全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能関手*は、構造を1つの値へと纏める畳み込み操作を提供する型構築子であったことを思い出してください)。 -それに加えて、`Traversable`関手はその構造に依存した副作用の集まりを連結する機能を提供します。 - -複雑そうに聞こえるかもしれませんが、配列の場合に特殊化して簡単にした上で考えてみましょう。配列型構築子は`Traversable`であり、つまりは次のような関数が存在するということです。 - -```haskell -traverse :: forall a b m. Applicative m => (a -> m b) -> Array a -> m (Array b) -``` - -直感的にはこうです。 -任意のアプリカティブ関手`m`と、型`a`の値を取って型`b`の値を返す(`f`で追跡される副作用を持つ)関数が与えられたとします。 -このとき、その関数を型`Array a`の配列のそれぞれの要素に適用して型`Array -b`の(`f`で追跡される副作用を持つ)結果を得ることができます。 - -まだよくわからないでしょうか。それでは更に、`f`を上記の`V -Errors`アプリカティブ関手に特殊化して考えてみましょう。これで次の型を持つ関数が得られます。 - -```haskell -traverse :: forall a b. (a -> V Errors b) -> Array a -> V Errors (Array b) -``` - -この型シグネチャは、型`a`についての検証関数`m`があれば、`traverse m`は型`Array -a`の配列についての検証関数であるということを言っています。 -これはまさに、今必要になっている`Person`データ構造体の`phones`フィールドを検証する検証器そのものです。 -それぞれの要素が成功するかどうかを検証する検証関数を作るために、`validatePhoneNumber`を`traverse`へ渡しています。 - -一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算し、結果を累積します。 - -`Traversable`のもう1つの関数、`sequence`の型シグネチャには見覚えがあるかもしれません。 - -```haskell -sequence :: forall a m. Applicative m => t (m a) -> m (t a) -``` - -実際、先ほど書いた`combineList`関数は`Traversable`型クラスの`sequence`関数の特別な場合に過ぎません。 -`t`を型構築子`List`だとすると、`combineList`関数の型が復元されます。 - -```haskell -combineList :: forall f a. Applicative f => List (f a) -> f (List a) -``` - -巡回可能関手は、作用のある計算を集めてその作用を結合するという、データ構造走査の考え方を見据えたものです。実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくらい重要です。これらはお互いがお互いを利用して実装できます。これについては興味ある読者への演習として残しておきます。 - -`Data.List`で与えられているリストの`Traversable`インスタンスは次の通り。 - -```haskell -instance Traversable List where --- traverse :: forall a b m. Applicative m => (a -> m b) -> List a -> m (List b) -traverse _ Nil = pure Nil -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つの結果を組み合わせます。 - -巡回可能関手の例はただの配列やリスト以外にもあります。 -以前に見た`Maybe`型構築子も`Traversable`のインスタンスを持っています。 -PSCiで試してみましょう。 - -```text -> import Data.Maybe -> import Data.Traversable -> import Data.AddressBook.Validation - -> traverse (nonEmpty "Example") Nothing -pure (Nothing) - -> traverse (nonEmpty "Example") (Just "") -invalid (["Field 'Example' cannot be empty"]) - -> traverse (nonEmpty "Example") (Just "Testing") -pure ((Just "Testing")) -``` - -これらの例では、`Nothing`の値の走査は検証なしで`Nothing`の値を返し、`Just -x`を走査すると`x`を検証するのに検証関数が使われるということを示しています。 -要は、`traverse`は型`a`についての検証関数をとり、`Maybe -a`についての検証関数、つまり型`a`のオプショナルな値についての検証関数を返すのです。 - -他の巡回可能関手には`Array`、また任意の型`a`について`Tuple a`、`Either -a`が含まれます。一般的に、「容器」のようなデータの型構築子は大抵`Traversable`インスタンスを持っています。例として、演習では二分木の型の`Traversable`インスタンスを書くことになります。 - -## 演習 - - 1. (簡単)`Eq`と`Show`インスタンスを以下の2分木データ構造に対して書いてください。 - - ```haskell - data Tree a = Leaf | Branch (Tree a) a (Tree a) - ``` - - これらのインスタンスを手作業で書くこともできますし、コンパイラに導出してもらうこともできることを前の章から思い起こしてください。 - - `Show`の出力には多くの「正しい」書式の選択肢があります。 - この演習のテストでは以下の空白スタイルを期待しています。 - これはたまたま一般化されたshowの既定の書式と合致しているため、このインスタンスを手作業で書くつもりのときだけ、このことを念頭に置いておいてください。 - - ```haskell - (Branch (Branch Leaf 8 Leaf) 42 Leaf) - ``` - - 1. (普通)`Traversable`インスタンスを`Tree a`に対して書いてください。 - これは副作用を左から右に結合するものです。 - *手掛かり*:`Traversable`に定義する必要のある追加のインスタンス依存関係が幾つかあります。 - - 1. (普通)行き掛け順に木を巡回する関数`traversePreOrder :: forall a m b. Applicative m => (a - -> m b) -> Tree a -> m (Tree b)`を書いてください。 - つまり作用の実行は根左右と行われ、以前の通り掛け順の巡回の演習でしたような左根右ではありません。 - *手掛かり*:追加でインスタンスを定義する必要はありませんし、前に定義した関数は何も呼ぶ必要はありません。 - アプリカティブdo記法 (`ado`) はこの関数を書く最も簡単な方法です。 - - 1. (普通)木を帰り掛け順に巡回する関数`traversePostOrder`を書いてください。作用は左右根と実行されます。 - - 1. (普通)`homeAddress`フィールドがオプショナル(`Maybe`を使用)な新しい版の`Person`型をつくってください。 - それからこの新しい`Person`を検証する新しい版の`validatePerson`(`validatePersonOptionalAddress`と改名します)を書いてください。 - *手掛かり*:`traverse`を使って型`Maybe a`のフィールドを検証してください。 - - 1. (難しい)`sequence`のように振る舞う関数`sequenceUsingTraverse`を書いてください。 - ただし`traverse`を使ってください。 - - 1. (難しい)`traverse`のように振る舞う関数`traverseUsingSequence`を書いてください。 - ただし`sequence`を使ってください。 - -## アプリカティブ関手による並列処理 - -これまでの議論では、アプリカティブ関手がどのように「副作用を結合」させるかを説明するときに、「結合」(combine) という単語を選びました。 -しかし、これらの全ての例において、アプリカティブ関手は作用を「連鎖」(sequence) させる、というように言っても同じく妥当です。 -巡回可能関手がデータ構造に従って作用を順番に結合させる`sequence`関数を提供していることと、この直感的理解とは一致するでしょう。 - -しかし一般には、アプリカティブ関手はこれよりももっと一般的です。 -アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しません。 -実際、並列に副作用を実行するためのアプリカティブ関手というものは妥当になりえます。 - -例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだとしてもやはり正常に動き、このときどんな順序でそれぞれの検証器を実行しても問題はありません。 -データ構造に対して並列にこれの実行さえできるのです。 - -別の例として、`parallel`パッケージは、*並列計算*に対応する`Parallel`型クラスを与えます。 -`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入力の計算を*並列に*計算できます。 - -```haskell -f <$> parallel computation1 - <*> parallel computation2 -``` - -この計算は`computation1`と`computation2`を非同期に使って値の計算を始めるでしょう。そして両方の結果の計算が終わった時に、関数`f`を使って1つの結果へと結合するでしょう。 - -この考え方の詳細は、本書の後半で _コールバック地獄_ の問題に対してアプリカティブ関手を応用するときに見ていきます。 - -アプリカティブ関手は並列に結合できる副作用を一纏めにする自然な方法です。 - -## まとめ - -この章では新しい考え方を沢山扱いました。 - -- 関数適用の概念を副作用の観念を捉えた型構築子へと一般化する、 _アプリカティブ関手_ の概念を導入しました。 -- データ構造の検証という課題にアプリカティブ関手がどのような解決策を与えるか、どうすれば単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変換できるのかを見てきました。 -- `Traversable`型クラスに出会いました。*巡回可能関手*の考え方を内包するものであり、要素が副作用を持つ値の結合に使うことができる容れ物でした。 - -アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化です。 -本書を通じて何度も見ることになるでしょう。 -今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、これにより検証器が*どうやって*検証するかではなく、*何を*検証すべきなのかを定義できました。 -一般に、アプリカティブ関手は*領域特化言語*を設計する上で便利な道具になります。 - -次の章では、これに関連する考え方である*モナド*クラスを見て、アドレス帳の例をブラウザで実行させられるように拡張しましょう。 diff --git a/text-ja/chapter8.md b/text-ja/chapter8.md deleted file mode 100644 index 6d26638d..00000000 --- a/text-ja/chapter8.md +++ /dev/null @@ -1,1154 +0,0 @@ -# 作用モナド - -## この章の目標 - -前章では、オプショナルな型やエラーメッセージ、データの検証など、 _副作用_ -を扱いを抽象化するアプリカティブ関手を導入しました。この章では、より表現力の高い方法で副作用を扱うための別の抽象化、 _モナド_ を導入します。 - -この章の目的は、なぜモナドが便利な抽象化なのかということと、 _do記法_ との関係を説明することです。 - -## プロジェクトの準備 - -このプロジェクトでは、以下の依存関係が追加されています。 - -- `effect`: - 章の後半の主題である`Effect`モナドを定義しています。この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存関係にありました)、明示的にインストールしなければいけないことは稀です。 -- `react-basic-hooks`: アドレス帳アプリに使うWebフレームワークです。 - -## モナドとdo記法 - -do記法は*配列内包表記*を扱うときに初めて導入されました。 -配列内包表記は`Data.Array`モジュールの`concatMap`関数の構文糖として提供されています。 - -次の例を考えてみましょう。2つのサイコロを振って出た目を数え、出た目の合計が -`n`のときそれを得点とすることを考えます。次のような非決定的なアルゴリズムを使うとこれを実現できます。 - -- 最初の投擲で値 `x`を _選択_ します。 -- 2回目の投擲で値 `y`を _選択_ します。 -- もし `x`と `y`の和が `n`なら組 `[x, y]`を返し、そうでなければ失敗します。 - -配列内包表記を使うと、この非決定的アルゴリズムを自然に書くことができます。 - -```hs -import Prelude - -import Control.Plus (empty) -import Data.Array ((..)) - -{{#include ../exercises/chapter8/test/Examples.purs:countThrows}} -``` - -PSCiでこの関数の動作を見てみましょう。 - -```text -> import Test.Examples - -> countThrows 10 -[[4,6],[5,5],[6,4]] - -> countThrows 12 -[[6,6]] -``` - -前の章では、*オプショナルな値*に対応したより大きなプログラミング言語へとPureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養いました。 -同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができます。 - -一般に、ある型構築子 `m`のモナドは、型 `m a`の値を持つdo記法を使う手段を提供します。 -上の配列内包表記では、全ての行に何らかの型 `a`についての型 `Array a`の計算が含まれていることに注目してください。 -一般に、do記法ブロックの全ての行は、何らかの型 `a`とモナド `m`について、型 `m a`の計算を含んでいます。 -モナド `m`は全ての行で同じでなければなりません(つまり、副作用の種類は固定されます)が、型 -`a`は異なることもあります(言い換えると、個々の計算は異なる型の結果を持つことができます)。 - -以下はdo記法の別の例です。 -今回は型構築子 `Maybe`に適用されています。 -XMLノードを表す型 `XML`と次の関数があるとします。 - -```hs -child :: XML -> String -> Maybe XML -``` - -この関数はノードの子の要素を探し、もしそのような要素が存在しなければ `Nothing`を返します。 - -この場合、do記法を使うと深い入れ子になった要素を検索できます。 -XML文書としてエンコードされた利用者情報から、利用者の住んでいる市町村を読み取りたいとします。 - -```hs -userCity :: XML -> Maybe XML -userCity root = do - prof <- child root "profile" - addr <- child prof "address" - city <- child addr "city" - pure city -``` - -`userCity`関数は子の要素である `profile`を探し、 `profile`要素の中にある `address`要素、最後に -`address`要素から `city`要素を探します。 -これらの要素の何れかが欠落している場合は、返り値は `Nothing`になります。 -そうでなければ、返り値は `city`ノードから `Just`を使って構築されています。 - -最後の行にある`pure`関数は、全ての`Applicative`関手について定義されているのでした。 -`Maybe`の`Applicative`関手の`pure`関数は`Just`として定義されており、最後の行を `Just -city`へ変更しても同じように正しく動きます。 - -## モナド型クラス - -`Monad`型クラスは次のように定義されています。 - -```hs -class Apply m <= Bind m where - bind :: forall a b. m a -> (a -> m b) -> m b - -class (Applicative m, Bind m) <= Monad m -``` - -ここで鍵となる関数は `Bind`型クラスで定義されている演算子 `bind`で、`Functor`及び `Apply`型クラスにある `<$>`や `<*>`などの演算子と同様に、`Prelude`では `>>=`として `bind`の中置の別名が定義されています。 - -`Monad`型クラスは、既に見てきた `Applicative`型クラスの操作で `Bind`を拡張します。 - -`Bind`型クラスの例を幾つか見てみるのがわかりやすいでしょう。 -配列についての `Bind`の妥当な定義は次のようになります。 - -```hs -instance Bind Array where - bind xs f = concatMap f xs -``` - -これは以前に仄めかした、配列内包表記と `concatMap`関数の関係を説明しています。 - -`Maybe`型構築子についての `Bind`の実装は次のようになります。 - -```hs -instance Bind Maybe where - bind Nothing _ = Nothing - bind (Just a) f = f a -``` - -この定義は欠落した値がdo記法ブロックを通じて伝播するという直感的理解を裏付けるものです。 - -`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。最初に何らかの計算結果からの値の束縛から始まる簡単なdo記法ブロックについて考えてみましょう。 - -```hs -do value <- someComputation - whatToDoNext -``` - -PureScriptコンパイラはこのようなパターンを見つけるたびにコードを次にように置き換えます。 - -```hs -bind someComputation \value -> whatToDoNext -``` - -あるいは中置で書くと以下です。 - -```hs -someComputation >>= \value -> whatToDoNext -``` - -この計算 `whatToDoNext`は `value`に依存できます。 - -複数の束縛が関係している場合、この規則は先頭のほうから複数回適用されます。例えば、先ほど見た `userCity`の例では次のように脱糖されます。 - -```hs -userCity :: XML -> Maybe XML -userCity root = - child root "profile" >>= \prof -> - child prof "address" >>= \addr -> - child addr "city" >>= \city -> - pure city -``` - -do記法を使って表現されたコードは、`>>=`演算子を使って書かれた同じ意味のコードよりしばしば読みやすくなることも特筆すべき点です。一方で、明示的に `>>=`を使って束縛を書くと、しばしば*ポイントフリー*形式でコードが書けるようになります。ただし、読みやすさにはやはり注意がいります。 - -## モナド則 - -`Monad`型クラスは*モナド則*と呼ばれる3つの規則を持っています。これらは -`Monad`型クラスの合理的な実装から何を期待できるかを教えてくれます。 - -do記法を使用してこれらの規則を説明していくのが最も簡単でしょう。 - -### 単位元律 - -*右単位元則* (right-identity law) -が3つの規則の中で最も簡単です。この規則はdo記法ブロックの最後の式であれば、`pure`の呼び出しを排除できると言っています。 - -```hs -do - x <- expr - pure x -``` - -右単位元則は、この式は単なる `expr`と同じだと言っています。 - -*左単位元則* (left-identity law) -は、もしそれがdo記法ブロックの最初の式であれば、`pure`の呼び出しを除去できると述べています。 - -```hs -do - x <- pure y - next -``` - -このコードは`next`の名前`x`を式`y`で置き換えたものと同じです。 - -最後の規則は _結合則_ (associativity law) -です。これは入れ子になったdo記法ブロックをどう扱うのかについて教えてくれます。この規則が述べているのは以下のコード片のことです。 - -```hs -c1 = do - y <- do - x <- m1 - m2 - m3 -``` - -上記のコード片は、次のコードと同じです。 - -```hs -c2 = do - x <- m1 - y <- m2 - m3 -``` - -これらの計算にはそれぞれ、3つのモナドの式`m1`、`m2`、`m3`が含まれています。 -どちらの場合でも`m1`の結果は名前`x`に束縛され、`m2`の結果は名前`y`に束縛されます。 - -`c1`では2つの式 `m1`と `m2`がそれぞれのdo記法ブロック内にグループ化されています。 - -`c2`では`m1`、`m2`、`m3`の3つ全ての式が同じdo記法ブロックに現れています。 - -結合法則は入れ子になったdo記法ブロックをこのように単純化しても問題ないことを言っています。 - -*補足*:do記法を`bind`の呼び出しへと脱糖する定義により、 `c1`と `c2`は何れも次のコードと同じです。 - -```hs -c3 = do - x <- m1 - do - y <- m2 - m3 -``` - -## モナドで畳み込む - -抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で機能する関数を紹介していきます。 -これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと対応しているという直感的理解を補強しますし、モナドによるプログラミングがもたらす一般性も示しています。 - -これから `foldM`と呼ばれる関数を書いてみます。これは以前扱った -`foldl`関数をモナドの文脈へと一般化します。型シグネチャは次のようになっています。 - -```hs -foldM :: forall m a b. Monad m => (a -> b -> m a) -> a -> List b -> m a -foldl :: forall a b. (a -> b -> a) -> a -> List b -> a -``` - -モナド `m`が現れている点を除いて、 `foldl`の型と同じであることに注意しましょう。 - -直感的には、 `foldM`はさまざまな副作用の組み合わせに対応した文脈での配列の畳み込みを行うと捉えることができます。 - -例として `m`が `Maybe`であるとすると、この畳み込みはそれぞれの段階で `Nothing`を返すことで失敗させられます。 -それぞれの段階ではオプショナルな結果を返しますから、それゆえ畳み込みの結果もオプショナルになります。 - -もし `m`として配列の型構築子 -`Array`を選ぶとすると、畳み込みのそれぞれの段階で複数の結果を返すことができ、畳み込みは結果それぞれに対して次の手順を継続します。 -最後に、結果の集まりは、可能な経路全ての畳み込みから構成されることになります。 -これはグラフの走査と対応しています。 - -`foldM`を書くには、単に入力のリストについて場合分けをするだけです。 - -リストが空なら、型 `a`の結果を生成するための選択肢は1つしかありません。第2引数を返します。 - -```hs -foldM _ a Nil = pure a -``` - -なお`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。 - -リストが空でない場合はどうでしょうか。 -その場合、型 `a`の値、型 `b`の値、型 `a -> b -> m a`の関数があります。 -もしこの関数を適用すると、型 `m a`のモナドの結果を手に入れることになります。 -この計算の結果を逆向きの矢印 `<-`で束縛できます。 - -あとはリストの残りに対して再帰するだけです。実装は簡単です。 - -```hs -foldM f a (b : bs) = do - a' <- f a b - foldM f a' bs -``` - -なお、do記法を除けば、この実装は配列に対する `foldl`の実装とほとんど同じです。 - -PSCiでこれを定義し、試してみましょう。 -以下では例として、除算可能かどうかを調べて、失敗を示すために `Maybe`型構築子を使う、整数の「安全な除算」関数を定義するとしましょう。 - -```hs -{{#include ../exercises/chapter8/test/Examples.purs:safeDivide}} -``` - -これで、 `foldM`で安全な除算の繰り返しを表現できます。 - -```text -> import Test.Examples -> import Data.List (fromFoldable) - -> foldM safeDivide 100 (fromFoldable [5, 2, 2]) -(Just 5) - -> foldM safeDivide 100 (fromFoldable [2, 0, 4]) -Nothing -``` - -もし何れかの時点で整数にならない除算が行われようとしたら、`foldM safeDivide`関数は `Nothing`を返します。 -そうでなければ、除算を繰り返した累積の結果を`Just`構築子に包んで返します。 - -## モナドとアプリカティブ - -クラス間に上位クラス関係の効能があるため、`Monad`型クラスの全てのインスタンスは `Apply`型クラスのインスタンスでもあります。 - -しかし、あらゆる`Monad`のインスタンスに「無料で」ついてくる`Apply`型クラスの実装もあります。これは`ap`関数により与えられます。 - -```hs -ap :: forall m a b. Monad m => m (a -> b) -> m a -> m b -ap mf ma = do - f <- mf - a <- ma - pure (f a) -``` - -もし`m`に`Monad`型クラスの法則の縛りがあれば、`ap`で与えられる`m`について妥当な `Apply`インスタンスが存在します。 - -興味のある読者は、これまで登場した `Array`、 `Maybe`、 `Either e`といったモナドについて、この `ap`が -`apply`と一致することを確かめてみてください。 - -もし全てのモナドがアプリカティブ関手でもあるなら、アプリカティブ関手についての直感的理解を全てのモナドについても適用できるはずです。 -特に、モナドが更なる副作用の組み合わせで増強された「より大きな言語」でのプログラミングといろいろな意味で一致することを予想するのはもっともです。 -`map`と `apply`を使って、引数が任意個の関数をこの新しい言語へと持ち上げることができるはずです。 - -しかし、モナドはアプリカティブ関手でできること以上を行うことができ、重要な違いはdo記法の構文で強調されています。 -利用者情報をエンコードしたXML文書から利用者の都市を検索する、`userCity`の例についてもう一度考えてみましょう。 - -```hs -userCity :: XML -> Maybe XML -userCity root = do - prof <- child root "profile" - addr <- child prof "address" - city <- child addr "city" - pure city -``` - -do記法では2番目の計算が最初の結果 `prof`に依存し、3番目の計算が2番目の計算の結果`addr`に依存するというようなことができます。 -`Applicative`型クラスのインターフェイスだけを使うのでは、このように以前の値へ依存できません。 - -`pure`と `apply`だけを使って `userCity`を書こうとしてみれば、これが不可能であることがわかるでしょう。 -アプリカティブ関手ができるのは関数の互いに独立した引数を持ち上げることだけですが、モナドはもっと興味深いデータの依存関係に関わる計算を書くことを可能にします。 - -前の章では `Applicative`型クラスは並列処理を表現できることを見ました。 -持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りです。 -`Monad`型クラスは計算が前の計算の結果に依存できるようにしますから、同じようにはなりません。 -モナドは副作用を順番に組み合わせなければいけません。 - -## 演習 - - 1. (簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてください。 - 関数は適切な`Maybe`型で返します。 - *手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数の型を見つけ出してください。 - これらの関数を繋げるには`Maybe`モナドと共にdo記法を使ってください。 - 1. (普通)一掴みの硬貨を使ってできる可能な全ての合計を決定する関数 `possibleSums`を、 `foldM`を使って書いてみましょう。 - 入力の硬貨は、硬貨の価値の配列として与えられます。この関数は次のような結果にならなくてはいけません。 - - ```text - > possibleSums [] - [0] - - > possibleSums [1, 2, 10] - [0,1,2,3,10,11,12,13] - ``` - - *手掛かり*:`foldM`を使うと1行でこの関数を書くことが可能です。 - 重複を取り除いたり、結果を並び替えたりするのに、`nub`関数や `sort`関数を使いたくなるかもしれません。 -1. (普通)`Maybe`型構築子について、 `ap`関数と `apply`演算子が一致することを確認してください。 - *補足*:この演習にはテストがありません。 -1. (普通)`maybe`パッケージで定義されている`Maybe`型についての `Monad`インスタンスが、モナド則を満たしていることを検証してください。 - *補足*:この演習にはテストがありません。 -1. (普通)配列上の `filter`の関数を一般化した関数`filterM`を書いてください。 - この関数は次の型シグネチャを持ちます。 - - ```hs - filterM :: forall m a. Monad m => (a -> m Boolean) -> List a -> m (List a) - ``` - - 1. (難しい)全てのモナドには次で与えられるような既定の`Functor`インスタンスがあります。 - - ```hs - map f a = do - x <- a - pure (f x) - ``` - - モナド則を使って、全てのモナドが次を満たすことを証明してください。 - - ```hs - lift2 f (pure a) (pure b) = pure (f a b) - ``` - - ここで、 `Applly`インスタンスは上で定義された `ap`関数を使用しています。 - `lift2`が次のように定義されていたことを思い出してください。 - - ```hs - lift2 :: forall f a b c. Apply f => (a -> b -> c) -> f a -> f b -> f c - lift2 f a b = f <$> a <*> b - ``` - - *補足*:この演習にはテストがありません。 - -## ネイティブな作用 - -ここではPureScriptの中核となる重要なモナド、 `Effect`モナドについて見ていきます。 - -`Effect`モナドは `Effect`モジュールで定義されています。かつてはいわゆる _ネイティブ_ -副作用を管理していました。Haskellに馴染みがあれば、これは`IO`モナドと同等のものです。 - -ネイティブな副作用とは何でしょうか。 -この副作用はPureScript特有の式からJavaScriptの式を区別するものです。 -PureScriptの式は概して副作用とは無縁なのです。 -ネイティブな作用の例を以下に示します。 - -- コンソール入出力 -- 乱数生成 -- 例外 -- 変更可能な状態の読み書き - -また、ブラウザでは次のようなものがあります。 - -- DOM操作 -- XMLHttpRequest / AJAX呼び出し -- WebSocketによる相互作用 -- Local Storageの読み書き - -既に「ネイティブでない」副作用の例については数多く見てきています。 - -- `Maybe`データ型で表現される省略可能な値 -- `Either`データ型で表現されるエラー -- 配列やリストで表現される多値関数 - -これらの区別はわかりにくいので注意してください。 -エラーメッセージは例外の形でJavaScriptの式の副作用となることがあります。 -その意味では例外はネイティブな副作用を表していて、 `Effect`を使用して表現できます。 -しかし、 `Either`を使用して実装されたエラーメッセージはJavaScriptランタイムの副作用ではなく、 -`Effect`を使うスタイルでエラーメッセージを実装するのは適切ではありません。 -そのため、ネイティブなのは作用自体というより、実行時にどのように実装されているかです。 - -## 副作用と純粋性 - -PureScriptのような言語が純粋であるとすると、疑問が浮かんできます。副作用がないなら、どうやって役に立つ実際のコードを書くことができるというのでしょうか。 - -その答えはPureScriptの目的は副作用を排除することではないということです。これは、純粋な計算と副作用のある計算とを型システムにおいて区別できるような方法で、副作用を表現することを目的としているのです。この意味で、言語はあくまで純粋だということです。 - -副作用のある値は、純粋な値とは異なる型を持っています。そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起こらなくなります。 - -`Effect`モナドで管理された副作用を実行する唯一の方法は、型 `Effect a`の計算をJavaScriptから実行することです。 - -Spagoビルドツール(や他のツール)は早道を用意しており、アプリケーションの起動時に`main`計算を呼び出すための追加のJavaScriptコードを生成します。 -`main`は `Effect`モナドでの計算であることが要求されます。 - -## 作用モナド - -`Effect`は副作用のある計算を充分に型付けするAPIを提供すると同時に、効率的なJavaScriptを生成します。 - -馴染みのある`log`関数から返る型をもう少し見てみましょう。 -`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコンソールIOです。 -`Unit`はいかなる*意味のある*データも返らないことを示しています。 -`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられます。 - -```hs -log :: String -> Effect Unit -``` - -> _余談_ :より一般的な(そしてより込み入った型を持つ)`Effect.Class.Console`の`log`関数をIDEから提案されるかもしれません。 -> これは基本的な`Effect`モナドを扱う際は`Effect.Console`からの関数と交換可能です。 -> より一般的なバージョンがあることの理由は「モナドな冒険」章の「モナド変換子」について読んだあとにより明らかになっていることでしょう。 -> 好奇心のある(そしてせっかちな)読者のために言うと、これは`Effect`に`MonadEffect`インスタンスがあるから機能するのです。 -> -> ```hs -> log :: forall m. MonadEffect m => String -> m Unit -> ``` - -それでは意味のあるデータを返す`Effect`を考えましょう。 -`Effect.Random`の`random`関数は乱択された`Number`を生み出します。 - -```hs -random :: Effect Number -``` - -以下は完全なプログラムの例です(この章の演習フォルダの`test/Random.purs`にあります)。 - -```hs -{{#include ../exercises/chapter8/test/Random.purs}} -``` - -`Effect`はモナドなので、do記法を使って含まれるデータを開封し、それからこのデータを作用のある`logShow`関数に渡します。 -気分転換に、以下は`bind`演算子を使って書かれた同等なコードです。 - -```hs -main :: Effect Unit -main = random >>= logShow -``` - -これを手元で走らせてみてください。 - -```shell -spago run --main Test.Random -``` - -コンソールに出力 `0.0`と `1.0`の間で無作為に選ばれた数が表示されるでしょう。 - -> 余談:`spago run`は既定で`Main`モジュールとその中の`main`関数を探索します。 -`--main`フラグで代替のモジュールを入口として指定でき、上の例ではそうしています。 -この代替のモジュールもまた`main`関数を含んでいることに注目してください。 - -なお、不浄な作用付きのコードに訴えることなく、「乱択された」(技術的には疑似乱択された)データも生成できます。 -この技法は「テストを生成する」章で押さえます。 - -以前言及したように`Effect`モナドはPureScriptで核心的な重要さがあります。 -なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやりとりする上での常套手段だからです。 -`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕組みを提供します。 -`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように動作しどう使うのか理解することもまた極めて大事なことですので、実際にPureScriptで何か動かす前にその章を読まれることをお勧めします。 -要は`Effect`モナドは結構単純なのです。幾つかの補助関数がありますが、それを差し置いても副作用を内包すること以外には大したことはしません。 - -## 例外 - -2つの _ネイティブな_ 副作用が絡む`node-fs`パッケージの関数を調べましょう。ここでの副作用は可変状態の読み取りと例外です。 - -```hs -readTextFile :: Encoding -> String -> Effect String -``` - -もし存在しないファイルを読もうとすると…… - -```hs -import Node.Encoding (Encoding(..)) -import Node.FS.Sync (readTextFile) - -main :: Effect Unit -main = do - lines <- readTextFile UTF8 "iDoNotExist.md" - log lines -``` - -以下の例外に遭遇します。 - -```text - throw err; - ^ -Error: ENOENT: no such file or directory, open 'iDoNotExist.md' -... - errno: -2, - syscall: 'open', - code: 'ENOENT', - path: 'iDoNotExist.md' -``` - -この例外をうまく管理するには、潜在的に問題があるコードを`try`に包めばどのような出力でも制御できます。 - -```hs -main :: Effect Unit -main = do - result <- try $ readTextFile UTF8 "iDoNotExist.md" - case result of - Right lines -> log $ "Contents: \n" <> lines - Left error -> log $ "Couldn't open file. Error was: " <> message error -``` - -`try`は`Effect`を走らせて起こりうる例外を`Left`値として返します。 -もし計算が成功すれば結果は`Right`に包まれます。 - -```hs -try :: forall a. Effect a -> Effect (Either Error a) -``` - -独自の例外も生成できます。 -以下は`Data.List.head`の代替実装で、`Maybe`の値の`Nothing`を返す代わりにリストが空のとき例外を投げます。 - -```hs -exceptionHead :: List Int -> Effect Int -exceptionHead l = case l of - x : _ -> pure x - Nil -> throwException $ error "empty list" -``` - -ただし`exceptionHead`関数はどこかしら非実用的な例です。 -というのも、PureScriptのコードで例外を生成するのは避け、代わりに`Either`や`Maybe`のようなネイティブでない作用でエラーや欠けた値を使うのが一番だからです。 - -## 可変状態 - -中核ライブラリには `ST`作用という、これまた別の作用も定義されています。 - -`ST`作用は変更可能な状態を操作するために使われます。 -純粋関数プログラミングを知っているなら、共有される変更可能な状態は問題を引き起こしやすいということも知っているでしょう。 -しかし、`ST`作用は型システムを使って安全で*局所的な*状態変化を可能にし、状態の共有を制限するのです。 - -`ST`作用は -`Control.Monad.ST`モジュールで定義されています。これがどのように動作するかを確認するには、そのアクションの型を見る必要があります。 - -```hs -new :: forall a r. a -> ST r (STRef r a) - -read :: forall a r. STRef r a -> ST r a - -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`は型システムで*メモリ領域*(または*ヒープ*)を表しています。 - -例を示します。小さな時間刻みで簡単な更新関数の実行を何度も繰り返すことによって、重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。 - -粒子の位置と速度を保持する変更可能な参照領域を作成し、領域に格納された値を更新するのにforループを使うことでこれを実現できます。 - -```hs -import Prelude - -import Control.Monad.ST.Ref (modify, new, read) -import Control.Monad.ST (ST, for, run) - -simulate :: forall r. Number -> Number -> Int -> ST r Number -simulate x0 v0 time = do - ref <- new { x: x0, v: v0 } - for 0 (time * 1000) \_ -> - modify - ( \o -> - { v: o.v - 9.81 * 0.001 - , x: o.x + o.v * 0.001 - } - ) - ref - final <- read ref - pure final.x -``` - -計算の最後では、参照領域の最終的な値を読み取り、粒子の位置を返しています。 - -なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの他の部分で使われるのが許されない限り、これは純粋な関数のままです。 -`ST`作用が禁止するものが正確には何であるのかについては後ほど見ます。 - -`ST`作用付きで計算するには、`run`関数を使用する必要があります。 - -```hs -run :: forall a. (forall r. ST r a) -> a -``` - -ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化されているということです。 -`run`に渡したどんなアクションでも、*任意の領域*`r`が何であれ動作するということを意味しています。 - -しかし、ひとたび参照領域が -`new`によって作成されると、その領域の型は既に固定されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エラーになるでしょう。 -`run`が安全に `ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由なのです。 - -```hs -simulate' :: Number -> Number -> Int -> Number -simulate' x0 v0 time = run (simulate x0 v0 time) -``` - -PSCiでもこの関数を実行してみることができます。 - -```text -> import Main - -> simulate' 100.0 0.0 0 -100.00 - -> simulate' 100.0 0.0 1 -95.10 - -> simulate' 100.0 0.0 2 -80.39 - -> simulate' 100.0 0.0 3 -55.87 - -> simulate' 100.0 0.0 4 -21.54 -``` - -実は、もし `simulate`の定義を `run`の呼び出しのところへ埋め込むとすると、次のようになります。 - -```hs -simulate :: Number -> Number -> Int -> Number -simulate x0 v0 time = - run do - ref <- new { x: x0, v: v0 } - for 0 (time * 1000) \_ -> - modify - ( \o -> - { v: o.v - 9.81 * 0.001 - , x: o.x + o.v * 0.001 - } - ) - ref - final <- read ref - pure final.x -``` - -参照領域はそのスコープから逃れることができないことがコンパイラにわかりますし、安全に`ref`を`var`に変換できます。 -`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになります。 - -```javascript -var simulate = function (x0) { - return function (v0) { - return function (time) { - return (function __do() { - - var ref = { value: { x: x0, v: v0 } }; - - Control_Monad_ST_Internal["for"](0)(time * 1000 | 0)(function (v) { - return Control_Monad_ST_Internal.modify(function (o) { - return { - v: o.v - 9.81 * 1.0e-3, - x: o.x + o.v * 1.0e-3 - }; - })(ref); - })(); - - return ref.value.x; - - })(); - }; - }; -}; -``` - -なおこの結果として得られたJavaScriptは最適化の余地があります。 -詳細は[この課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。 -上記の抜粋はその課題が解決されたら更新されるでしょう。 - -比較としてこちらが埋め込まれていない形式で生成されたJavaScriptです。 - -```js -var simulate = function (x0) { - return function (v0) { - return function (time) { - return function __do() { - - var ref = Control_Monad_ST_Internal["new"]({ x: x0, v: v0 })(); - - Control_Monad_ST_Internal["for"](0)(time * 1000 | 0)(function (v) { - return Control_Monad_ST_Internal.modify(function (o) { - return { - v: o.v - 9.81 * 1.0e-3, - x: o.x + o.v * 1.0e-3 - }; - })(ref); - })(); - - var $$final = Control_Monad_ST_Internal.read(ref)(); - return $$final.x; - }; - }; - }; -}; -``` - -局所的な変更可能状態を扱うとき、特に作用が絡むループを生成する`for`、 `foreach`、 -`while`のようなアクションを一緒に使うときには、`ST`作用は短いJavaScriptを生成する良い方法となります。 - -## 演習 - -1. (普通)`safeDivide`関数を書き直し、もし分母がゼロなら`throwException`を使って文言`"div - zero"`の例外を投げるようにしたものを`exceptionDivide`としてください。 -1. (普通)関数`estimatePi :: Int -> Number`を書いてください。 - この関数は`n`項[Gregory - Series](https://mathworld.wolfram.com/GregorySeries.html)を使って`pi`の近似を計算するものです。 - *手掛かり*:解答は上記の`simulate`の定義に倣うことができます。 - また`Data.Int`の`toNumber :: Int -> - Number`を使って、`Int`を`Number`に変換する必要があるかもしれません。 -1. (普通)`n`番目のフィボナッチ数を計算する関数`fibonacci :: Int -> - Int`を書いてください。`ST`を使って前の2つのフィボナッチ数の値を把握します。新しい`ST`に基づく実装の実行速度を第4章の再帰実装に対して比較してください。 - -## DOM作用 - -この章の最後の節では、`Effect`モナドでの作用についてこれまで学んだことを、実際のDOM操作の問題に応用します。 - -DOMを直接扱ったり、オープンソースのDOMライブラリを扱ったりするPureScriptパッケージが沢山あります。 -例えば以下です。 - -- [`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ライブラリもあります。 -以下のようなものです。 - -- [`thermite`](https://github.com/paf31/purescript-thermite)は[`react`](https://github.com/purescript-contrib/purescript-react)を土台に構築されています。 -- [`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-hooks)は[`react-basic`](https://github.com/lumihq/purescript-react-basic)を土台に構築されています。 -- [`halogen`](https://github.com/purescript-halogen/purescript-halogen)は独自の仮想DOMライブラリを土台とする型安全な一揃いの抽象化を提供します。 - -この章では -`react-basic-hooks`ライブラリを使用し、住所簿アプリケーションにユーザーインターフェイスを追加しますが、興味のあるユーザは異なるアプローチで進めることをお勧めします。 - -## 住所録のユーザーインターフェース - -`react-basic-hooks`ライブラリを使い、アプリケーションをReact*コンポーネント*として定義していきます。ReactコンポーネントはHTML要素を純粋なデータ構造としてコードで記述します。それからこのデータ構造は効率的にDOMへ描画されます。加えてコンポーネントはボタンクリックのようなイベントに応答できます。`react-basic-hooks`ライブラリは`Effect`モナドを使ってこれらのイベントの制御方法を記述します。 - -Reactライブラリの完全な入門はこの章の範囲をはるかに超えていますが、読者は必要に応じて説明書を参照することをお勧めします。 -目的に応じて、Reactは `Effect`モナドの実用的な例を提供してくれます。 - -利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。 -フォームには、さまざまなフィールド(姓、名前、都市、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。 -テキストボックスに利用者がテキストを入力すると、検証エラーが更新されます。 - -簡潔さを保つために、フォームは固定の形状とします。電話番号は種類(自宅、携帯電話、仕事、その他)ごとに別々のテキストボックスへ分けることにします。 - -`exercises/chapter8`ディレクトリから以下のコマンドでWebアプリを立ち上げることができます。 - -```shell -$ npm install -$ npx spago build -$ npx parcel src/index.html --open -``` - -もし`spago`や`parcel`のような開発ツールが大域的にインストールされていれば、`npx`の前置は省けるでしょう。 -恐らく既に`spago`を`npm i -g spago`で大域的にインストールしていますし、`parcel`についても同じことができるでしょう。 - -`parcel`は「アドレス帳」アプリのブラウザ窓を立ち上げます。 -`parcel`の端末を開いたままにし、他の端末で`spago`で再構築すると、最新の編集を含むページが自動的に再読み込みされるでしょう。 -また、[`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)を使っていれば、ファイルを保存したときに自動的にページが再構築される(そして自動的にページが再読み込みされる)ように設定できます。 - -このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上に出力された検証エラーを見ることができるでしょう。 - -動作の仕組みを散策しましょう。 - -`src/index.html`ファイルは最小限です。 - -```html -{{#include ../exercises/chapter8/src/index.html}} -``` - -`>= document >>= toNonElementParentNode >>> getElementById "container" -``` - -途中の`w`や`doc`変数が読みやすさの助けになるかは主観的な好みの問題です。 - -AddressBookの`reactComponent`を深堀りしましょう。 -単純化されたコンポーネントから始め、それから`Main.purs`で実際のコードに構築していきます。 - -以下の最小限のコンポーネントをご覧ください。 -遠慮なく全体のコンポーネントをこれに置き換えて実行の様子を見てみましょう。 - -```hs -mkAddressBookApp :: Effect (ReactComponent {}) -mkAddressBookApp = - reactComponent - "AddressBookApp" - (\props -> pure $ D.text "Hi! I'm an address book") -``` - -`reactComponent`にはこのような威圧的なシグネチャがあります。 - -```hs -reactComponent :: - forall hooks props. - Lacks "children" props => - Lacks "key" props => - Lacks "ref" props => - String -> - ({ | props } -> Render Unit hooks JSX) -> - Effect (ReactComponent { | props }) -``` - -重要な注意点は全ての型クラス制約の後の引数にあります。 -`String`(任意のコンポーネント名)、`props`を描画された`JSX`に変換する方法を記述する関数を取り、そして`Effect`に包まれた`ReactComponent`を返します。 - -propsからJSXへの関数は単にこうです。 - -```hs -\props -> pure $ D.text "Hi! I'm an address book" -``` - -`props`は無視されており、`D.text`は`JSX`を返し、そして`pure`は描画されたJSXに持ち上げます。 -これで`component`には`ReactComponent`を生成するのに必要な全てがあります。 - -次に完全なアドレス帳コンポーネントにある幾つかの複雑な事柄をもう少し調べていきます。 - -これらは完全なコンポーネントの最初の数行です。 - -```hs -mkAddressBookApp :: Effect (ReactComponent {}) -mkAddressBookApp = do - reactComponent "AddressBookApp" \props -> R.do - Tuple person setPerson <- useState examplePerson -``` - -`person`を`useState`フックの状態の一部として追跡します。 - -```hs -Tuple person setPerson <- useState examplePerson -``` - -なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部品に分解することが自在にできます。 -例えば`Person`のそれぞれのレコードフィールドについて分離した状態の部品を使って、このアプリを書き直すことができるでしょう。 -しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいます。 - -他の例では`Tuple`用の`/\`中置演算子に出喰わすかもしれません。 -これは先の行と等しいものです。 - -```hs -firstName /\ setFirstName <- useState p.firstName -``` - -`useState`は、既定の初期値を取って現在の値と値を更新する方法を取ります。 -`useState`の型を確認すれば型`person`と`setPerson`についてより深い洞察が得られます。 - -```hs -useState :: - forall state. - state -> - Hook (UseState state) (Tuple state ((state -> state) -> Effect Unit)) -``` - -結果の値の梱包`Hook (UseState -state)`は取り去ることができますが、それは`useState`が`R.do`ブロックの中で呼ばれているからです。 -`R.do`は後で詳述します。 - -さてこれで以下のシグネチャを観察できます。 - -```hs -person :: state -setPerson :: (state -> state) -> Effect Unit -``` - -`state`の限定された型は初期の既定値によって決定されます。 -これは`examplePerson`の型なのでこの場合は`Person` `Record`です。 - -`person`はそれぞれの再描画の時点で現在の状態にアクセスする方法です。 - -`setPerson`は状態を更新する方法です。 -単に現在の状態を新しい状態に変形する方法を記述する関数を提供します。 -`state`の型が偶然`Record`のときは、レコード更新構文がこれにぴったり合います。 -例えば以下。 - -```hs -setPerson (\currentPerson -> currentPerson {firstName = "NewName"}) - -``` - -あるいは短かく以下です。 - -```hs -setPerson _ {firstName = "NewName"} -``` - -`Record`でない状態もまた、この更新パターンに従います。 -ベストプラクティスについて、より詳しいことは[この手引き](https://github.com/megamaddu/purescript-react-basic-hooks/pull/24#issuecomment-620300541)を参照してください。 - -`useState`が`R.do`ブロックの中で使われていることを思い出しましょう。 -`R.do`は`do`の特別なreactフックの派生です。 -`R.`の前置はこれが`React.Basic.Hooks`から来たものとして「限定する」もので、`R.do`ブロックの中でフック互換版の`bind`を使うことを意味しています。 -これは「限定されたdo」として知られています。 -`Hook (UseState state)`の梱包を無視し、内部の値の`Tuple`と変数に束縛してくれます。 - -他の状態管理戦略として挙げられるのは`useReducer`ですが、それはこの章の範疇外です。 - -以下では`JSX`の描画が行われています。 - -```hs -pure - $ D.div - { className: "container" - , children: - renderValidationErrors errors - <> [ D.div - { className: "row" - , children: - [ D.form_ - $ [ D.h3_ [ D.text "Basic Information" ] - , formField "First Name" "First Name" person.firstName \s -> - setPerson _ { firstName = s } - , formField "Last Name" "Last Name" person.lastName \s -> - setPerson _ { lastName = s } - , D.h3_ [ D.text "Address" ] - , formField "Street" "Street" person.homeAddress.street \s -> - setPerson _ { homeAddress { street = s } } - , formField "City" "City" person.homeAddress.city \s -> - setPerson _ { homeAddress { city = s } } - , formField "State" "State" person.homeAddress.state \s -> - setPerson _ { homeAddress { state = s } } - , D.h3_ [ D.text "Contact Information" ] - ] - <> renderPhoneNumbers - ] - } - ] - } -``` - -ここでDOMの意図した状態を表現する`JSX`を生成しています。このJSXはHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、`label`、`input`)に対応し、典型的には単一のHTML要素を作る関数を適用することで作られます。これらのHTML要素は実はReactコンポーネントそのものによりJSXに変換されます。通常これらの関数にはそれぞれ3つの種類があります。 - -- `div_`: 子要素の配列を受け付けます。 - 既定の属性を使います。 -- `div`: 属性の`Record`を受け付けます。 - 子要素の配列をこのレコードの`children`フィールドに渡すことができます。 -- `div'`: `div`と同じですが、`JSX`に変換する前に`ReactComponent`を返します。 - -検証エラーをフォームの一番上に(もしあれば)表示するため、`Errors`構造体をJSXの配列に変える`renderValidationErrors`補助関数を作ります。この配列はフォームの残り部分の手前に付けます。 - -```hs -{{#include ../exercises/chapter8/src/Main.purs:renderValidationErrors}} -``` - -なお、ここでは単に通常のデータ構造体を操作しているので、`map`のような関数を使ってもっと面白い要素を構築できます。 - -```hs -children: [ D.ul_ (map renderError xs)] -``` - -`className`プロパティを使ってCSSスタイルのクラスを定義します。 -このプロジェクトでは[Bootstrap](https://getbootstrap.com/)の`stylesheet`を使っており、これは`index.html`でインポートされています。 -例えばフォーム中のアイテムは`row`として配置されてほしいですし、検証エラーは`alert-danger`の装飾で強調されていてほしいです。 - -```hs -className: "alert alert-danger row" -``` - -2番目の補助関数は `formField`です。 -これは、単一フォームフィールドのテキスト入力を作ります。 - -```hs -{{#include ../exercises/chapter8/src/Main.purs:formField}} -``` - -`input`を置いて`label`の中に`text`を表示すると、スクリーンリーダーのアクセシビリティの助けになります。 - -`onChange`属性があれば利用者の入力に応答する方法を記述できます。`handler`関数を使いますが、これは以下の型を持ちます。 - -```hs -handler :: forall a. EventFn SyntheticEvent a -> (a -> Effect Unit) -> EventHandler -``` - -`handler`への最初の引数には`targetValue`を使いますが、これはHTMLの`input`要素中のテキストの値を提供します。 -この場合は型変数`a`が`Maybe String`で、`handler`が期待するシグネチャに合致しています。 - -```hs -targetValue :: EventFn SyntheticEvent (Maybe String) -``` - -JavaScriptでは`input`要素の`onChange`イベントは実は`String`値と一緒になっているのですが、JavaScriptの文字列はnullになりえるので、安全のために`Maybe`が使われています。 - -したがって`(a -> Effect Unit)`の`handler`への2つ目の引数は、このシグネチャを持ちます。 - -```hs -Maybe String -> Effect Unit -``` - -この関数は`Maybe String`値を求める作用に変換する方法を記述します。 -この目的のために以下のように独自の`handleValue`関数を定義して`handler`を渡します。 - -```hs -onChange: - let - handleValue :: Maybe String -> Effect Unit - handleValue (Just v) = setValue v - handleValue Nothing = pure unit - in - handler targetValue handleValue -``` - -`setValue`はそれぞれの`formField`の呼び出しに与えた関数で、文字列を取り`setPerson`フックに適切なレコード更新呼び出しを実施します。 - -なお`handleValue`は以下のようにも置き換えられます。 - -```hs -onChange: handler targetValue $ traverse_ setValue -``` - -`traverse_`の定義を調査して、両方の形式が確かに等価であることをご確認ください。 - -これでコンポーネント実装の基本を押さえました。しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随する出典元をお読みください。 - -明らかに、このユーザーインターフェースには改善すべき点が沢山あります。 -演習ではアプリケーションがより使いやすくなるような方法を追究していきます。 - -## 演習 - -以下の演習では`src/Main.purs`を変更してください。 -これらの演習には単体試験はありません。 - -1. (簡単)このアプリケーションを変更し、職場の電話番号を入力できるテキストボックスを追加してください。 -1. (普通)現時点でアプリケーションは検証エラーを単一の「pink-alert」背景に集めて表示させています。 - 空の線で分割することにより、それぞれの検証エラーにpink-alert背景を持たせるように変更してください。 - - *手掛かり*:リスト中の検証エラーを表示するのに`ul`要素を使う代わりに、コードを変更し、それぞれのエラーに`alert`と`alert-danger`装飾を持つ`div`を作ってください。 -1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。コードを変更してこの問題を解決してください。 - - *手掛かり*:検証器によって返されるエラーの型は、エラーの原因となっているフィールドを示すために拡張する必要があります。次のような変更されたエラー型を使用したくなるでしょう。 - - ```hs - data Field = FirstNameField - | LastNameField - | StreetField - | CityField - | StateField - | PhoneField PhoneType - - data ValidationError = ValidationError String Field - - type Errors = Array ValidationError - ``` - - `Error`構造体から特定の`Field`のための検証エラーを取り出す関数を書く必要があるでしょう。 - -## まとめ - -この章ではPureScriptでの副作用の扱いについての多くの考え方を導入しました。 - -- `Monad`型クラスとdo記法との関係性に出会いました。 -- モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。 -- 異なる副作用を扱うコードを書くために、モナドを抽象的に使う方法を見ました。 -- モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算を可能にするのかということ、そして2つの手法の違いを説明しました。 -- ネイティブな作用の概念を定義し、ネイティブな副作用を処理するために使用する `Effect`モナドを導入しました。 -- 乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作といった、さまざまな作用を扱うために - `Effect`モナドを使いました。 - -`Effect`モナドは実際のPureScriptコードにおける基本的なツールです。本書ではこのあとも、多くの場面で副作用を処理するために使っていきます。 diff --git a/text-ja/chapter9.md b/text-ja/chapter9.md index b638aeac..3eff1186 100644 --- a/text-ja/chapter9.md +++ b/text-ja/chapter9.md @@ -2,7 +2,11 @@ ## この章の目標 -この章では`Aff`モナドに集中します。これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。ファイルシステムとやりとりしてHTTPリクエストを作る、非同期な例を実演していきます。また非同期作用の直列ないし並列な実行の管理方法も押さえます。 +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 managing sequential and parallel execution of +asynchronous effects. ## プロジェクトの準備 @@ -13,9 +17,9 @@ - `affjax` - AJAXと`Aff`を使ったHTTPリクエスト。 - `parallel` - `Aff`の並列実行。 -(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリは`xhr2`NPMモジュールが必要です。 -このモジュールはこの章の`package.json`中の依存関係に挙げられています。 -以下を走らせてインストールします。 +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 a +dependency in the `package.json` of this chapter. Install that by running: ```shell $ npm install @@ -42,7 +46,8 @@ copyFile('file1.txt', 'file2.txt') }); ``` -コールバックや同期関数を使うことも可能ですが、以下の理由から望ましくありません。 +It is also possible to use callbacks or synchronous functions, but those are +less desirable because: - コールバックは過剰な入れ子に繋がります。これは「コールバック地獄」や「悪夢のピラミッド」として知られています。 - 同期関数はアプリ中の他のコードの実行を堰き止めてしまいます。 @@ -58,10 +63,14 @@ PureScriptでの`Aff`モナドはJavaScriptの`async`/`await`構文に似た人 なお、`main`は`Effect Unit`でなければならないので、`launchAff_`を使って`Aff`から`Effect`へと変換せねばなりません。 -上のコード片をコールバックや同期関数を使って書き換えることも可能ですが(例えば`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それらのコーディング形式は推奨されません。 +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`, +respectively), but those share the same downsides as discussed earlier with +JavaScript, so that coding style is not recommended. -`Aff`を扱う文法は`Effect`を扱うものと大変似ています。 -どちらもモナドですし、したがってdo記法で書くことができます。 +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. 例えば`readTextFile`のシグネチャを見れば、これがファイルの内容を`String`とし、`Aff`に包んで返していることがわかります。 @@ -91,18 +100,23 @@ attempt :: forall a. Aff a -> Aff (Either Error a) ## 演習 - 1. (簡単)2つのテキストファイルを連結する関数`concatenateFiles`を書いてください。 + 1. (Easy) Write a `concatenateFiles` function that concatenates two text + files. - 1. (普通)入力ファイル名の配列と出力ファイル名が与えられたとき、複数のテキストファイルを連結する関数`concatenateMany`を書いてください。 - *手掛かり*:`traverse`を使ってください。 + 1. (Medium) Write a function `concatenateMany` to concatenate multiple text + files, given an array of input and output file names. _Hint_: use + `traverse`. 1. (普通)ファイル中の文字数を返すか、エラーがあればそれを返す関数`countCharacters :: FilePath -> Aff (Either Error Int)`を書いてください。 ## 更なるAffの資料 -もしまだ[公式のAffの手引き](https://pursuit.purescript.org/packages/purescript-aff/)を見ていなければ、今ざっと目を通してください。 -この章の残りの演習を完了する上で事前に必要なことではありませんが、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. 以下の補足資料についてもあたってみるとよいでしょう。しかし繰り返しになりますがこの章の演習はこれらの内容に依りません。 @@ -111,11 +125,19 @@ attempt :: forall a. Aff a -> Aff (Either Error a) ## 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`を使います。 -より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript.org/packages/purescript-affjax)にあたってください。 -以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例です。 +The `affjax` library offers a convenient way to make asynchronous AJAX HTTP +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: ```hs {{#include ../exercises/chapter9/test/HTTP.purs:getUrl}} @@ -150,9 +172,12 @@ unit 非同期計算を*並列にも*合成できたら便利でしょう。 `Aff`があれば2つの計算を次々に開始するだけで並列に計算できます。 -`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義しており、並列実行に対応しています。 -以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリカティブ関手がどれほど便利なのかを見ました。 -実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を合成するために使われるアプリカティブ関手`f`との対応関係を定義しているのです。 +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` that can be used to combine computations in parallel: ```hs class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where @@ -165,16 +190,19 @@ class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where - `parallel`:モナド`m`中の計算を取り、アプリカティブ関手`f`中の計算に変えます。 - `sequential`:反対方向に変換します。 -`aff`ライブラリは `Aff`モナドの `Parallel`インスタンスを提供します。 -これは、2つの継続 (continuation) のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に -`Aff`アクションを組み合わせます。 -両方の結果が返されたら、最終結果を計算してメインの継続に渡すことができます。 +The `aff` library provides a `Parallel` instance for the `Aff` monad. It +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. アプリカティブ関手では任意個の引数の関数の持ち上げができるので、このアプリカティブコンビネータを使ってより多くの計算を並列に実行できます。 `traverse`や`sequence`といった、アプリカティブ関手を扱う全ての標準ライブラリ関数から恩恵を受けることもできます。 -必要に応じて -`parralel`と`sequential`を使って型構築子を変更することで、do記法ブロック中でアプリカティブコンビネータを使い、直列的なコードの一部で並列計算を結合したり、またはその逆を行ったりできます。 +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. 直列実行と並列実行の間の違いを実演するために、100個の10ミリ秒の遅延からなる配列をつくり、それからその遅延を両方の手法で実行します。REPLで試すと`seqDelay`が`parDelay`より遥かに遅いことに気付くでしょう。並列実行が`sequence_`を`parSequence_`で置き換えるだけで有効になるところに注目です。 @@ -219,18 +247,20 @@ unit ## 演習 -1. (簡単)前の`concatenateMany`関数と同じシグネチャを持つ`concatenateManyParallel`関数を書いてください。 - ただし全ての入力ファイルを並列に読むようにしてください。 +1. (Easy) Write a `concatenateManyParallel` function with the same signature + as the earlier `concatenateMany` function but reads all input files in + parallel. 1. (普通)与えられたURLへHTTP `GET`を要求して以下の何れかを返す`getWithTimeout :: Number -> String -> Aff (Maybe String)`関数を書いてください。 - `Nothing`: 要求してから与えられた時間制限(ミリ秒単位)より長く掛かった場合。 - 文字列の応答:時間制限を越える前に要求が成功した場合。 -1. (難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてください。 - 一覧にあるファイルを並列に読んでください。 - パスはそのファイルが表れたディレクトリから相対的なものです。 - *手掛かり*:`node_path`モジュールにはディレクトリを扱う上で便利な関数があります。 +1. (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 some helpful functions for negotiating directories. 例えば次のような`root.txt`ファイルから始まるとします。 @@ -261,7 +291,7 @@ $ cat c/a/a.txt ## まとめ -この章では非同期エフェクトと以下の方法を押さえました。 +In this chapter, we covered asynchronous effects and learned how to: - `aff`ライブラリを使って`Aff`モナド中で非同期コードを走らせる。 - `affjax`ライブラリを使って非同期にHTTPリクエストを行う。 diff --git a/translation/all.pot b/translation/all.pot index 85b3a5a7..36c888e0 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-07-10 21:30+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,14 +397,14 @@ 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 "" @@ -420,24 +420,24 @@ msgstr "" 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 #, 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:" @@ -457,7 +457,7 @@ msgstr "" #, 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 "" @@ -497,8 +497,8 @@ msgstr "" 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 ## @@ -511,7 +511,7 @@ msgstr "" #: text/chapter1.md:69 #, 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 "" @@ -533,7 +533,7 @@ msgstr "" 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 "" @@ -596,8 +596,8 @@ msgstr "" #: text/chapter1.md:87 #, 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 "" @@ -632,7 +632,7 @@ msgstr "" 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 "" @@ -641,7 +641,7 @@ msgstr "" #, 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 " @@ -659,7 +659,7 @@ msgstr "" #: text/chapter1.md:102 #, 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 " @@ -674,7 +674,7 @@ msgstr "" #, 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, " @@ -687,7 +687,7 @@ msgstr "" #. type: Plain text #: text/chapter1.md:106 #, 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) @@ -720,7 +720,7 @@ msgstr "" #, 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 "" @@ -744,9 +744,9 @@ msgstr "" #: text/chapter1.md:131 #, 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 @@ -757,7 +757,7 @@ msgid "" "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 ## @@ -780,7 +780,7 @@ msgstr "" 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: '- ' @@ -788,9 +788,7 @@ msgstr "" #, 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: '- ' @@ -828,7 +826,7 @@ msgstr "" 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 "" @@ -837,7 +835,7 @@ msgstr "" #, 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 "" @@ -845,9 +843,9 @@ msgstr "" #: text/chapter1.md:146 #, 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 @@ -855,7 +853,7 @@ msgstr "" #, markdown-text msgid "" "If you prefer to learn by reading examples, the `purescript`, " -"`purescript-node` and `purescript-contrib` GitHub organizations contain " +"`purescript-node`, and `purescript-contrib` GitHub organizations contain " "plenty of examples of PureScript code." msgstr "" @@ -871,7 +869,7 @@ msgstr "" 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 "" @@ -895,7 +893,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 "" @@ -920,7 +918,7 @@ msgstr "" 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 "" @@ -929,8 +927,8 @@ msgstr "" #, 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 "" @@ -962,7 +960,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 +1009,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 +1041,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 +1084,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 +1094,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 +1151,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 +1174,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 +1291,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 +1398,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 +1432,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 +1503,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 +1530,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 +1541,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,11 +1595,11 @@ 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 @@ -1611,10 +1608,10 @@ msgstr "" #: 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 +1667,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 +1709,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 +1754,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 +1905,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 +1964,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 +1987,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 +2003,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 +2017,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 +2054,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 +2074,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 +2082,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 +2090,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 +2117,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 +2142,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 +2150,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:487 +#: text/chapter10.md:489 #, markdown-text, no-wrap msgid "" " ```hs\n" @@ -2157,7 +2163,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 +2174,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 +2183,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 +2199,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 +2207,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 +2239,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 +2265,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 +2279,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 +2297,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 +2305,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 +2318,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 +2329,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:562 +#: text/chapter10.md:564 #, no-wrap msgid "" "$ spago repl\n" @@ -2335,13 +2341,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 +2356,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 +2364,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 +2372,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 +2382,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 +2403,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 +2413,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 +2432,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 +2443,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 +2462,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 +2478,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 +2487,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 +2501,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 +2509,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 +2525,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 +2552,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 +2570,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 +2583,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 +2591,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 +2602,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:698 +#: text/chapter10.md:700 #, no-wrap msgid "" "$ spago repl\n" @@ -2615,7 +2621,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 +2629,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 +2653,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 +2676,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 +2693,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 +2701,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:754 +#: text/chapter10.md:756 #, no-wrap msgid "" "$ spago repl\n" @@ -2722,7 +2728,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 +2738,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 +2748,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 +2756,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 +2766,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 +2774,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 +2782,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 +2796,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 +2812,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 +2820,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:809 +#: text/chapter10.md:811 #, no-wrap msgid "" "$ spago repl\n" @@ -2830,13 +2836,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 +2850,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 +2858,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter10.md:830 +#: text/chapter10.md:832 #, no-wrap msgid "" "$ spago repl\n" @@ -2867,7 +2873,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 +2885,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 +2894,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 +2908,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 +2919,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 +2928,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 +2939,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 +2968,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 +2978,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 +2989,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 +3021,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:906 +#: text/chapter10.md:908 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -3026,7 +3032,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 +3048,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter10.md:917 +#: text/chapter10.md:919 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -3053,7 +3059,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 +3068,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 +3091,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 +3099,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 +3113,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 +3121,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 +3130,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 +3139,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 +3147,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 +3158,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 +3182,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 +3190,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 +3205,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 +3213,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 +3221,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 +3241,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 +3249,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 +3284,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 +3304,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 +3312,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 +3320,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 +3336,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 +3344,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 +3358,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 +3369,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 +3394,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 +3428,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 +3436,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 +3444,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 +3452,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 +3460,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/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: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/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 +3487,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 +3531,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 +3547,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 +3563,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 +3573,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 +3581,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 +3601,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 +3625,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 +3651,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 +3701,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 +3710,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 +3722,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 +3734,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 +3779,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 +3842,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 +3852,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 +3864,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 +3902,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 +3958,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 +3978,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 +3986,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 +3995,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 +4006,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 +4019,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 +4044,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 +4107,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 +4124,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 +4134,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 +4142,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 +4151,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 +4168,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 +4180,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 +4205,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 +4219,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 +4256,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 +4279,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 +4288,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 +4297,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 +4306,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 +4325,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 +4363,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 +4382,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 +4402,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 +4426,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 +4435,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 +4495,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 +4518,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 +4554,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 +4587,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 +4595,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 +4604,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 +4622,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:130 +#: text/chapter11.md:131 #, no-wrap msgid "" "> :paste\n" @@ -4636,14 +4642,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 +4669,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 +4687,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:161 +#: text/chapter11.md:160 #, markdown-text, no-wrap msgid "" " > testParens \"(()(())())\"\n" @@ -4690,7 +4695,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:164 +#: text/chapter11.md:163 #, markdown-text, no-wrap msgid "" " > testParens \")\"\n" @@ -4698,7 +4703,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:168 +#: text/chapter11.md:167 #, markdown-text, no-wrap msgid "" " > testParens \"(()()\"\n" @@ -4707,7 +4712,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 +4721,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 +4738,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 +4746,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 +4760,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 +4769,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 +4779,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 +4787,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 +4796,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 +4808,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 +4816,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 +4824,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 +4832,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 +4840,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 +4848,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 +4863,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 +4872,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 +4889,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 +4898,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:246 +#: text/chapter11.md:245 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4902,7 +4907,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 +4916,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:253 +#: text/chapter11.md:252 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4920,7 +4925,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 +4934,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter11.md:260 +#: text/chapter11.md:259 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -4938,21 +4943,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 +4971,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 +5024,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 +5045,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 +5053,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 +5063,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 +5071,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 +5084,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 +5092,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 +5100,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 +5108,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 +5126,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 +5134,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 +5152,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 +5160,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 +5176,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 +5207,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 +5234,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 +5243,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 +5251,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 +5259,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 +5267,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 +5277,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 +5285,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 +5293,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 +5301,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 +5336,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 +5350,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 +5374,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 +5400,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 +5411,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 +5419,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 +5457,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 +5476,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 +5484,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 +5492,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 +5501,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 +5510,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 +5525,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 +5536,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 +5544,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 +5601,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 +5622,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 +5630,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 +5655,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 +5663,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter11.md:538 +#: text/chapter11.md:537 #, no-wrap msgid "" "> runParser split \"\"\n" @@ -5669,31 +5671,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 +5704,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 +5713,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 +5728,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 +5752,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 +5773,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 +5787,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 +5796,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 +5804,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 +5813,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 +5824,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 +5901,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 +5919,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 +5929,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 +5955,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 +5970,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 +5979,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 +5994,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 +6031,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 +6062,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 +6077,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 +6101,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 +6109,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 +6129,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 +6179,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 +6210,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 +6218,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 +6249,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 +6272,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 +6281,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 +6289,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 +6307,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 +6324,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 +6332,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 +6364,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 +6390,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 +6404,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 +6428,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 +6492,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 +6549,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 +6557,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 +6580,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 +6598,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 +6613,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 +6635,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 +6653,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 +6661,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 +6676,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 +6690,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 +6699,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 +6709,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 +6721,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 +6744,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 +6753,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 +6777,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 +6791,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 +6805,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 +6822,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 +6837,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 +6915,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 +6980,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 +7006,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 +7015,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 +7065,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 +7113,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 +7158,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 +7195,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 +7225,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 +7234,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 +7257,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 +7301,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 +7379,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 +7448,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 +7469,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 +7509,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 +7563,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 +7608,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 +7678,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 +7719,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 +7790,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 +7816,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 +7824,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 +7866,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 +7875,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 +7897,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 +7925,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 +7942,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 +7968,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 +7986,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 +8021,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 +8090,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 +8126,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 +8166,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 +8283,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 +8326,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 +8360,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 +8370,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 +8417,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 +8483,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 +8500,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 +8538,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 +8570,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 +8610,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 +8642,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 +8726,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 +8745,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 +8762,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 +8781,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 +8884,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 +8944,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 +8961,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 +8994,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 +9027,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 +9072,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 +9120,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 +9157,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 +9200,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 +9221,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 +9237,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 +9273,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 +9287,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 +9320,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 +9343,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 +9353,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 +9368,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 +9435,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 +9474,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 +9508,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 +9523,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 +9565,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 +9609,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 +9654,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 +9681,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 +9690,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 +9720,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 +9740,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 +9749,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 +9760,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 +9769,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 +9782,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 +9819,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 +9885,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 +9935,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 +9964,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 +10030,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 +10040,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 +10077,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 +10118,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 +10240,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 +10257,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 +10464,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 +10475,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 +10511,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 +10553,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 +10561,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 +10580,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 +10592,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 +10613,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 +10639,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 +10678,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 +10693,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 +10763,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 +10773,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 +10894,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 +10914,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 +10973,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 +11003,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 +11036,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 +11156,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 +11191,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 +11240,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 +11269,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 +11282,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 +11290,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 +11322,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 +11330,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 +11339,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 +11373,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 +11392,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 +11491,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 +11546,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 +11565,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 +11595,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 +11632,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 +11738,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 +11752,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 "" @@ -11839,8 +11833,8 @@ msgstr "" #: text/chapter3.md:24 #, 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 "" @@ -11887,8 +11881,8 @@ msgstr "" #: text/chapter3.md:37 #, 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:" @@ -11914,7 +11908,7 @@ msgstr "" #: text/chapter3.md:52 #, 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 "" @@ -11976,9 +11970,8 @@ msgstr "" #: text/chapter3.md:81 #, 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 @@ -12006,9 +11999,9 @@ msgstr "" #: text/chapter3.md:94 #, 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 @@ -12071,11 +12064,11 @@ msgstr "" #: text/chapter3.md:124 #, 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) @@ -12131,7 +12124,7 @@ msgstr "" #, 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 " +"quantified type_. It means we can substitute any types for `a`, `b`, and " "`c`, and `flip` will work with those types." msgstr "" @@ -12139,8 +12132,8 @@ msgstr "" #: 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 " +"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 "" @@ -12155,8 +12148,8 @@ msgstr "" #, 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:" +"type – it happens automatically. For example, we can use `flip` as if it had " +"this type already:" msgstr "" #. type: Fenced code block (text) @@ -12172,11 +12165,11 @@ msgstr "" #: 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:" +"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 "" #. type: Fenced code block (text) @@ -12215,7 +12208,7 @@ msgstr "" #. type: Plain text #: text/chapter3.md:179 #, 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) @@ -12229,7 +12222,7 @@ msgstr "" #. type: Plain text #: text/chapter3.md:186 #, markdown-text -msgid "But this is not valid code:" +msgid "But this is not a valid code:" msgstr "" #. type: Fenced code block (haskell) @@ -12270,7 +12263,7 @@ msgstr "" #. type: Plain text #: text/chapter3.md:204 #, markdown-text -msgid "but this is not:" +msgid "But this is not:" msgstr "" #. type: Fenced code block (text) @@ -12342,11 +12335,11 @@ msgstr "" #: text/chapter3.md:234 #, 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) @@ -12365,7 +12358,7 @@ msgstr "" #: text/chapter3.md:242 #, 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 "" @@ -12379,7 +12372,7 @@ msgstr "" #: text/chapter3.md:248 #, 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 "" @@ -12403,8 +12396,8 @@ msgstr "" #, 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 "" @@ -12513,7 +12506,7 @@ msgstr "" #: text/chapter3.md:294 #, 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 "" @@ -12648,7 +12641,7 @@ msgstr "" #, 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) @@ -12678,7 +12671,7 @@ msgstr "" #, 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 "" @@ -12687,9 +12680,9 @@ msgstr "" #, 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 "" @@ -12718,7 +12711,7 @@ msgstr "" #: text/chapter3.md:378 #, 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 "" @@ -12766,9 +12759,9 @@ msgstr "" #: text/chapter3.md:398 #, 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 ## @@ -12782,8 +12775,8 @@ msgstr "" #, 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_." msgstr "" #. type: Plain text @@ -12804,7 +12797,7 @@ msgstr "" #: text/chapter3.md:410 #, markdown-text msgid "" -"That is, `insertEntry` is a function which returns a function! It takes a " +"That is, `insertEntry` is a function that 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`." msgstr "" @@ -12813,8 +12806,8 @@ msgstr "" #: text/chapter3.md:412 #, 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) @@ -12846,7 +12839,7 @@ msgstr "" #: text/chapter3.md:427 #, 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 "" @@ -12862,9 +12855,9 @@ msgstr "" #: text/chapter3.md:434 #, 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 @@ -12872,8 +12865,8 @@ msgstr "" #, 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 @@ -12907,8 +12900,8 @@ 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) @@ -12935,9 +12928,9 @@ msgstr "" #: text/chapter3.md:460 #, 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 @@ -12945,8 +12938,8 @@ msgstr "" #, 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 "" @@ -13034,16 +13027,16 @@ 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 #, 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 @@ -13051,7 +13044,7 @@ msgstr "" #, 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 "" @@ -13082,16 +13075,16 @@ msgstr "" #, 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 #, 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 " @@ -13120,7 +13113,7 @@ msgstr "" #, 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 @@ -13154,8 +13147,8 @@ msgstr "" #: text/chapter3.md:541 #, 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 "" @@ -13195,7 +13188,7 @@ msgstr "" #: text/chapter3.md:556 #, 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 "" @@ -13216,7 +13209,7 @@ msgstr "" #: text/chapter3.md:560 #, 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 "" @@ -13231,9 +13224,9 @@ msgstr "" #: text/chapter3.md:564 #, 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 "" @@ -13251,9 +13244,9 @@ msgid "" "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) @@ -13266,17 +13259,17 @@ msgstr "" #: text/chapter3.md:576 #, 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 #, 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) @@ -13291,7 +13284,7 @@ msgstr "" #: text/chapter3.md:585 #, 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 "" @@ -13372,7 +13365,7 @@ msgstr "" #: text/chapter3.md:618 #, 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 "" @@ -13416,7 +13409,7 @@ msgstr "" #: text/chapter3.md:634 #, 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 "" @@ -13622,10 +13615,10 @@ msgstr "" #: text/chapter3.md:713 #, 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. ' @@ -13662,7 +13655,7 @@ msgstr "" #: text/chapter3.md:721 #, 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." @@ -13677,60 +13670,60 @@ 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 #, 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 #, 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 #, 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 #, 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 #, 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 #, markdown-text -msgid "Structuring code neatly using `where` expressions." +msgid "Structure code neatly using `where` expressions." msgstr "" #. type: Bullet: '- ' #: text/chapter3.md:733 #, 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 #, 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 @@ -13742,7 +13735,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 +13752,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 +13762,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 +13859,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 +13887,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 +13938,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 +13947,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 +13974,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 +13991,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 +14025,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 +14065,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) @@ -14141,7 +14133,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) @@ -14340,10 +14332,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 @@ -14413,8 +14405,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 +14543,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 +14568,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 +14585,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 +14593,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 +14626,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) @@ -14731,8 +14722,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 +14743,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 +14752,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 +14774,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 +14790,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 "" @@ -14827,9 +14818,9 @@ msgstr "" #: 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 assume that PSCi has given the following (more specific) " +"answer:" msgstr "" #. type: Fenced code block (text) @@ -14847,8 +14838,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 +14861,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 +14893,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 +14926,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 +14945,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 +14978,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 +15042,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 +15056,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 +15102,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 +15113,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 +15135,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 +15215,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 +15253,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 +15311,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 +15326,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 +15344,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 +15363,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 +15402,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 +15423,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 +15471,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 +15496,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 +15506,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 +15539,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 +15578,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 +15601,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 +15616,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 +15629,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 +15670,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 +15711,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 +15749,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 +15773,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 +15792,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 +15854,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 +15869,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 +15897,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 +15915,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 +15930,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 "" @@ -16000,11 +15985,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 +16028,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 +16043,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 +16079,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 +16094,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 +16145,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 +16160,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 +16169,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 +16186,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 +16197,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 +16227,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 +16242,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 +16269,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 +16286,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 +16309,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 +16363,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 +16375,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 +16405,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 +16452,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 +16485,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 +16497,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 +16533,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 +16637,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 +16785,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 +16800,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 +16858,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 +16999,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 +17007,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 +17031,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 +17040,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 +17099,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 +17186,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 +17245,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 +17293,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 +17397,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 +17412,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 +17444,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 +17473,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 +17523,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 +17549,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 +17596,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 +17634,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 +17710,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 +17721,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 +17747,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 +17756,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 +17765,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 +17866,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 +17994,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 "" @@ -18117,10 +18100,9 @@ msgstr "" #: 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 +18140,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 +18157,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 +18173,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 +18181,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:419 +#: text/chapter6.md:418 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18209,16 +18191,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 +18208,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 +18232,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 +18248,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 +18267,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 +18276,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:448 +#: text/chapter6.md:447 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18305,15 +18287,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 +18303,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 +18344,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 +18362,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 +18371,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 +18394,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 +18402,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 +18442,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 +18451,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 +18459,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 +18473,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 +18482,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 +18499,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 +18511,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,7 +18519,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter6.md:542 +#: text/chapter6.md:541 #, no-wrap msgid "" "> :type genericTail\n" @@ -18548,41 +18530,41 @@ msgid "" 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 +18573,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 +18582,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 +18593,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 +18601,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 +18609,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 +18618,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 +18633,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 +18644,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 +18659,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 +18669,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 +18732,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 +18762,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 +18777,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:632 +#: text/chapter6.md:631 #, markdown-text, no-wrap msgid "" " {{#include " @@ -18803,7 +18785,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:635 +#: text/chapter6.md:634 #, markdown-text, no-wrap msgid "" " {{#include " @@ -18812,13 +18794,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 +18811,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 +18846,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 +18856,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 +18870,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 +18878,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:665 +#: text/chapter6.md:664 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -18905,7 +18887,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 +18898,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 +18907,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 +18921,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 +18951,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 +18981,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 +19001,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 +19050,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 +19064,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 +19080,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 +19095,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 +19126,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 +19134,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 +19142,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 +19161,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:751 +#: text/chapter6.md:750 #, markdown-text, no-wrap msgid "" " ```haskell\n" @@ -19187,7 +19169,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter6.md:754 +#: text/chapter6.md:753 #, markdown-text, no-wrap msgid "" " {{#include " @@ -19196,7 +19178,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 +19189,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 +19220,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 +19242,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 +19285,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 +19307,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 +19378,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 "" @@ -19497,7 +19478,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 +19564,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 +19622,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 +19659,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 +19730,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 +19758,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 +19776,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 +19840,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 +19863,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 +19904,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 +19978,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 +20007,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 +20039,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 +20061,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 +20164,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 +20175,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 +20183,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 +20191,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 +20212,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 +20222,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 +20241,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 +20254,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 +20330,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 +20347,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 +20364,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 +20425,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 +20559,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 +20600,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 +20618,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 +20653,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 +20708,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 +20751,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 +20785,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 +20826,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 +20834,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 +20862,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 +20870,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 +20889,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 +20902,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 +20965,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 +20985,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 +21018,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 +21033,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 +21041,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 +21060,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 +21087,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 +21111,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 +21162,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 +21219,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 +21248,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 +21256,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 +21278,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 +21330,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 +21385,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 +21454,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 +21575,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 +21592,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 +21634,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 +21645,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 +21677,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 +21687,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 +21750,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 +21793,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 +21844,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 +21866,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 +21897,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 +21945,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 +22001,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 +22032,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 +22049,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 +22131,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 +22150,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 +22169,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 +22199,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 +22240,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 +22248,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 +22262,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 +22277,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 +22285,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 +22305,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 +22324,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 +22372,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 +22392,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 +22400,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 +22413,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 +22421,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 +22446,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 +22456,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 +22478,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 +22486,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 +22499,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 +22528,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:528 +#: text/chapter8.md:529 #, no-wrap msgid "" "import Prelude\n" @@ -22564,25 +22552,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 +22578,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 +22593,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 +22611,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 +22639,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 +22647,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 +22667,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 +22705,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 +22751,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 +22769,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 +22780,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 +22790,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 +22804,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 +22838,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 +22880,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 +22898,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 +22908,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 +22928,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 +22936,7 @@ msgid "" msgstr "" #. type: Fenced code block (shell) -#: text/chapter8.md:702 +#: text/chapter8.md:703 #, no-wrap msgid "" "$ npm install\n" @@ -22958,7 +22945,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 +22955,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 +22970,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 +23165,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 +23189,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 +23219,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 +23234,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:823 +#: text/chapter8.md:824 #, no-wrap msgid "" "useState ::\n" @@ -23258,7 +23244,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 +23253,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 +23267,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 +23276,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 +23300,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 +23321,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 +23333,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 +23341,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 +23386,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 +23412,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 +23420,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 +23429,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 +23443,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 +23460,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 +23474,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 +23488,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 +23496,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 +23504,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 +23514,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 +23537,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 +23552,7 @@ msgid "" msgstr "" #. type: Fenced code block (hs) -#: text/chapter8.md:949 +#: text/chapter8.md:950 #, no-wrap msgid "" "onChange:\n" @@ -23579,7 +23565,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 +23573,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 +23593,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 +23611,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 +23619,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 +23646,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 +23668,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 +23682,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 +23698,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 +23728,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 +23745,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 +23766,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 +23805,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 +23863,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 +23914,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 +23924,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 +23995,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 +24003,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 +24026,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 +24062,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 +24100,7 @@ msgid "" msgstr "" #. type: Fenced code block (shell) -#: text/chapter9.md:116 +#: text/chapter9.md:117 #, no-wrap msgid "" "$ spago repl\n" @@ -24130,7 +24121,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 +24129,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 +24145,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 +24166,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 +24180,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 +24207,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 +24228,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 +24249,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 +24260,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 +24283,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 +24295,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 +24313,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 +24321,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 +24338,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 +24366,37 @@ 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 "" diff --git a/translation/ja.po b/translation/ja.po index 8774a4a8..ecf0debb 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-07-10 21:30+0900\n" +"PO-Revision-Date: 2023-07-11 19:41+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -346,7 +346,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,39 +436,35 @@ 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" -"また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに" -"重要な、高速で理解しやすいコードを生成します。\n" -"PureScriptを一言で言えば、純粋関数型プログラミングの理論的な強力さと、" -"JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを" -"狙った言語だということを理解して頂けたらと思います。" +"PureScriptはこうした課題への対処を目指すプログラミング言語です。\n" +"PureScriptは軽量な構文を備えていますが、この構文によりとても表現力豊かでありながら分かりやすく読みやすいコードが書けるのです。\n" +"強力な抽象化を支援する豊かな型システムも採用しています。\n" +"また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに重要な、高速で理解しやすいコードを生成します。\n" +"概してPureScriptとは、純粋関数型プログラミングの理論的な強力さと、JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語だということを理解して頂けたらと思います。" #. type: Title ## #: text/chapter1.md:41 @@ -481,44 +477,38 @@ msgstr "型と型推論" 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 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の型はMLやHaskellのような言語に影響を受けています。\n" -"開発者がプログラムについての強い主張を表明できるので、PureScriptの型は表現力" -"豊かなのです。\n" -"最も重要なのは、PureScriptの型システムは*型推論*に対応していることです。\n" -"型推論があれば他の言語より遥かに少ない型注釈で済み、型システムを厄介者ではな" -"く*道具*にしてくれます。\n" -"簡単な例を示すと、次のコードは*数*を定義していますが、それが `Number`型だとい" -"う注釈はコードのどこにもありません。" +"多くの点で、PureScriptの型とこれまでJavaやC#のような他の言語で見てきたであろう型が異なっていることにも、注意することが大切です。\n" +"大まかに言えばPureScriptの型はJavaやC#と同じ目的を持っているものの、PureScriptの型はMLやHaskellのような言語に影響を受けています。\n" +"PureScriptの型は表現力豊かであり、開発者はプログラムについての強い主張を表明できます。\n" +"最も重要なのはPureScriptの型システムが*型推論*に対応していることです。\n" +"型推論があれば他の言語より明示的な型注釈が遥かに少なく済み、型システムを厄介者ではなく*道具*にしてくれます。\n" +"単純な一例として、次のコードは*数*を定義していますが、`Number`型への言及はコードのどこにもありません。" #. type: Fenced code block (haskell) #: text/chapter1.md:47 @@ -536,12 +526,11 @@ msgstr "" #: text/chapter1.md:54 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 @@ -586,13 +575,12 @@ msgstr "" 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 @@ -603,14 +591,12 @@ msgstr "多言語Webプログラミング" #. type: Plain text #: text/chapter1.md:69 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 @@ -633,13 +619,11 @@ msgstr "" 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の残りの部分" -"を記述するのに他の言語を使用するという方法もあります。" +"しかし、PureScriptの強みの1つは、JavaScriptを対象とする他の言語との相互運用性にあります。\n" +"アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分を記述するのに1つ以上の他の言語を使用するという方法もあります。" #. type: Plain text #: text/chapter1.md:75 @@ -706,14 +690,13 @@ msgstr "" #. type: Plain text #: text/chapter1.md:87 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 @@ -748,33 +731,26 @@ msgstr "" 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 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 " "apply ideas from one language in the other, although many of the concepts " "presented here will have some interpretation in Haskell." msgstr "" -"PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通" -"じている読者はこの本の中で提示された概念や構文の多くに見覚えがあるでしょ" -"う。\n" -"しかし、読者はPureScriptとHaskellの間には幾らか重要な違いがあることも理解して" -"おかなければなりません。\n" -"ここで紹介する概念の多くはHaskellでも同じように解釈できるとはいえ、どちらかの" -"言語での考え方を他方の言語でそのまま応用しようとすることは、必ずしも適切では" -"ありません。" +"PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通じている読者は本書で提示された概念や構文の多くに見覚えがあるでしょう。\n" +"しかし、PureScriptとHaskellの間には数多くの重要な違いがあることも理解しておくと良いでしょう。\n" +"ここで紹介する概念の多くはHaskellでも同じように解釈できるとはいえ、どちらかの言語での考え方を他方の言語でそのまま応用しようとすることは、必ずしも適切ではありません。" #. type: Title ## #: text/chapter1.md:99 @@ -785,7 +761,7 @@ msgstr "本書の読み進めかた" #. type: Plain text #: text/chapter1.md:102 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 +770,16 @@ 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" -"関数型プログラミングの考え方に充分通じた読者(特にMLやHaskellのような強く型付" -"けされた言語での経験を持つ読者)なら、本書の前半の章を読まなくても、後半の章" -"のコードの大まかな理解を得ることが恐らく可能でしょう。" +"本書のほとんどの章が各章毎に完結しています。\n" +"しかし、関数型プログラミングの経験がほとんどない初心者の方は、各章を順番に進めていくのが賢明です。\n" +"最初の数章は本書の後半の内容を理解するのに必要な下地作りです。\n" +"関数型プログラミングの考え方に充分通じた読者(特にMLやHaskellのような強く型付けされた言語での経験を持つ読者)なら、本書の前半の章を読まなくても、後半の章のコードの大まかな理解を得ることが恐らく可能でしょう。" #. type: Plain text #: text/chapter1.md:104 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,18 +787,15 @@ 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 "コード例は次のように等幅フォントで示されています。" +msgid "Code samples will appear in a monospaced font as follows:" +msgstr "コード例は次のように等幅フォントで示されます。" #. type: Fenced code block (haskell) #: text/chapter1.md:107 @@ -860,12 +830,12 @@ msgstr "$ spago build\n" #: text/chapter1.md:122 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 @@ -889,12 +859,12 @@ msgstr "" #. type: Plain text #: text/chapter1.md:131 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 @@ -903,13 +873,12 @@ msgid "" "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 @@ -931,23 +900,17 @@ msgstr "" 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のDiscordサーバ](https://discord.gg/vKn9up84bp)は抱えている問題についてチャットするのに良い場所です。\n" +"こちらのサーバはPureScriptについてのチャット専用です。" #. type: Bullet: '- ' #: text/chapter1.md:146 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." -msgstr "" -"[PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくあ" -"る問題への解決策を探すのに良い場所です。メッセージ履歴が約2週間しか保たない" -"Slackとは違い、ここで質問した内容は将来の読者の助けとして使えるでしょう。" +"another good place to search for solutions to common problems." +msgstr "[PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくある問題への解決策を探すのに良い場所です。" #. type: Bullet: '- ' #: text/chapter1.md:146 @@ -989,7 +952,7 @@ msgstr "" #: text/chapter1.md:146 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/" @@ -1000,32 +963,29 @@ msgstr "" #: text/chapter1.md:146 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 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 msgid "" "If you prefer to learn by reading examples, the `purescript`, `purescript-" -"node` and `purescript-contrib` GitHub organizations contain plenty of " +"node`, and `purescript-contrib` GitHub organizations contain plenty of " "examples of PureScript code." -msgstr "" -"もし例を読んで学ぶ方が好きでしたら、GitHubの `purescript`組織、`purescript-" -"node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。" +msgstr "もし例を読んで学ぶ方が好きでしたら、GitHubの`purescript`組織、`purescript-node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。" #. type: Title ## #: text/chapter1.md:149 @@ -1038,15 +998,13 @@ msgstr "著者について" 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" -"それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そし" -"てPureScript)で業務に携わってきました。" +"私はPureScriptコンパイラの最初の開発者です。\n" +"カリフォルニア州ロサンゼルスを拠点にしており、8ビットパーソナルコンピュータであるAmstrad CPC上のBASICでまだ幼い時にプログラミングを始めました。\n" +"それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そしてPureScript)で専門的に業務に携わってきました。" #. type: Plain text #: text/chapter1.md:154 @@ -1068,19 +1026,15 @@ 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 "" -"JavaScriptでの経験をもとに、私はPureScriptコンパイラの開発を始めることにしま" -"した。\n" -"気が付くとHaskellのような言語から取り上げた関数型プログラミングの手法を使って" -"いましたが、それを応用するためのもっと理に適った環境を求めていました。\n" -"そのとき検討した案のなかには、Haskellからその意味論を維持しながらJavaScriptへ" -"とコンパイルするいろいろな試み(Fay、Haste、GHCJS)もありました。\n" -"しかし私が興味を持っていたのはこの問題への別の切り口からのアプローチ、すなわ" -"ちHaskellのような言語の構文と型システムを楽しみながらJavaScriptの意味論も維持" -"するということが、どのようにすれば可能になるのかでした。" +"JavaScriptでの経験をもとに、私はPureScriptコンパイラの開発を始めることにしました。\n" +"気が付くとHaskellのような言語から取り上げた関数型プログラミングの手法を使っていましたが、それを応用するためのもっと理に適った環境を求めていました。\n" +"そのとき検討した案のなかには、Haskellからその意味論を維持しながらJavaScriptへとコンパイルするいろいろな試み(Fay、Haste、GHCJS)もありました。\n" +"しかし私が興味を持っていたのは、この問題へ別の切り口からアプローチすると、どの程度うまくいくのかということでした。\n" +"そのアプローチとは、JavaScriptの意味論を維持しつつ、Haskellのような言語の構文と型システムを楽しむことなのです。" #. type: Plain text #: text/chapter1.md:158 @@ -1102,24 +1056,20 @@ msgstr "謝辞" 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 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/)." -msgstr "" -"この本の表紙に表示されたPureScriptのロゴはGareth Hughesによって作成されたもの" -"で、[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/licenses/by/4.0/)の条件の下で再利用させて頂いています 。" #. type: Plain text #: text/chapter1.md:165 @@ -1147,9 +1097,14 @@ msgstr "この章の目標" #. type: Plain text #: text/chapter10.md:6 +#, fuzzy +#| msgid "" +#| "This chapter will introduce PureScript's _foreign function interface_ (or " +#| "_FFI_), which enables communication from PureScript code to JavaScript " +#| "code, and vice versa. We will cover how to:" 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; " @@ -1202,11 +1157,17 @@ msgstr "" #. 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:" +#, fuzzy +#| 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:" +msgid "" +"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" "ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本の" @@ -1233,9 +1194,14 @@ msgstr "プロジェクトの準備" #. type: Plain text #: text/chapter10.md:24 +#, fuzzy +#| 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 " +#| "source files from those chapters." 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章の続きになります。そうし" @@ -1281,13 +1247,22 @@ msgstr "免責事項" #. type: Plain text #: text/chapter10.md:34 +#, fuzzy +#| 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." 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" @@ -1300,10 +1275,17 @@ msgstr "" #. type: Plain text #: text/chapter10.md:36 +#, fuzzy +#| 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 of foreign code. Code in the standard libraries tends to favor " +#| "the latter approach." 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 "" @@ -1376,8 +1358,9 @@ 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" +#, fuzzy, 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" +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" #. type: Plain text @@ -1397,9 +1380,17 @@ msgstr "{{#include ../exercises/chapter10/test/URI.purs}}\n" #. type: Plain text #: text/chapter10.md:62 +#, fuzzy +#| 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 " +#| "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 `_encodeURIComponent`:" 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 " @@ -1541,9 +1532,14 @@ msgstr "{{#include ../exercises/chapter10/test/Examples.purs:diagonal}}\n" #. type: Plain text #: text/chapter10.md:114 +#, fuzzy +#| 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 returns a `Number`." 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" @@ -1670,9 +1666,13 @@ msgstr "" #. type: Plain text #: text/chapter10.md:166 +#, fuzzy +#| msgid "" +#| "We can then call it with `runFn2` which takes the uncurried function then " +#| "the arguments." 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 "カリー化されていない関数と引数を取る`runFn2`で呼び出すことができます。" #. type: Fenced code block (text) @@ -1710,10 +1710,17 @@ msgstr "カリー化されていない関数についての補足" #. type: Plain text #: text/chapter10.md:181 -msgid "" -"PureScript's curried functions has certain advantages. It allows us to " +#, fuzzy +#| msgid "" +#| "PureScript's curried functions has 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 " +#| "code, it is sometimes necessary to define uncurried JavaScript functions " +#| "which accept multiple arguments." +msgid "" +"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 "" @@ -1792,8 +1799,12 @@ msgstr "{{#include ../exercises/chapter10/test/Examples.purs:curried_add}}\n" #. type: Plain text #: text/chapter10.md:211 +#, fuzzy +#| msgid "" +#| "and the resulting generated code, which is less compact due to the nested " +#| "functions:" 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" @@ -1827,8 +1838,15 @@ 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 " +#, fuzzy +#| msgid "" +#| "The arrow function syntax we saw earlier is an ES6 feature, and so it 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 browser." +msgid "" +"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 " @@ -1841,11 +1859,16 @@ msgstr "" #. type: Plain text #: text/chapter10.md:227 +#, fuzzy +#| 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." 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" @@ -1854,8 +1877,14 @@ msgstr "" #. type: Plain text #: text/chapter10.md:229 -msgid "" -"You may still use arrow functions in your own FFI code, but then should " +#, fuzzy +#| msgid "" +#| "You may still use arrow functions in your own FFI code, but then 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." +msgid "" +"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 "" @@ -1907,11 +1936,11 @@ 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 @@ -1920,10 +1949,10 @@ msgstr "本書の残りの例では入れ子の関数の代わりに矢印関数 #: 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 "演習" @@ -1986,12 +2015,18 @@ msgstr "" #. type: Plain text #: text/chapter10.md:266 +#, fuzzy +#| 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." 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の関数の呼び出し方を示します。前にありましたが、" @@ -2046,11 +2081,17 @@ msgstr "" #. type: Plain text #: text/chapter10.md:292 +#, fuzzy +#| 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:" 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" @@ -2111,12 +2152,19 @@ msgstr "" #. type: Plain text #: text/chapter10.md:320 +#, fuzzy +#| 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." 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のコードに型検査を適用できないからです。この型安全" @@ -2296,44 +2344,62 @@ msgstr "forall a. (forall x. x -> Maybe x) -> (forall x. Maybe x) -> Array a -> #. type: Plain text #: text/chapter10.md:387 -msgid "and not:" +#, fuzzy +#| 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" +#, fuzzy, 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 "forall a. ( a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" #. type: Plain text -#: text/chapter10.md:394 +#: text/chapter10.md:393 +#, fuzzy +#| 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:" 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 -#, 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" +msgid "Which returns `Just 1000` for any array input." +msgstr "これは如何なる配列の入力に対しても`Just 1000`を返します。" + +#. type: Plain text +#: text/chapter10.md:403 +#, fuzzy, 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" +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 "" "これはいかなる配列についても`Just 1000`を返します。\n" "この脆弱性は`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,17 +2407,23 @@ 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 +#, fuzzy +#| 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`." 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" "型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する" @@ -2359,7 +2431,7 @@ msgstr "" "この型を`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 +2440,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 +2457,14 @@ msgstr "" "言い換えれば`Undefined`は型構築子です。\n" #. type: Plain text -#: text/chapter10.md:418 -msgid "We can now simply reuse our original definition for `head`:" +#: text/chapter10.md:420 +#, fuzzy +#| msgid "We can now simply reuse our original definition for `head`:" +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,29 +2474,38 @@ 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 +#, fuzzy +#| msgid "" +#| "The body of the `undefinedHead` function returns `arr[0]` which may be " +#| "`undefined`, and the type signature correctly reflects that fact." 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 +#, fuzzy +#| msgid "" +#| "This function has the correct runtime representation for its type, but is " +#| "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!" 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 "" @@ -2432,25 +2515,25 @@ msgstr "" "別の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 +2543,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 +2552,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,11 +2562,18 @@ msgstr "" "isEmpty = isUndefined <<< undefinedHead\n" #. type: Plain text -#: text/chapter10.md:455 +#: text/chapter10.md:457 +#, fuzzy +#| 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 possible, and application logic moved into PureScript code " +#| "wherever possible." 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" @@ -2492,13 +2582,13 @@ msgstr "" "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 +2601,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 +2633,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 +2642,7 @@ msgstr "" "ます。" #. type: Plain text -#: text/chapter10.md:487 +#: text/chapter10.md:489 #, no-wrap msgid "" " ```hs\n" @@ -2572,7 +2662,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 +2671,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 +2680,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 +2700,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 +2708,24 @@ 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 -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." +#: text/chapter10.md:506 +#, fuzzy +#| 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." +msgid "" +"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 +2733,20 @@ msgstr "" "ここでは型クラスのメンバー関数をFFI越しに渡す方法を探ります。" #. type: Plain text -#: text/chapter10.md:506 +#: text/chapter10.md:508 +#, fuzzy +#| msgid "" +#| "We start with writing a foreign JavaScript function which expects the " +#| "appropriate instance of `show` to match the type of `x`." 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 +2756,25 @@ 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 +#, fuzzy +#| 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 "そして`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 +2784,14 @@ msgstr "" "bold x = boldImpl show x\n" #. type: Plain text -#: text/chapter10.md:526 -msgid "Alternatively in point-free form:" +#: text/chapter10.md:528 +#, fuzzy +#| 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" @@ -2697,12 +2801,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 +2824,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 +2833,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 +2853,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 +2867,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 +2885,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 +2903,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 +2913,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 +2922,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 +2936,20 @@ msgstr "" "yell = yellImpl show\n" #. type: Plain text -#: text/chapter10.md:590 +#: text/chapter10.md:592 +#, fuzzy +#| 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." 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 +2969,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 +2982,20 @@ msgstr "" "ことができます。" #. type: Plain text -#: text/chapter10.md:604 +#: text/chapter10.md:606 +#, fuzzy +#| 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. 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 wouldn't find that in the existing JavaScript " +#| "ecosystem." 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 +3005,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 +3014,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 +3030,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 +3056,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 +3076,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 +3087,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 +3110,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 +3129,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,11 +3171,16 @@ msgstr "" "done waiting\n" #. type: Plain text -#: text/chapter10.md:676 +#: text/chapter10.md:678 +#, fuzzy +#| 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." 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" @@ -3067,7 +3188,7 @@ msgstr "" "り予測に近い挙動をします。" #. 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 +3199,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 +3219,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 +3240,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 +3272,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,17 +3281,23 @@ msgstr "" "もし何か良い演習の考えがあればご提案ください。" #. type: Title ## -#: text/chapter10.md:718 +#: text/chapter10.md:720 #, no-wrap msgid "JSON" msgstr "JSON" #. type: Plain text -#: text/chapter10.md:721 -msgid "" -"There are many reasons to use JSON in an application, for example, it's a " +#: text/chapter10.md:723 +#, fuzzy +#| msgid "" +#| "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 passing structural data over the FFI." +msgid "" +"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" @@ -3179,7 +3306,7 @@ msgstr "" "構造的なデータを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 +3315,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 +3355,20 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:745 +#: text/chapter10.md:747 +#, fuzzy +#| msgid "" +#| "We can use the original type signatures, and the code will still compile, " +#| "despite the fact that the return types are incorrect." 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 +3380,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 +3389,7 @@ msgstr "" "ります。" #. type: Fenced code block (text) -#: text/chapter10.md:754 +#: text/chapter10.md:756 #, no-wrap msgid "" "$ spago repl\n" @@ -3304,7 +3435,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 +3449,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 +3462,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 +3471,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,7 +3485,7 @@ 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`:" @@ -3363,7 +3494,7 @@ msgstr "" "こうなります。" #. 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 +3504,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 +3519,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 +3536,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 +3545,7 @@ msgstr "" "ラーとして表れます。" #. type: Fenced code block (text) -#: text/chapter10.md:809 +#: text/chapter10.md:811 #, no-wrap msgid "" "$ spago repl\n" @@ -3438,12 +3569,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 +3583,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 +3593,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 +3617,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 +3634,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 +3644,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 +3659,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 +3675,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 +3686,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 +3702,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 +3745,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 +3757,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 " @@ -3642,10 +3773,15 @@ msgstr "" "コンパイラが導いてくれます。" #. type: Bullet: '1. ' -#: text/chapter10.md:900 +#: text/chapter10.md:902 +#, fuzzy +#| msgid "" +#| "(Medium) Rewrite the earlier `quadraticRoots` function as " +#| "`quadraticRootsSet` which returns the `Complex` roots as a `Set` via JSON " +#| "(instead of as a `Pair`)." 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`としてくださ" @@ -3654,10 +3790,15 @@ msgstr "" "す。" #. type: Plain text -#: text/chapter10.md:900 -#, no-wrap +#: text/chapter10.md:902 +#, fuzzy, 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" +#| "_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" 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" @@ -3676,7 +3817,7 @@ msgstr "" "1. (普通)以下のデータ型は値が葉にある二分木を表現します。\n" #. type: Plain text -#: text/chapter10.md:906 +#: text/chapter10.md:908 #, no-wrap msgid "" " ```haskell\n" @@ -3692,7 +3833,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 +3848,7 @@ msgstr "" "1. (難しい)以下の`data`型は整数か文字列かによってJSONで異なって表現されます。\n" #. type: Plain text -#: text/chapter10.md:917 +#: text/chapter10.md:919 #, no-wrap msgid "" " ```haskell\n" @@ -3723,7 +3864,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 +3872,21 @@ 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 +#, fuzzy +#| 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 features:" 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 +3894,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 +3903,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,14 +3912,14 @@ 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:" @@ -3782,7 +3928,7 @@ msgstr "" "とから始めていきます。" #. 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 +3937,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 +3949,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 +3961,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 +3970,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 +3986,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 +4021,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 +4030,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 +4052,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 "なおこの段階でコンパイルしようとすると以下のエラーに遭遇します。" #. 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,11 +4069,17 @@ msgstr "" " Data.Argonaut.Encode.Class.EncodeJson PhoneType\n" #. type: Plain text -#: text/chapter10.md:987 +#: text/chapter10.md:989 +#, fuzzy +#| 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 argonaut docs:" 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`インスタンス" @@ -3937,7 +4089,7 @@ msgstr "" "この仕組みについて、より詳しくは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 +4101,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,25 +4111,33 @@ 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 +#, fuzzy +#| 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." 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" @@ -3987,7 +4147,7 @@ msgstr "" "そのためこれらを`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 +4163,15 @@ msgstr "" " decodeJson j\n" #. type: Plain text -#: text/chapter10.md:1013 +#: text/chapter10.md:1015 +#, fuzzy +#| 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 person retrieved from local storage." 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 +4179,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 +4195,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 +4203,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 +4213,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,7 +4232,7 @@ 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`." @@ -4076,7 +4241,7 @@ msgstr "" "の質を向上させます。" #. type: Fenced code block (hs) -#: text/chapter10.md:1040 +#: text/chapter10.md:1042 #, no-wrap msgid "" "processItem :: Json -> Either String Person\n" @@ -4092,13 +4257,20 @@ msgstr "" " lmap (\"Cannot decode Person: \" <> _) $ decodeJson j\n" #. type: Plain text -#: text/chapter10.md:1049 -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." +#: text/chapter10.md:1051 +#, fuzzy +#| 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." +msgid "" +"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ブラウザの開発ツールを開いてローカルストレージ中に保存された" @@ -4108,14 +4280,21 @@ msgstr "" "それぞれのエラーを引き起こせるかどうかやってみてください。" #. type: Plain text -#: text/chapter10.md:1051 +#: text/chapter10.md:1053 +#, fuzzy +#| 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." 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" @@ -4128,13 +4307,13 @@ msgstr "" "例えば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 +4323,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 +4356,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 +4365,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 +4375,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 +4384,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,51 +4393,66 @@ 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/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: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/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 +#, fuzzy +#| 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 using the FFI:" 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を使用して信頼できるコードを書く時に生じる問題について見てきました。" #. 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 +#, fuzzy +#| 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." 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 +#, fuzzy +#| msgid "" +#| "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 these " +#| "libraries put to use to solve real-world problems in a type-safe way." 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 "" @@ -4268,19 +4462,19 @@ msgstr "" "を幾つか見ていきます。" #. 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,13 +4483,22 @@ 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 -#, no-wrap +#: text/chapter10.md:1101 +#, fuzzy, no-wrap +#| msgid "" +#| "module Test where\n" +#| "\n" +#| "gcd :: Int -> Int -> Int\n" +#| "gcd 0 m = m\n" +#| "gcd n 0 = n\n" +#| "gcd n m\n" +#| " | n > m = gcd (n - m) m\n" +#| " | otherwise = gcd (m - n) n\n" msgid "" "module Test where\n" "\n" @@ -4304,7 +4507,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" @@ -4316,7 +4519,7 @@ msgstr "" " | 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 +4535,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 +4547,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,12 +4557,18 @@ msgstr "" "Test.gcd(15)(20);\n" #. type: Plain text -#: text/chapter10.md:1120 -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`." +#: text/chapter10.md:1122 +#, fuzzy +#| 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`." +msgid "" +"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`を使って " @@ -4367,7 +4576,7 @@ msgstr "" "ました。" #. 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,16 +4589,22 @@ 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 +#, fuzzy +#| msgid "" +#| "PureScript aims to preserve names during code generation as much as " +#| "possible. In particular, most identifiers which are neither PureScript " +#| "nor JavaScript keywords can be expected to be preserved, at least for " +#| "names of top-level declarations." 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 "" @@ -4398,7 +4613,7 @@ msgstr "" "JavaScriptのキーワードでなければほとんどの識別子が保存されます。" #. 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 +4623,26 @@ 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 +#, fuzzy +#| msgid "generates the following JavaScript:" +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,22 +4652,29 @@ 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 +#, fuzzy +#| msgid "" +#| "Where compiled PureScript code is intended to be called from JavaScript, " +#| "it 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." 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." @@ -4463,16 +4687,22 @@ msgstr "" "します。" #. 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 +#, fuzzy +#| 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 mean? In PureScript, it means that the type of an " +#| "expression should be compatible with its representation at runtime." 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 "" @@ -4484,7 +4714,7 @@ msgstr "" "す。" #. 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 +4728,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 +4738,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,9 +4755,17 @@ msgstr "" "特に`null`や `undefined`に評価される型`Boolean`なPureScriptの式はありません。" #. type: Plain text -#: text/chapter10.md:1164 -msgid "" -"A similar law holds for expressions of type `Int`, `Number`, and `String` - " +#: text/chapter10.md:1166 +#, fuzzy +#| msgid "" +#| "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`." +msgid "" +"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, " @@ -4541,15 +4779,23 @@ msgstr "" "は実行時に整数に評価されます。" #. type: Plain text -#: text/chapter10.md:1166 +#: text/chapter10.md:1168 +#, fuzzy +#| 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`)." 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つのみで値が観測できないため、実のところ実行時に何" @@ -4561,14 +4807,15 @@ msgstr "" "返します)。" #. 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 -#, 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" +#: text/chapter10.md:1172 +#, fuzzy, 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" @@ -4577,10 +4824,18 @@ msgstr "" "簡単な例としては、 `String -> String`型の式は、 `null`でないJavaScript文字列から `null`でないJavaScript文字列への関数へと評価されます。\n" #. type: Plain text -#: text/chapter10.md:1172 +#: text/chapter10.md:1174 +#, fuzzy +#| msgid "" +#| "As you might expect, PureScript's arrays correspond to JavaScript 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 " +#| "type `a`." 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`." @@ -4593,13 +4848,20 @@ msgstr "" "JavaScript配列へと評価されます。" #. type: Plain text -#: text/chapter10.md:1174 +#: text/chapter10.md:1176 +#, fuzzy +#| 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." 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" @@ -4608,17 +4870,23 @@ msgstr "" "もちろん、レコードのそれぞれのフィールドは、同じ型である必要はありません。" #. 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 +#, fuzzy +#| 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 " +#| "based on those prototypes." 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コンパイラは、代数的データ型の全ての構築子についてそれぞれを関数と" @@ -4627,23 +4895,23 @@ msgstr "" "応しています。" #. 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,7 +4941,7 @@ 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 " @@ -4686,7 +4954,7 @@ msgstr "" "フィールドに、対応するデータを格納します。" #. 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,11 +4970,17 @@ msgstr "" "築子を適用する `create`関数を生成します。" #. type: Plain text -#: text/chapter10.md:1207 +#: text/chapter10.md:1209 +#, fuzzy +#| 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:" 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" @@ -4716,18 +4990,20 @@ 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 "data Two a b = Two a b\n" #. type: Plain text -#: text/chapter10.md:1213 -msgid "generates this JavaScript code:" +#: text/chapter10.md:1215 +#, fuzzy +#| msgid "generates this JavaScript code:" +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,21 +5029,31 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter10.md:1228 +#: text/chapter10.md:1230 +#, fuzzy +#| msgid "" +#| "Here, values of the object type `Two` can be created using the `new` " +#| "keyword, or by using the `Two.create` function." 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`関数を使" "用すると作成できます。" #. type: Plain text -#: text/chapter10.md:1230 +#: text/chapter10.md:1232 +#, fuzzy +#| 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." 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は単一の引数を取る単一の構築子を持つよう制限された代数的データ型である" @@ -4775,35 +5061,43 @@ msgstr "" "この場合、実際のnewtypeの実行時表現は、その引数の型と同じになります。" #. type: Plain text -#: text/chapter10.md:1232 -msgid "For example, this newtype representing telephone numbers:" +#: text/chapter10.md:1234 +#, fuzzy +#| 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 "例えば、電話番号を表す次のようなnewtypeを考えます。" #. 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 +#, fuzzy +#| 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." 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は更なる型安全性のための層を提供しますが、実行時の関数呼び出しのオー" "バーヘッドがないので、ライブラリを設計するのに役に立ちます。" #. 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 +5109,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 +5129,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 +5139,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,17 +5159,25 @@ 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 +#, fuzzy +#| msgid "" +#| "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 argument in its implementation. This additional condition prevents " +#| "problematic implementations such as the following JavaScript function " +#| "from inhabiting a polymorphic type:" 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:" @@ -4889,7 +5191,7 @@ msgstr "" "のある実装を防止します。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1264 +#: text/chapter10.md:1266 #, no-wrap msgid "" "function invalid(a) {\n" @@ -4909,27 +5211,37 @@ msgstr "" "}\n" #. type: Plain text -#: text/chapter10.md:1275 -#, 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" +#: text/chapter10.md:1277 +#, fuzzy, 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" #. type: Plain text -#: text/chapter10.md:1277 -#, 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" +#: text/chapter10.md:1279 +#, fuzzy, 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" +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 "関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけであり、したがって `id`はたしかに `forall a. a -> a`の唯一の実装なのです。\n" #. type: Plain text -#: text/chapter10.md:1279 +#: text/chapter10.md:1281 +#, fuzzy +#| msgid "" +#| "A full discussion of _parametric polymorphism_ and _parametricity_ is " +#| "beyond 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." 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 +5250,24 @@ 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 +#, fuzzy +#| 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 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." 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 +5279,20 @@ msgstr "" "す。" #. type: Plain text -#: text/chapter10.md:1285 +#: text/chapter10.md:1287 +#, fuzzy +#| msgid "" +#| "For example, here is a simple PureScript function with a constrained type " +#| "which uses the `Show` type class:" 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" "関数について考えます。" #. 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 +5302,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 +5323,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 +5335,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 +5344,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 +5356,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 +5377,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,16 +5388,23 @@ 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 +#, fuzzy +#| msgid "" +#| "The `Effect` monad is also defined as a foreign type. Its runtime " +#| "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`." 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`." @@ -5084,7 +5415,7 @@ msgstr "" "この関数はあらゆる副作用を実行し型 `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 +5423,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,27 +5438,33 @@ 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 +#, fuzzy +#| 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 returns it, and the return value matches the runtime " +#| "representation of the `Number` type: it is a non-null JavaScript number." 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 "" @@ -5138,7 +5475,7 @@ msgstr "" "`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 +5485,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,7 +5512,7 @@ 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 " @@ -5185,7 +5522,7 @@ msgstr "" "す。内側の関数はコンソールにメッセージを書き込むという副作用を実行します。" #. 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 +5533,7 @@ msgstr "" "う型でなければならないので、次のように実行できます。" #. type: Fenced code block (javascript) -#: text/chapter10.md:1368 +#: text/chapter10.md:1370 #, no-wrap msgid "" "import { main } from 'Main'\n" @@ -5208,10 +5545,14 @@ msgstr "" "main();\n" #. type: Plain text -#: text/chapter10.md:1374 +#: text/chapter10.md:1376 +#, fuzzy +#| msgid "" +#| "When using `spago bundle-app --to` or `spago run`, this call to `main` is " +#| "generated automatically, whenever the `Main` module is defined." 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`の呼び出しを自動的に生成できます。" @@ -5224,10 +5565,18 @@ msgstr "モナドな冒険" #. type: Plain text #: text/chapter11.md:6 +#, fuzzy +#| 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 console in NodeJS. The various side-effects of the game (logging, " +#| "state, and configuration) will all be provided by a monad transformer " +#| "stack." 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 "" @@ -5266,8 +5615,12 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter11.md:15 +#, fuzzy +#| msgid "" +#| "`optparse`, which provides applicative parsers for processing command " +#| "line arguments" msgid "" -"`optparse`, which provides applicative parsers for processing command line " +"`optparse`, which provides applicative parsers for processing command-line " "arguments" msgstr "" "`optparse` はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" @@ -5285,7 +5638,9 @@ msgstr "プロジェクトを走らせるには`spago run`を使います。" #. type: Plain text #: text/chapter11.md:21 -msgid "By default you will see a usage message:" +#, fuzzy +#| msgid "By default you will see a usage message:" +msgid "By default, you will see a usage message:" msgstr "既定では使い方が表示されます。" #. type: Fenced code block (text) @@ -5315,20 +5670,31 @@ 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 +#, fuzzy +#| 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" +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" +"コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-" +"a`オプション付きで`spago run`を呼び出すか、`spago bundle-app`とすればよいで" +"す。\n" "2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。\n" #. 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 +5704,7 @@ msgstr "" ">\n" #. type: Fenced code block (text) -#: text/chapter11.md:43 +#: text/chapter11.md:44 #, no-wrap msgid "" "$ spago bundle-app \n" @@ -5350,12 +5716,18 @@ msgstr "" ">\n" #. type: Plain text -#: text/chapter11.md:50 +#: text/chapter11.md:51 +#, fuzzy +#| 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." 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" @@ -5363,13 +5735,20 @@ msgstr "" "に、ゲームの状態を出力するのに使えます。" #. type: Plain text -#: text/chapter11.md:52 +#: text/chapter11.md:53 +#, fuzzy +#| 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." 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 "" "ゲームは2次元の碁盤の目の上が舞台で、コマンド `north`、 `south`、`east`、 " "`west`を発行することによってプレイヤーが移動します。\n" @@ -5379,12 +5758,12 @@ msgstr "" "ます。" #. 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 +5823,28 @@ msgstr "" "You win!\n" #. type: Plain text -#: text/chapter11.md:86 +#: text/chapter11.md:87 +#, fuzzy +#| 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." 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`パッケージを使用し" "てこのようなゲームを素早く開発できるようにするライブラリを構築することです。" #. 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 +5853,15 @@ msgstr "" "しょう。" #. type: Plain text -#: text/chapter11.md:92 +#: text/chapter11.md:93 +#, fuzzy +#| 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 " +#| "state provided by the `Effect` monad. `State` provides an alternative." 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,12 +5871,18 @@ msgstr "" "`State`はその代替を提供します。" #. type: Plain text -#: text/chapter11.md:94 +#: text/chapter11.md:95 +#, fuzzy +#| 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` " +#| "monad\", the instance of the `Monad` type class is actually provided for " +#| "the `State s` type constructor, for any type `s`." 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種類の引数を取りま" "す。\n" @@ -5495,12 +5890,12 @@ msgstr "" "ンスタンスが任意の型`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,12 +5911,20 @@ msgstr "" "modify_ :: forall s. (s -> s) -> State s Unit\n" #. type: Plain text -#: text/chapter11.md:106 +#: text/chapter11.md:107 +#, fuzzy +#| 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." 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" @@ -5531,11 +5934,17 @@ msgstr "" "ください。" #. type: Plain text -#: text/chapter11.md:108 +#: text/chapter11.md:109 +#, fuzzy +#| 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 array, with a call to `modify` for each array element:" 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" @@ -5545,7 +5954,7 @@ msgstr "" "それぞれについて `modify`を呼び出すと、これを実現できます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:109 +#: text/chapter11.md:110 #, no-wrap msgid "" "import Data.Foldable (traverse_)\n" @@ -5563,7 +5972,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 +5981,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 +5993,25 @@ msgstr "" "runState :: forall s a. State s a -> s -> Tuple a s\n" #. type: Plain text -#: text/chapter11.md:127 +#: text/chapter11.md:128 +#, fuzzy +#| 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`." 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`型の値として表現された両方を返します。" #. 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 +6020,7 @@ msgstr "" "うに複数の配列内の数字を合計できます。" #. type: Fenced code block (text) -#: text/chapter11.md:130 +#: text/chapter11.md:131 #, no-wrap msgid "" "> :paste\n" @@ -5633,15 +6048,23 @@ 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" -msgstr "" -"1. (普通)括弧からなる文字列について、次の何れかであれば*平衡している*とします。\n" -" 1つは0個以上のより短い平衡した文字列を連結したもので、もう1つはより短い平衡した文字列を一対の括弧で囲んだものです。\n" +#, fuzzy +#| 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" +msgid "" +"(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" #. type: Plain text #: text/chapter11.md:147 @@ -5662,18 +6085,19 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:154 -#, 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" +#: text/chapter11.md:153 +#, fuzzy, 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" #. type: Plain text -#: text/chapter11.md:158 +#: text/chapter11.md:157 #, no-wrap msgid "" " ```text\n" @@ -5685,7 +6109,7 @@ msgstr "" " true\n" #. type: Plain text -#: text/chapter11.md:161 +#: text/chapter11.md:160 #, no-wrap msgid "" " > testParens \"(()(())())\"\n" @@ -5695,7 +6119,7 @@ msgstr "" " true\n" #. type: Plain text -#: text/chapter11.md:164 +#: text/chapter11.md:163 #, no-wrap msgid "" " > testParens \")\"\n" @@ -5705,7 +6129,7 @@ msgstr "" " false\n" #. type: Plain text -#: text/chapter11.md:168 +#: text/chapter11.md:167 #, no-wrap msgid "" " > testParens \"(()()\"\n" @@ -5717,19 +6141,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 +6167,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 +6176,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,7 +6191,7 @@ 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 " @@ -5777,7 +6201,7 @@ msgstr "" "た設定で計算するために使います。" #. 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 +6213,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 +6223,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 +6234,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,7 +6252,7 @@ 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:" @@ -5837,7 +6261,7 @@ 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" @@ -5847,7 +6271,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 +6280,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 +6290,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 +6298,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 +6312,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 +6324,20 @@ msgstr "" "type Doc = Reader Level String\n" #. type: Bullet: ' 1. ' -#: text/chapter11.md:235 +#: text/chapter11.md:234 +#, fuzzy +#| msgid "" +#| "(Easy) Write a function `line` which renders a function at the current " +#| "indentation level. Your function should have the following type:" 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" "関数は以下の型を持つ必要があります。" #. type: Plain text -#: text/chapter11.md:239 +#: text/chapter11.md:238 #, no-wrap msgid "" " ```haskell\n" @@ -5921,7 +6349,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 +6360,7 @@ msgstr "" "1. (普通)`local`関数を使用して次の関数を書いてください。\n" #. type: Plain text -#: text/chapter11.md:246 +#: text/chapter11.md:245 #, no-wrap msgid "" " ```haskell\n" @@ -5944,7 +6372,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 +6382,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 +6394,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 +6404,7 @@ msgstr "" "1. (普通)`runReader`関数を使用して次の関数を書いてください。\n" #. type: Plain text -#: text/chapter11.md:260 +#: text/chapter11.md:259 #, no-wrap msgid "" " ```haskell\n" @@ -5988,19 +6416,20 @@ 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 -#, no-wrap -msgid " You should now be able to use your library to write simple documents, as follows:\n" +#: text/chapter11.md:263 +#, fuzzy, no-wrap +#| msgid " You should now be able to use your library to write simple documents, as follows:\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,29 +6451,40 @@ 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 +#, fuzzy +#| msgid "" +#| "The `Writer` monad provides the ability to accumulate a secondary value " +#| "in addition to the return value of a computation." 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 "" "`Writer`モナドは、計算の返り値に加えて、もう1つの値を累積していく機能を提供し" "ます。" #. type: Plain text -#: text/chapter11.md:281 +#: text/chapter11.md:280 +#, fuzzy +#| 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." 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 "" "よくある使い方としては型 `String`もしくは `Array String`でログを累積していく" "というものなどがありますが、 `Writer`モナドはこれよりもっと一般的なもので" @@ -6054,36 +6494,45 @@ msgstr "" "`Boolean`値の何れかが真であるかどうかを追跡するのに使うことができます。" #. type: Plain text -#: text/chapter11.md:283 +#: text/chapter11.md:282 +#, fuzzy +#| msgid "" +#| "The `Writer` type constructor takes two type arguments: a type `w` which " +#| "should be an instance of the `Monoid` type class, and the return type `a`." 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つの型引数を取ります。" #. 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`アクションは、与えられた値を現在の累積結果に付け加えます。" #. type: Plain text -#: text/chapter11.md:293 +#: text/chapter11.md:292 +#, fuzzy +#| msgid "" +#| "As an example, let's add a log to an existing function by using the " +#| "`Array String` monoid. Consider our previous implementation of the " +#| "_greatest common divisor_ function:" 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 "" @@ -6091,7 +6540,7 @@ msgstr "" "ましょう。 _最大公約数_ 関数の以前の実装を考えてみます。" #. type: Fenced code block (haskell) -#: text/chapter11.md:294 +#: text/chapter11.md:293 #, no-wrap msgid "" "gcd :: Int -> Int -> Int\n" @@ -6109,7 +6558,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 +6567,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 +6581,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 +6589,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 +6609,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 +6618,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,7 +6628,7 @@ 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." @@ -6188,12 +6637,12 @@ msgstr "" "返すのに対して、 `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 +6658,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,10 +6667,15 @@ msgstr "" "うに、上の `sumArray`関数を書き換えてください。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:347 +#: text/chapter11.md:346 +#, fuzzy +#| 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 Collatz sequence starting at `10` is as follows:" 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 * " @@ -6229,7 +6683,7 @@ msgstr "" "例えば`10`で始まるコラッツ数列は次のようになります。" #. type: Plain text -#: text/chapter11.md:351 +#: text/chapter11.md:350 #, no-wrap msgid "" " ```text\n" @@ -6241,35 +6695,41 @@ 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 -#, 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" +#: text/chapter11.md:354 +#, fuzzy, 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" +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" #. 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 +#, fuzzy +#| msgid "" +#| "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." 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" @@ -6277,7 +6737,7 @@ msgstr "" "す。" #. 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,11 +6764,16 @@ msgstr "" "この問題を解決するのが*モナド変換子*です。" #. type: Plain text -#: text/chapter11.md:365 +#: text/chapter11.md:364 +#, fuzzy +#| 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." 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" @@ -6316,18 +6781,23 @@ msgstr "" "制約があります。" #. type: Plain text -#: text/chapter11.md:367 +#: text/chapter11.md:366 +#, fuzzy +#| 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." 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つ取り、独自のいろいろな副作用を追加した別のモナドへと変換し" "ます。" #. 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 +6808,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 +6820,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 +6829,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 +6838,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 +6848,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 +6857,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 +6867,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 +6876,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,31 +6886,48 @@ msgstr "" "Type\n" #. type: Plain text -#: text/chapter11.md:400 +#: text/chapter11.md:399 +#, fuzzy +#| msgid "" +#| "Finally we are left with something of kind `Type`, which means we can try " +#| "to find values of this type." 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: Plain text -#: text/chapter11.md:402 +#: text/chapter11.md:401 +#, fuzzy +#| msgid "" +#| "The monad we have constructed - `StateT String (Either String)` - " +#| "represents computations which can fail with an error, and which can use " +#| "mutable state." 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)`は、エラーで失敗する可能性があ" "り、変更可能な状態を使える計算を表しています。" #. type: Plain text -#: text/chapter11.md:404 +#: text/chapter11.md:403 +#, fuzzy +#| 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:" 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 " @@ -6450,7 +6937,7 @@ msgstr "" "`MonadTrans`型クラスを次のように定義しています。" #. type: Fenced code block (haskell) -#: text/chapter11.md:405 +#: text/chapter11.md:404 #, no-wrap msgid "" "class MonadTrans t where\n" @@ -6460,11 +6947,21 @@ msgstr "" " lift :: forall m a. Monad m => m a -> t m a\n" #. type: Plain text -#: text/chapter11.md:411 +#: text/chapter11.md:410 +#, fuzzy +#| 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 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`." 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` " @@ -6480,16 +6977,20 @@ msgstr "" "`StateT String`と `Either String`を一緒に使うことができることを意味します。" #. type: Plain text -#: text/chapter11.md:413 +#: text/chapter11.md:412 +#, fuzzy +#| msgid "" +#| "For example, the following computation reads the underlying state, and " +#| "then throws an error if the state is the empty string:" 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 +7016,27 @@ msgstr "" " pure (take 1 s)\n" #. type: Plain text -#: text/chapter11.md:428 +#: text/chapter11.md:427 +#, fuzzy +#| 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`)." 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`の最初の文字)を返します。" #. 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,9 +7052,16 @@ msgstr "" "Left \"Empty string\"\n" #. type: Plain text -#: text/chapter11.md:440 +#: text/chapter11.md:439 +#, fuzzy +#| msgid "" +#| "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:" 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 " @@ -6561,7 +7074,7 @@ msgstr "" "例えば、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,14 +7084,21 @@ msgstr "" "(Right (Tuple \"te\" \"st\"))\n" #. type: Plain text -#: text/chapter11.md:447 +#: text/chapter11.md:446 +#, fuzzy +#| 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." 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`ライブラリで採用されている手法で" @@ -6587,24 +7107,28 @@ msgstr "" "成できるのです。" #. 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 +#, fuzzy +#| 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:" 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を提供します。" #. type: Fenced code block (haskell) -#: text/chapter11.md:452 +#: text/chapter11.md:451 #, no-wrap msgid "" "class MonadError e m where\n" @@ -6624,13 +7148,21 @@ 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 +#, fuzzy +#| 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`." 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" @@ -6640,14 +7172,14 @@ msgstr "" "を継続できるようになります。" #. 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 +7189,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 +7198,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,7 +7209,7 @@ 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 " @@ -6688,7 +7220,7 @@ msgstr "" "が、`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 +7244,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 +7259,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,29 +7269,42 @@ msgstr "" "Tuple (Left \"Error!\") [\"Before the error\"]\n" #. type: Plain text -#: text/chapter11.md:493 +#: text/chapter11.md:492 +#, fuzzy +#| msgid "" +#| "Note that only those log messages which were written before the error was " +#| "thrown actually get appended to the log." 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 +#, fuzzy +#| 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." 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" @@ -6771,15 +7316,24 @@ msgstr "" "子の*スタック*を構築できます。" #. type: Plain text -#: text/chapter11.md:499 +#: text/chapter11.md:498 +#, fuzzy +#| 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." 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`モナドになりま" @@ -6790,10 +7344,17 @@ msgstr "" "れぞれ`StateT`と`ReaderT`と`WriterT`で変換することによって実装されています。" #. type: Plain text -#: text/chapter11.md:501 +#: text/chapter11.md:500 +#, fuzzy +#| 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 bottom of the stack. This monad transformer stack will " +#| "provide the side effects of mutable state, accumulating a log, and pure " +#| "errors." 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 "" @@ -6804,7 +7365,7 @@ msgstr "" "を提供します。" #. 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 +7374,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 +7410,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,10 +7419,16 @@ msgstr "" "ることがわかります。" #. type: Plain text -#: text/chapter11.md:525 +#: text/chapter11.md:524 +#, fuzzy +#| 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 " +#| "the `StateT` type constructor, then `runWriterT`, then `runExceptT`. " +#| "Finally, we run the computation in the `Identity` monad by using `unwrap`." 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 "" @@ -6872,7 +7439,7 @@ msgstr "" "最後に `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 +7459,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 +7468,7 @@ msgstr "" "ん。" #. type: Fenced code block (text) -#: text/chapter11.md:538 +#: text/chapter11.md:537 #, no-wrap msgid "" "> runParser split \"\"\n" @@ -6911,15 +7478,24 @@ msgstr "" "(Left [\"Empty string\"])\n" #. type: Plain text -#: text/chapter11.md:544 -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`." +#: text/chapter11.md:543 +#, fuzzy +#| 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`." +msgid "" +"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" @@ -6930,13 +7506,20 @@ msgstr "" "るようになります。" #. type: Plain text -#: text/chapter11.md:546 +#: text/chapter11.md:545 +#, fuzzy +#| 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 " +#| "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." 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つは、複数のモナド変換子の上まで計算を持ち上げるために、 " "`lift`関数を複数回使わなければならないということです。\n" @@ -6946,7 +7529,7 @@ msgstr "" "になるでしょう。" #. 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 +7538,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 +7549,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 +7566,20 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:559 -#, no-wrap -msgid " which matches a string as a prefix of the current state, or fails with an error message.\n" +#: text/chapter11.md:558 +#, fuzzy, no-wrap +#| msgid " which matches a string as a prefix of the current state, or fails with an error message.\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 +7593,21 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter11.md:569 -#, no-wrap +#: text/chapter11.md:568 +#, fuzzy, 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" 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" #. 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,13 +7616,13 @@ 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:" @@ -7044,7 +7631,7 @@ msgstr "" "次のような型が与えられていました。" #. 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 +7643,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 +7652,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 +7664,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,15 +7680,25 @@ msgstr "" "ンスになっており、このクラスには他にも興味深いインスタンスが数多くあります。" #. type: Plain text -#: text/chapter11.md:593 +#: text/chapter11.md:592 +#, fuzzy +#| 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`." 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" @@ -7112,12 +7709,18 @@ msgstr "" "自由に使用できます。" #. type: Plain text -#: text/chapter11.md:595 +#: text/chapter11.md:594 +#, fuzzy +#| 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." 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`では主な変換子それぞれについ" @@ -7125,12 +7728,19 @@ msgstr "" "抽象化できるのです。" #. type: Plain text -#: text/chapter11.md:597 +#: text/chapter11.md:596 +#, fuzzy +#| 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 defined on the monad stack itself:" 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`、 " @@ -7140,16 +7750,22 @@ msgstr "" "`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 +#, fuzzy +#| 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 handling. However, everything is still implemented using pure " +#| "functions and immutable data under the hood." 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 "" @@ -7159,23 +7775,27 @@ msgstr "" "るのです。" #. 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 +#, fuzzy +#| msgid "" +#| "The `control` package defines a number of abstractions for working with " +#| "computations which can fail. One of these is the `Alternative` type class:" 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`型クラスです。" #. 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 +7815,16 @@ msgstr "" "class (Applicative f, Plus f) <= Alternative f\n" #. type: Plain text -#: text/chapter11.md:619 -#, 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" +#: text/chapter11.md:618 +#, fuzzy, 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 +7833,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,15 +7843,20 @@ 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 +#, fuzzy +#| msgid "" +#| "The `many` combinator uses the `Alternative` type class to repeatedly run " +#| "a computation _zero-or-more_ times. The `some` combinator is similar, but " +#| "requires at least the first computation to succeed." 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`型" @@ -7238,7 +7864,7 @@ msgstr "" "くとも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 +7881,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 +7905,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 +7917,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,22 +7935,28 @@ 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 +#, fuzzy +#| 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 which is an instance of `MonadPlus`:" 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 "" "以前本書中で配列内包表記を扱ったとき、不要な結果を除いて絞り込むために使われ" @@ -7333,13 +7965,13 @@ 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 "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 "" @@ -7347,16 +7979,22 @@ msgstr "" "これがどのように役立つかを見るために、大文字だけに適合する `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 +#, fuzzy +#| 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 - " +#| "using `MonadPlus` in this way, we sometimes refer to constructing _monad " +#| "comprehensions_." 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 "" @@ -7366,13 +8004,13 @@ msgstr "" "ばれることがあります。" #. 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,13 +8018,13 @@ 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 " @@ -7397,19 +8035,19 @@ 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 +8065,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,23 +8104,27 @@ msgstr "" " ]))\n" #. type: Plain text -#: text/chapter11.md:715 +#: text/chapter11.md:714 +#, fuzzy 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" -"標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器" -"を、ほんの数行のコードで書くことができました。" +"繰り返しになりますが、これはモナド変換子が齎す再利用性の威力を示しています。\n" +"標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器を、ほんの数行のコードで書くことができました。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 +#, fuzzy +#| 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." 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`関数の呼び出しを取り除いてくださ" "い。\n" @@ -7490,33 +8132,42 @@ msgstr "" "ておきましょう。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 +#, fuzzy +#| 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\"`." 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`を書いてください。" #. type: Bullet: ' 1. ' -#: text/chapter11.md:722 +#: text/chapter11.md:721 +#, fuzzy +#| msgid "" +#| "(Medium) Use the `<|>` operator to write a parser `asOrBs` which " +#| "recognizes strings of the letters `a` or `b` in any order." 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`を書いてください。" #. 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,25 +8179,32 @@ 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 +#, fuzzy +#| 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." 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" @@ -7556,7 +8214,7 @@ msgstr "" "す。" #. 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 +8223,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 +8231,43 @@ 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 +#, fuzzy +#| 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." 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`モ" "ナドが独自のモナド変換子を用いて定義されています。" #. type: Plain text -#: text/chapter11.md:744 +#: text/chapter11.md:743 +#, fuzzy +#| 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." 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`は可変状態" "の型を表しています。" #. 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,17 +8276,22 @@ 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 +#, fuzzy +#| 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." 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" @@ -7627,7 +8299,7 @@ msgstr "" "ます。" #. 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 +8308,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 +8320,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 +8329,24 @@ 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 +#, fuzzy +#| msgid "" +#| "The `GameState` type uses two new data structures: `Map` and `Set`, which " +#| "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 held by the player." 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 " @@ -7680,18 +8360,23 @@ msgstr "" "レイヤーが保有するゲームアイテムの集合です。" #. type: Plain text -#: text/chapter11.md:770 +#: text/chapter11.md:769 +#, fuzzy +#| 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." 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`型クラスの任意の型を" "キーとして使用できます。これは今回のデータ構造のキーが完全に順序付けできるこ" "とを意味します。" #. 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." @@ -7700,7 +8385,7 @@ msgstr "" "いきます。" #. 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,25 +8394,33 @@ 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 +#, fuzzy +#| 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." 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`モナドで定義されている単純なアクションを組み合わせてゲームを構築してい" @@ -7737,7 +8430,7 @@ msgstr "" "ために使っています。" #. 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 " @@ -7748,16 +8441,22 @@ 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 "{{#include ../exercises/chapter11/src/Game.purs:has}}\n" #. type: Plain text -#: text/chapter11.md:790 +#: text/chapter11.md:789 +#, fuzzy +#| 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 in `Data.Set` to test whether the specified `GameItem` appears in " +#| "the `Set` of inventory items." 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 "" @@ -7767,7 +8466,7 @@ msgstr "" "るために`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 " @@ -7781,13 +8480,13 @@ 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 "{{#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,17 +8495,23 @@ 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 +#, fuzzy +#| 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 the `Just` constructor." 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" @@ -7814,7 +8519,7 @@ msgstr "" "`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,30 +8529,39 @@ 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 +#, fuzzy +#| msgid "" +#| "In this case, we can use `put` to update the game state, and `tell` to " +#| "add a message to the log:" 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`を使ってログにメッセージ" "を追加できます。" #. 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 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -7856,14 +8570,22 @@ msgstr "" "用の適切なインスタンスが存在するからです。" #. type: Plain text -#: text/chapter11.md:820 +#: text/chapter11.md:819 +#, fuzzy +#| 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." 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`" "フィールドを変更しています。\n" @@ -7874,22 +8596,26 @@ msgstr "" "`inventory`は更新されます。" #. type: Plain text -#: text/chapter11.md:822 +#: text/chapter11.md:821 +#, fuzzy +#| msgid "" +#| "Finally, the `pickUp` function handles the remaining cases, by notifying " +#| "the user using `tell`:" 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`を使ってユーザに次のように通知することにより、残" "りの場合を処理します。" #. 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,17 +8626,23 @@ 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 +#, fuzzy +#| 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 same do notation block." 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" @@ -7919,20 +8651,29 @@ msgstr "" "ンを使うことができることに注意してください。" #. type: Plain text -#: text/chapter11.md:836 +#: text/chapter11.md:835 +#, fuzzy +#| 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." 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" "そうでなければ、エラーメッセージが追加されます。" #. type: Plain text -#: text/chapter11.md:838 +#: text/chapter11.md:837 +#, fuzzy +#| msgid "" +#| "The remainder of the `Game` module defines a set of similar actions, each " +#| "using only the actions defined by the `MonadState`, `MonadReader` and " +#| "`MonadWriter` type classes." 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`型" @@ -7940,22 +8681,26 @@ msgstr "" "アクションが定義されています。" #. 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 +#, fuzzy +#| 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." 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`モナドで動くため、ユーザのコマンドに応答するために" "は計算する必要があります。" #. 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 +8713,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 +8722,27 @@ 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 +#, fuzzy +#| 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`:" 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`の計算結果を実行します。" #. 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,11 +8754,17 @@ 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 +#, fuzzy +#| msgid "" +#| "`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 " +#| "the final state." 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`を組み合わせたように見えま" @@ -8017,7 +8773,7 @@ msgstr "" "含むデータ構造を返します。" #. 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 +8782,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,10 +8799,15 @@ msgstr "" "`runGame`は関数の引数としてのゲームの設定を取ります。" #. type: Plain text -#: text/chapter11.md:870 +#: text/chapter11.md:869 +#, fuzzy +#| msgid "" +#| "The `node-readline` package provides the `LineHandler` type, which " +#| "represents actions in the `Effect` monad which handle user input from the " +#| "terminal. Here is the corresponding API:" 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" @@ -8054,7 +8815,7 @@ msgstr "" "対応する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,10 +8835,15 @@ msgstr "" " -> Effect Unit\n" #. type: Plain text -#: text/chapter11.md:882 +#: text/chapter11.md:881 +#, fuzzy +#| 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 created using the `createConsoleInterface` function:" 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`型はコンソールの制御対象を表しており、コンソールとやり取りする関数" @@ -8085,7 +8851,7 @@ msgstr "" "`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 +8863,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 +8872,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 +8888,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 +8903,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,7 +8914,7 @@ 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 " @@ -8161,7 +8927,7 @@ msgstr "" "モナドで)`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. " @@ -8178,22 +8944,26 @@ msgstr "" "し、`prompt`アクションを使ってプロンプトを再び表示しています。" #. type: Plain text -#: text/chapter11.md:910 +#: text/chapter11.md:909 +#, fuzzy +#| msgid "" +#| "The `runGame` function finally attaches the initial line handler to the " +#| "console interface, and displays the initial prompt:" 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,7 +8975,7 @@ 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 " @@ -8217,21 +8987,22 @@ msgstr "" "います。" #. type: Plain text -#: text/chapter11.md:921 -#, 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" +#: text/chapter11.md:920 +#, fuzzy, 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" #. 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 +9013,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 +9036,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 +9052,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 " @@ -8302,12 +9073,12 @@ msgstr "" "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,30 +9090,32 @@ msgstr "" "{{#include ../exercises/chapter11/src/Main.purs:parserOptions}}\n" #. type: Plain text -#: text/chapter11.md:949 -#, 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" +#: text/chapter11.md:948 +#, fuzzy, 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" "`env <**> OP.helper`は`env`と名付けられた任意のコマンドライン引数`Parser`を取り、自動的に`--help`オプションを加えます。\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 -#, 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" +#: text/chapter11.md:956 +#, fuzzy, 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" "この関数は`Parser`上で型`PlayerName -> Boolean -> GameEnvironment`を持ちます。\n" @@ -8351,20 +9124,28 @@ msgstr "" "`optparse`は多種多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。\n" #. type: Plain text -#: text/chapter11.md:959 -#, 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" +#: text/chapter11.md:958 +#, fuzzy, 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" #. type: Bullet: ' 1. ' -#: text/chapter11.md:963 +#: text/chapter11.md:962 +#, fuzzy +#| 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." 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" @@ -8374,10 +9155,15 @@ msgstr "" "ません。" #. type: Plain text -#: text/chapter11.md:967 +#: text/chapter11.md:966 +#, fuzzy +#| 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, and the `Effect` monad to build a front-end using the console." 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" @@ -8385,7 +9171,7 @@ msgstr "" "エンドを構築するための `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,14 +9184,22 @@ msgstr "" "ようなことができるでしょう。" #. type: Plain text -#: text/chapter11.md:971 +#: text/chapter11.md:970 +#, fuzzy +#| 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." 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 "" "モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見" "てきました。\n" @@ -8417,11 +9211,17 @@ msgstr "" "うな標準的な抽象化を使用して、役に立つモナドを構築できました。" #. type: Plain text -#: text/chapter11.md:972 +#: text/chapter11.md:971 +#, fuzzy +#| 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." 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 "" "モナド変換子は、高階多相や多変数型クラスなどの高度な型システムの機能を利用す" "ることによって記述でき、表現力の高いコードの優れた実演となっています。" @@ -8472,12 +9272,19 @@ msgstr "" #. type: Plain text #: text/chapter12.md:17 +#, fuzzy +#| 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." 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" @@ -8507,9 +9314,15 @@ msgstr "" #. type: Plain text #: text/chapter12.md:23 +#, fuzzy +#| msgid "" +#| "The `main` action starts, like in the other modules, by using the " +#| "`getCanvasElementById` action to get a reference to the canvas object, " +#| "and the `getContext2D` action to access the 2D rendering context for the " +#| "canvas:" 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`" @@ -8519,9 +9332,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:25 +#, fuzzy +#| 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." 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`がシグネチャに沿うようにするために使われています。" @@ -8580,8 +9397,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:43 +#, fuzzy +#| msgid "" +#| "The graphics context `ctx` manages the state of the canvas, and provides " +#| "methods to render primitive shapes, set styles and colors, and apply " +#| "transformations." 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 "" @@ -8633,10 +9455,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 " +#, fuzzy +#| msgid "" +#| "`fillPath` takes a graphics context and another action which 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 rectangle:" +msgid "" +"`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`はグラフィックスコンテキストと描画するパスを構築する別のアクション" @@ -8683,10 +9511,15 @@ msgstr "行多相を利用する" #. type: Plain text #: text/chapter12.md:75 +#, fuzzy +#| 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." 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`関数は断片的な線分のパスを描画するの" @@ -8694,9 +9527,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:77 +#, fuzzy +#| msgid "" +#| "The `Shapes.purs` file renders three shapes: a rectangle, an arc segment " +#| "and a triangle." 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つの図形を描画しています。" @@ -8730,9 +9567,15 @@ msgstr "" # FIXME: w, hとなっていますが、上のコードではwidthとheightになっています。 #. type: Plain text #: text/chapter12.md:90 +#, fuzzy +#| 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." 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`のプロパティはそれぞ" "れ幅と高さを表しています。" @@ -8769,19 +9612,30 @@ msgstr "" # FIXME: これも半径がrとradiusで違います。 #. type: Plain text #: text/chapter12.md:104 +#, fuzzy +#| 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." 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`は弧の両" "端の角度を弧度法で表しています。" #. type: Plain text #: text/chapter12.md:106 +#, fuzzy +#| 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 of the canvas:" 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`の円弧を塗り潰しま" @@ -8812,11 +9666,17 @@ msgstr "" #. type: Plain text #: text/chapter12.md:118 +#, fuzzy +#| 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." 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" @@ -8826,8 +9686,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:120 +#, fuzzy +#| msgid "" +#| "For example, the `Shapes` module defines a `translate` function which " +#| "translates a shape by modifying its `x` and `y` properties:" 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`のプロパティを変更し図形を並行移動する " @@ -8870,9 +9734,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:130 +#, fuzzy +#| msgid "" +#| "The `translate` function can be used with both the `Rectangle` and `Arc` " +#| "records, as can be seen in the `Shapes` example." 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`レ" "コード双方に対して使うことができます。" @@ -8946,22 +9814,33 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 +#, fuzzy +#| msgid "" +#| "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " +#| "each of the examples so far." msgid "" "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " -"each of the examples so far." +"each example so far." msgstr "" "(簡単)これまでの例のそれぞれについて、 `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." +#, fuzzy +#| 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." +msgid "" +"(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" @@ -9032,8 +9911,9 @@ 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" +#, fuzzy, 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" @@ -9053,11 +9933,17 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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" @@ -9066,8 +9952,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:187 +#, fuzzy +#| msgid "" +#| "The `main` action obtains a reference to the graphics context as before, " +#| "and then sets the stroke and fill styles:" 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`アクションではこれまでのようにグラフィックスコンテキストへの参照を取得" @@ -9096,10 +9986,15 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:for}}\n" #. type: Plain text #: text/chapter12.md:199 +#, fuzzy +#| 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:" 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" @@ -9154,9 +10049,14 @@ msgstr "座標変換" #. type: Plain text #: text/chapter12.md:221 +#, fuzzy +#| msgid "" +#| "There is more to the canvas than just rendering simple shapes. Every " +#| "canvas maintains a transformation which is used to transform shapes " +#| "before rendering. Shapes can be translated, rotated, scaled, and skewed." 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" @@ -9218,9 +10118,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:245 +#, fuzzy +#| msgid "" +#| "The `rotate` action performs a rotation around the origin, through some " +#| "number of radians specified by the first argument." 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`アクションは最初の引数で指定されたラジアンの値に応じて、原点を中心と" "して回転します。" @@ -9302,9 +10206,13 @@ msgstr "コンテキストの保存" #. type: Plain text #: text/chapter12.md:268 +#, fuzzy +#| msgid "" +#| "A common use case is to render some subset of the scene using a " +#| "transformation, and then to reset the transformation afterwards." 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 "" "変換を適用してシーンの一部を描画し、それからその変換を元に戻す、という使い方" "はよくあります。" @@ -9353,11 +10261,18 @@ msgstr "" #. type: Plain text #: text/chapter12.md:284 +#, fuzzy +#| 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 transformation afterwards:" 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 "" "これらのアクションにより、現在の状態を保存し、いろいろなスタイルや変換を適用" @@ -9445,9 +10360,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:316 +#, fuzzy +#| msgid "" +#| "The `Effect.Ref` module provides a type constructor for global mutable " +#| "references, and an associated effect:" 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`モジュールでは、大域的に変更可能な参照のための型構築子、及び関連" "する作用を提供します。" @@ -9479,8 +10398,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:327 +#, fuzzy +#| msgid "" +#| "The `Example/Refs.purs` file contains an example which uses a `Ref` to " +#| "track mouse clicks on the `canvas` element." 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`要素上のマウスクリックを追跡するのに " @@ -9488,8 +10411,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:329 +#, fuzzy +#| msgid "" +#| "The code starts by creating a new reference containing the value `0`, by " +#| "using the `new` action:" 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`を含む新しい参照を作成してい" @@ -9531,8 +10458,13 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}}\n" #. type: Plain text #: text/chapter12.md:347 +#, fuzzy +#| msgid "" +#| "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):" 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 "" @@ -9542,9 +10474,13 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter12.md:352 +#, fuzzy +#| msgid "" +#| "The rectangle is translated through `(-100, -100)` so that its center " +#| "lies at the origin." 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: '- ' @@ -9561,9 +10497,13 @@ msgstr "矩形が原点を中心に`10`の倍数分の角度で回転します #. type: Bullet: '- ' #: text/chapter12.md:352 +#, fuzzy +#| msgid "" +#| "The rectangle is translated through `(300, 300)` so that it center lies " +#| "at the center of the canvas." 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 "矩形が`(300, 300)`だけ平行移動し、中心がcanvasの中心に来ます。" #. type: Plain text @@ -9589,18 +10529,27 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 +#, fuzzy +#| msgid "" +#| "(Easy) Write a higher-order function which strokes and fills a path " +#| "simultaneously. Rewrite the `Random.purs` example using your function." 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`例を書き直してください。" #. 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 " +#, fuzzy +#| 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 is clicked." +msgid "" +"(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`作用を使用して、マウスがクリックされたときに、" @@ -9609,8 +10558,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 +#, fuzzy +#| msgid "" +#| "(Medium) Write a function which transforms the scene by rotating it " +#| "around a point with specified coordinates. _Hint_: use a translation to " +#| "first translate the scene to the origin." 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 "" @@ -9634,11 +10588,18 @@ msgstr "" #. type: Plain text #: text/chapter12.md:372 +#, fuzzy +#| 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 of letters." 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は*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生" @@ -9659,9 +10620,14 @@ msgstr "" #. type: Plain text #: text/chapter12.md:376 +#, fuzzy +#| 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 production rules:" 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`(前進)で構成" @@ -9702,10 +10668,15 @@ msgstr "" #. type: Plain text #: text/chapter12.md:392 +#, fuzzy +#| 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." 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" @@ -9779,12 +10750,18 @@ 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? " +#, fuzzy +#| 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? 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." +msgid "" +"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" @@ -9822,12 +10799,19 @@ 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`." +#, fuzzy +#| 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`." +msgid "" +"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" @@ -9872,13 +10856,21 @@ 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`." +#, fuzzy +#| 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`." +msgid "" +"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" @@ -10015,17 +11007,22 @@ msgstr "" #. type: Plain text #: text/chapter12.md:494 +#, fuzzy +#| 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." 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`がゼロでないときです。" #. 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" +#, fuzzy, 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" @@ -10057,8 +11054,12 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_ #. type: Plain text #: text/chapter12.md:508 +#, fuzzy +#| msgid "" +#| "That's it! Note how the use of higher order functions like `foldM` and " +#| "`concatMap` allowed us to communicate our ideas concisely." 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" @@ -10097,12 +11098,19 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_anno} #. type: Plain text #: text/chapter12.md:518 +#, fuzzy +#| 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." 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" @@ -10113,13 +11121,22 @@ msgstr "" #. type: Plain text #: text/chapter12.md:520 +#, fuzzy +#| 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." 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" "この手法の利点は、複数の異なる方法でデータを解釈する自由が得られることで" @@ -10165,10 +11182,14 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} #. type: Plain text #: text/chapter12.md:534 +#, fuzzy +#| 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:" 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`(前進)を解釈するには、パスの新しい位置を計算し、線分を描画し、状態" "を次のように更新します。" @@ -10240,8 +11261,12 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 +#, fuzzy +#| msgid "" +#| "(Easy) Try changing the various numerical constants in the code, to " +#| "understand their effect on the rendered system." 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 "" "(簡単)描画システムへの影響を理解するために、コード中の様々な数値の定数を変" @@ -10260,10 +11285,16 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 +#, fuzzy +#| 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." 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`アクションを使い、塗りつぶされた" @@ -10303,10 +11334,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:571 -#, no-wrap +#, fuzzy, 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" 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" @@ -10343,8 +11377,9 @@ 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" +#, fuzzy, 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" @@ -10379,10 +11414,17 @@ msgstr "" #. type: Plain text #: text/chapter12.md:597 +#, fuzzy +#| 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 polymorphism, and the `Effect` monad for handling " +#| "side-effects." 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 " @@ -10425,13 +11467,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:611 +#, fuzzy 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." -msgstr "" -"この手法は `drawing`パッケージでも採用されており、描画前にさまざまな方法で" -"データとしてシーンを操作できる柔軟性をもたらしています。" +"flexibility of manipulating the scene as data in various ways before " +"rendering." +msgstr "この手法は `drawing`パッケージでも採用されており、描画前にさまざまな方法でデータとしてシーンを操作できる柔軟性を齎しています。" #. type: Plain text #: text/chapter12.md:612 @@ -10525,8 +11566,12 @@ msgstr "merge :: Array Int -> Array Int -> Array Int\n" #. type: Plain text #: text/chapter13.md:24 +#, fuzzy +#| msgid "" +#| "`merge` takes two sorted arrays of integers, and merges their elements so " +#| "that the result is also sorted. For example:" 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つの整列された整数の配列を取って、結果が整列されるように要素を統合" @@ -10549,9 +11594,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:33 +#, fuzzy +#| 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 the appropriate values. However, everything we need to know about the " +#| "`merge` function can be summarized by this property:" 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 "" @@ -10571,10 +11622,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:37 +#, fuzzy +#| 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:" 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" @@ -10595,13 +11651,20 @@ msgstr "" #. type: Plain text #: text/chapter13.md:45 +#, fuzzy +#| 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:" 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 "" "このコードを実行すると、 `quickcheck`は無作為な入力 `xs`と `ys`を生成してこの" "関数に渡すことで、主張しようとしている性質を反証しようとします。\n" @@ -10728,12 +11791,18 @@ 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." +#, fuzzy +#| 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." +msgid "" +"(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" @@ -10803,9 +11872,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:115 +#, fuzzy +#| 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 " +#| "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`:" 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 "" @@ -10827,10 +11902,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:122 +#, fuzzy +#| 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:" 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" @@ -10867,19 +11947,28 @@ msgstr "" #. type: Plain text #: text/chapter13.md:136 +#, fuzzy +#| msgid "" +#| "Here, `xs` and `ys` both have type `Array Int`, since the `ints` function " +#| "has been used to disambiguate the unknown type." 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`を持っています。" #. 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." +#, fuzzy +#| 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." +msgid "" +"(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`を書き、 " "`mergePoly`をその型でテストする性質を追加してください。" @@ -10905,9 +11994,13 @@ msgstr "任意のデータの生成" #. type: Plain text #: text/chapter13.md:145 +#, fuzzy +#| msgid "" +#| "Now we will see how the `quickcheck` library is able to randomly generate " +#| "test cases for our properties." 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`ライブラリを使って性質に対するテスト項目を無作為に生成する方法に" "ついて説明します。" @@ -10959,9 +12052,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:158 +#, fuzzy +#| 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:" 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 "" @@ -11020,11 +12119,17 @@ msgstr "" #. type: Plain text #: text/chapter13.md:179 +#, fuzzy +#| 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:" 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" @@ -11068,10 +12173,17 @@ msgstr "" #. type: Plain text #: text/chapter13.md:198 +#, fuzzy +#| 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. Ideally, the type of the `mergePoly` function itself would be " +#| "updated to use the `Sorted` type constructor." 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 "" @@ -11124,10 +12236,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:217 +#, fuzzy +#| 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:" 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" @@ -11155,10 +12271,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:229 +#, fuzzy +#| 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:" 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" @@ -11177,8 +12297,14 @@ 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, " +#, fuzzy +#| msgid "" +#| "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:" +msgid "" +"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:" @@ -11221,8 +12347,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter13.md:248 +#, fuzzy +#| msgid "" +#| "(Difficult) Write a property which asserts that a value inserted into a " +#| "tree is still a member of that tree after arbitrarily many more " +#| "insertions." 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 "" "(難しい)木に挿入された値は、どれだけ挿入があった後でも、その木の構成要素で" @@ -11236,11 +12367,17 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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`関数は追加の関数を引数として取り、統合される要素の順序を決定するの" @@ -11249,10 +12386,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:254 +#, fuzzy +#| 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:" 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" @@ -11280,9 +12422,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:266 +#, fuzzy +#| 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." 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つの引数全てについて、値を生成した" @@ -11290,8 +12437,12 @@ msgstr "" #. type: Plain text #: text/chapter13.md:268 +#, fuzzy +#| msgid "" +#| "There is a second type class which allows us to create randomly-generated " +#| "functions. It is called `Coarbitrary`, and it is defined as follows:" 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" @@ -11309,9 +12460,16 @@ 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 " +#, fuzzy +#| 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 " +#| "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." +msgid "" +"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 "" @@ -11321,8 +12479,13 @@ msgstr "" #. type: Plain text #: text/chapter13.md:277 +#, fuzzy +#| msgid "" +#| "In addition, there is a type class instance which gives us `Arbitrary` " +#| "functions if the function domain is `Coarbitrary` and the function " +#| "codomain is `Arbitrary`:" 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 "" @@ -11337,11 +12500,16 @@ msgstr "instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b)\n" #. type: Plain text #: text/chapter13.md:283 +#, fuzzy +#| 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." 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`関数の場合では、新しい引数を考慮するようにテストを修" @@ -11349,12 +12517,20 @@ msgstr "" #. 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 " +#, fuzzy +#| 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 " +#| "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 the function `f` has been applied:" +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 " "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" @@ -11425,8 +12601,13 @@ msgstr "instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b)\n" #. type: Plain text #: text/chapter13.md:315 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -11472,10 +12653,15 @@ msgstr "instance Coarbitrary a => Coarbitrary (Tree a) where\n" #. type: Plain text #: text/chapter13.md:327 +#, fuzzy +#| 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:" 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`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があ" "ります。\n" @@ -11514,10 +12700,16 @@ msgstr "" #. type: Plain text #: text/chapter13.md:342 +#, fuzzy +#| 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:" 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" @@ -11532,9 +12724,13 @@ msgstr "anywhere :: forall a. (Tree a -> Boolean) -> Tree a -> Boolean\n" #. type: Plain text #: text/chapter13.md:348 +#, fuzzy +#| msgid "" +#| "Now we are able to generate the predicate function randomly. For example, " +#| "we expect the `anywhere` function to _respect disjunction_:" 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`関数は*ある命題のもとで不変*であることが期待されます。" @@ -11578,12 +12774,19 @@ msgstr "副作用のないテスト" #. type: Plain text #: text/chapter13.md:365 +#, fuzzy +#| 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." 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" @@ -11645,10 +12848,15 @@ msgstr "" #. type: Plain text #: text/chapter13.md:386 +#, fuzzy +#| 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." 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アプリケーションの" "フォームデータ例を無作為に生成するというような状況で便利かもしれません。" @@ -11696,10 +12904,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:400 -#, no-wrap +#, fuzzy, 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) 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" 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" @@ -11726,8 +12938,12 @@ msgstr "`spago test`を使ってQuickCheckのテストを自動化する方法 #. type: Bullet: '- ' #: text/chapter13.md:408 +#, fuzzy +#| msgid "" +#| "We saw how to write properties as functions, and how to use the `` " +#| "operator to improve error messages." 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 "" "性質を関数として書く方法とエラーメッセージを改良する ``演算子の使い方を説" @@ -11735,9 +12951,14 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter13.md:408 +#, fuzzy +#| 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 properties." 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`型クラスによって、如何にして定型的なテストコードの" @@ -11770,11 +12991,18 @@ msgstr "" #. type: Plain text #: text/chapter14.md:8 -msgid "" -"A domain-specific language is a language which is well-suited to development " +#, fuzzy +#| msgid "" +#| "A domain-specific language is a language which 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:" +msgid "" +"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" "領域特化言語の構文及び機能は、その領域内の考え方を表現するコードの読みやすさ" @@ -11793,8 +13021,13 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter14.md:11 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -11804,22 +13037,27 @@ msgstr "" #. type: Plain text #: text/chapter14.md:13 +#, fuzzy 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 +#, fuzzy +#| 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 " +#| "correct HTML documents, and we will work by improving a naive " +#| "implementation in small steps." 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 "" @@ -11829,10 +13067,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:19 +#, fuzzy +#| 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." 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`ライブラリです。" @@ -11844,8 +13086,9 @@ msgstr "このプロジェクトをPSCiを使って試していきます。" #. type: Title ## #: text/chapter14.md:22 -#, no-wrap -msgid "A HTML Data Type" +#, fuzzy, no-wrap +#| msgid "A HTML Data Type" +msgid "An HTML Data Type" msgstr "HTMLデータ型" #. type: Plain text @@ -11893,9 +13136,15 @@ msgstr "" #. type: Plain text #: text/chapter14.md:44 +#, fuzzy +#| msgid "" +#| "The `Element` type represents HTML elements. Each element consists of an " +#| "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." 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 "" @@ -11987,8 +13236,12 @@ msgstr "現状のライブラリには幾つもの問題があります。" #. type: Bullet: '- ' #: text/chapter14.md:87 +#, fuzzy +#| msgid "" +#| "Creating HTML documents is difficult - every new element requires at " +#| "least one record and one data constructor." 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" @@ -12032,12 +13285,19 @@ msgstr "スマート構築子" #. type: Plain text #: text/chapter14.md:93 +#, fuzzy +#| 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." 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" "モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリ" @@ -12073,9 +13333,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:106 +#, fuzzy +#| msgid "" +#| "Next, we create smart constructors for those HTML elements we want our " +#| "users to be able to create, by applying the `element` function:" 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`関数を適用します。" @@ -12160,8 +13424,13 @@ msgstr "型クラス。クラス名により指定されます。" #. type: Bullet: '- ' #: text/chapter14.md:139 +#, fuzzy +#| msgid "" +#| "A type constructor and any associated data constructors, indicated by the " +#| "name of the type followed by a parenthesized list of exported data " +#| "constructors." 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 "" @@ -12170,10 +13439,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:141 +#, fuzzy +#| 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." 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" @@ -12212,9 +13485,14 @@ msgstr "閉じた要素は構築するときに内容を含められません。 #. type: Plain text #: text/chapter14.md:150 +#, fuzzy +#| 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, and provide the following smart constructors:" 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" @@ -12269,11 +13547,17 @@ msgstr "" #. type: Plain text #: text/chapter14.md:172 +#, fuzzy +#| 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 names were entered incorrectly. To solve this problem, we " +#| "can create a newtype which represents attribute names:" 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" @@ -12446,12 +13730,19 @@ msgstr "" #. type: Plain text #: text/chapter14.md:248 +#, fuzzy +#| 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." 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" @@ -12470,9 +13761,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:253 +#, fuzzy +#| msgid "" +#| "(Medium) Some HTML attributes such as `checked` and `disabled` do not " +#| "require values, and may be rendered as _empty attributes_:" 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属性がありますが、これ" "らは次のような _空の属性_ として表示されるかもしれません。" @@ -12743,10 +14038,15 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:356 +#, fuzzy +#| 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." 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" @@ -12755,10 +14055,16 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:356 +#, fuzzy +#| 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 " +#| "`checked`." 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`用の最上位の表現を定義すること" @@ -12793,11 +14099,17 @@ msgstr "Freeモナド" #. type: Plain text #: text/chapter14.md:367 +#, fuzzy +#| 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:" 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モナド_ と呼ばれる構造を使うことです。これによって入れ子になった要" @@ -12852,10 +14164,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:392 +#, fuzzy +#| 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 actions." 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モナドが" @@ -12864,8 +14182,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:394 +#, fuzzy +#| msgid "" +#| "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:" 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 "" @@ -12890,10 +14213,15 @@ msgstr "" #. type: Plain text #: text/chapter14.md:403 +#, fuzzy +#| 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`!" 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" @@ -12901,12 +14229,18 @@ msgstr "" #. type: Plain text #: text/chapter14.md:405 +#, fuzzy +#| 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:" 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つのデータ構築子を" @@ -12936,9 +14270,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:417 +#, fuzzy +#| 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 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." 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." @@ -12968,9 +14309,15 @@ msgstr "type Content = Free ContentF\n" #. type: Plain text #: text/chapter14.md:425 +#, fuzzy +#| 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 " +#| "`Content` data constructor, we restrict our users to only using the " +#| "monadic actions we provide." 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 "" @@ -13017,10 +14364,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:439 +#, fuzzy +#| 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 type:" 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`と " @@ -13037,10 +14390,15 @@ msgstr "liftF :: forall f a. f a -> Free f a\n" #. type: Plain text #: text/chapter14.md:445 +#, fuzzy +#| 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:" 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" @@ -13130,11 +14488,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:479 +#, fuzzy +#| 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_." 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" @@ -13144,9 +14507,15 @@ msgstr "" #. type: Plain text #: text/chapter14.md:481 +#, fuzzy +#| 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." 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文字列を累積することにします。" @@ -13298,8 +14667,12 @@ msgstr " renderContentItem :: ContentF (Content Unit) -> Writer String (Con #. type: Plain text #: text/chapter14.md:540 +#, fuzzy +#| msgid "" +#| "We can implement this function by simply pattern matching on the two data " +#| "constructors of `ContentF`:" 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つのデータ構築子でパターン照合するだけでこの関数を実装できます。" @@ -13324,8 +14697,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:551 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -13404,21 +14782,32 @@ msgstr "" #. type: Plain text #: text/chapter14.md:578 +#, fuzzy +#| 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." 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モナ" "ド構造の威力をお見せしましょう。" #. type: Plain text #: text/chapter14.md:580 -msgid "" -"Suppose we want to generate HTML documents which contain hyperlinks to " +#, fuzzy +#| msgid "" +#| "Suppose we want to generate HTML documents which 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:" +msgid "" +"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 "" "*アンカー*を使用して文書のさまざまな節へのハイパーリンクが含まれているHTML文" "書を生成するとします。\n" @@ -13440,10 +14829,15 @@ msgstr "開発者がアンカー名を1つ以上の箇所で打ち間違うか #. type: Plain text #: text/chapter14.md:585 +#, fuzzy +#| 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." 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 "" "開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい" "一意な名前を生成するためのモナドアクションを提供できます。" @@ -13479,9 +14873,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:598 +#, fuzzy +#| 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:" 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`型クラ" "スのインスタンスを定義します。" @@ -13626,23 +15024,35 @@ msgstr "" #. type: Plain text #: text/chapter14.md:654 +#, fuzzy +#| msgid "" +#| "Notice that we provide the `id` function as our continuation, meaning " +#| "that we return the result of type `Name` unchanged." 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`の結果を変更せずに返すということを意味しています。" #. type: Plain text #: text/chapter14.md:656 -msgid "" -"Finally, we need to update our interpretation function, to interpret the new " +#, fuzzy +#| msgid "" +#| "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:" +msgid "" +"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 "" "最後に、新しいアクションを解釈するために解釈関数を更新する必要があります。\n" "以前は計算を解釈するために `Writer String`モナドを使っていましたが、このモナ" @@ -13669,10 +15079,17 @@ msgstr "" #. type: Plain text #: text/chapter14.md:664 +#, fuzzy +#| 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, need to modify the handler used to run our computation. Instead " +#| "of just `execWriter`, we now need to use `evalState` as well:" 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 "" @@ -13731,9 +15148,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:683 +#, fuzzy +#| 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 element and the target of a hyperlink:" 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" @@ -13778,15 +15200,19 @@ msgstr "" #. type: Plain text #: text/chapter14.md:703 +#, fuzzy +#| msgid "" +#| "You can verify that multiple calls to `newName` do in fact result in " +#| "unique names." 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`の呼び出しの結果が、実際に一意な名前になっていることも確か" "められます。" #. 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,7 +15221,7 @@ 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`." @@ -13804,7 +15230,7 @@ msgstr "" "て、型 `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 +15238,32 @@ msgstr "" "`Element`の代わりに型`Content Unit`の引数を受け付けるように`render`関数を変更" "してください。" -#. type: Plain text -#: text/chapter14.md:712 -#, no-wrap -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" -msgstr "" -" 1. (普通)型同義語の代わりに`newtype`を使うことによって`Content`モナドの実装を隠してください。\n" +#. type: Bullet: ' 1. ' +#: text/chapter14.md:711 +#, fuzzy +#| 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" +msgid "" +"(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" +" 1. (難しい)`ContentF`型を変更して以下の新しいアクションに対応してくださ" +"い。\n" + +#. 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,13 +15275,13 @@ 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" #. 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 "" @@ -13851,34 +15289,48 @@ msgstr "" " あるいは、`RWS`モナドを使うほうが好みの人もいるかもしれません。\n" #. type: Plain text -#: text/chapter14.md:724 +#: text/chapter14.md:723 +#, fuzzy +#| msgid "" +#| "In this chapter, we developed a domain-specific language for creating " +#| "HTML documents, by incrementally improving a naive implementation using " +#| "some standard techniques:" 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 +#, fuzzy +#| msgid "" +#| "We used _smart constructors_ to hide the details of our data " +#| "representation, only permitting the user to create documents which were " +#| "_correct-by-construction_." 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 +#, fuzzy +#| msgid "" +#| "We used an _user-defined infix binary operator_ to improve the syntax of " +#| "the language." 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." @@ -13887,19 +15339,25 @@ msgstr "" "が誤った型の属性値を与えることを防いでいます。" #. type: Bullet: '- ' -#: text/chapter14.md:729 +#: text/chapter14.md:728 +#, fuzzy +#| 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." 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記法に対応したモナドな表現に変" "えました。それからこの表現を新しいモナドアクションに対応するよう拡張し、標準" "モナド変換子を使ってモナドの計算を解釈しました。" #. 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,12 +15367,18 @@ msgstr "" "したりするために、PureScriptのモジュールと型システムを活用しています。" #. type: Plain text -#: text/chapter14.md:732 -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." +#: text/chapter14.md:731 +#, fuzzy +#| 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." +msgid "" +"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 "" "関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野で" "すが、幾つかの簡単な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言" @@ -14020,13 +15484,23 @@ msgstr "git clone https://github.com/purescript-contrib/purescript-book.git\n" #. type: Plain text #: text/chapter2.md:28 +#, fuzzy +#| 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):" 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 "" @@ -14092,13 +15566,21 @@ msgstr "" #. type: Plain text #: text/chapter2.md:55 +#, fuzzy +#| 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." 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 "" "なお、`answer`関数(`src/Euler.purs`にあります)は、任意の整数以下の3と5の倍" "数を見付けるように変更されています。\n" @@ -14120,8 +15602,12 @@ msgstr "" #. type: Plain text #: text/chapter2.md:59 +#, fuzzy +#| msgid "" +#| "Let's work through this next exercise together in test-driven-development " +#| "style." 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 "テスト駆動開発のスタイルでこの次の演習を一緒に進めてみましょう。" @@ -14149,9 +15635,14 @@ msgstr "解法" #. type: Plain text #: text/chapter2.md:67 +#, fuzzy +#| 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 `{-` and end with `-}`:" 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" @@ -14199,9 +15690,13 @@ msgstr "" #. type: Plain text #: text/chapter2.md:86 +#, fuzzy +#| 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`:" 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`に追加してください。" @@ -14330,14 +15825,24 @@ msgstr "" #. type: Plain text #: text/chapter2.md:134 +#, fuzzy +#| 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." 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." +"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" @@ -14350,13 +15855,22 @@ msgstr "" #. type: Plain text #: text/chapter2.md:136 +#, fuzzy +#| 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 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), please send us a PR." 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`にあるものと解答とを比べ" @@ -14447,9 +15961,14 @@ msgstr "`Control.Plus`モジュールには`empty`値が定義されています #. type: Bullet: '- ' #: text/chapter3.md:24 -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 " +#, fuzzy +#| 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 working with linked lists." +msgid "" +"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を使ってインス" @@ -14503,9 +16022,17 @@ msgstr "単純な型" #. type: Plain text #: text/chapter3.md:37 -msgid "" -"PureScript defines three built-in types which correspond to JavaScript's " -"primitive types: numbers, strings and booleans. These are defined in the " +#, fuzzy +#| msgid "" +#| "PureScript defines three built-in types which correspond 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:" +msgid "" +"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:" @@ -14545,8 +16072,12 @@ msgstr "" #. type: Plain text #: text/chapter3.md:52 +#, fuzzy +#| msgid "" +#| "PureScript defines some other built-in types: integers, characters, " +#| "arrays, records, and functions." 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には他にも、整数、文字、配列、レコード、関数といった組み込み型が定" @@ -14621,10 +16152,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:81 +#, fuzzy +#| 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." 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、等価にする意)しようとして失敗したことを示してい" @@ -14659,10 +16194,15 @@ msgstr "" #. type: Plain text #: text/chapter3.md:94 +#, fuzzy +#| 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." 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` と" @@ -14743,12 +16283,18 @@ msgstr "" #. type: Plain text #: text/chapter3.md:124 -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:" +#, fuzzy +#| 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:" +msgid "" +"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" @@ -14816,9 +16362,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:149 +#, fuzzy +#| 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." 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 " +"quantified type_. It means we can substitute any types for `a`, `b`, and " "`c`, and `flip` will work with those types." msgstr "" "この `forall`キーワードは、 `flip`が _全称量化された型_ (universally " @@ -14827,9 +16378,14 @@ msgstr "" #. 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 " +#, fuzzy +#| 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" +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`というように選んでみた" @@ -14843,10 +16399,15 @@ msgstr "(Int -> String -> String) -> String -> Int -> String\n" #. type: Plain text #: text/chapter3.md:157 +#, fuzzy +#| 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:" 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:" +"type – it happens automatically. For example, we can use `flip` as if it had " +"this type already:" msgstr "" "量化された型を特殊化したいということをコードで示す必要はありません。\n" "特殊化は自動的に行われます。\n" @@ -14867,12 +16428,19 @@ msgstr "" #. 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:" +#, fuzzy +#| 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:" +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" @@ -14923,7 +16491,9 @@ msgstr "" #. type: Plain text #: text/chapter3.md:179 -msgid "Therefore, the following is valid PureScript code:" +#, fuzzy +#| msgid "Therefore, the following is valid PureScript code:" +msgid "Therefore, the following is a valid PureScript code:" msgstr "したがって、次は正しいPureScriptコードです。" #. type: Fenced code block (haskell) @@ -14938,7 +16508,9 @@ msgstr "" #. type: Plain text #: text/chapter3.md:186 -msgid "But this is not valid code:" +#, fuzzy +#| msgid "But this is not valid code:" +msgid "But this is not a valid code:" msgstr "しかし、次は正しいコードではありません。" #. type: Fenced code block (haskell) @@ -14988,7 +16560,9 @@ msgstr "" #. type: Plain text #: text/chapter3.md:204 -msgid "but this is not:" +#, fuzzy +#| msgid "but this is not:" +msgid "But this is not:" msgstr "しかし、これは正しくありません。" #. type: Fenced code block (text) @@ -15072,12 +16646,19 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}}\n" #. type: Plain text #: text/chapter3.md:234 -msgid "" -"This defines a _type synonym_ called `Entry` - the type `Entry` is " +#, fuzzy +#| msgid "" +#| "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:" +msgid "" +"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、型シノニム)を定義していま" "す。\n" @@ -15100,8 +16681,12 @@ msgstr "なお、レコードには他のレコードを含めることができ #. type: Plain text #: text/chapter3.md:242 +#, fuzzy +#| msgid "" +#| "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:" 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つめの型同義語も定義してみましょう。住所録のデータ構造としては、単" @@ -15115,8 +16700,12 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}} #. type: Plain text #: text/chapter3.md:248 +#, fuzzy +#| msgid "" +#| "Note that `List Entry` is not the same as `Array Entry`, which represents " +#| "an _array_ of entries." 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`とは同じではないということに注意してください。 " @@ -15142,10 +16731,16 @@ msgstr "" #. type: Plain text #: text/chapter3.md:254 +#, fuzzy +#| 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 of entries." 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 "" "ちょうど関数適用と同じように、型構築子は他の型に並べることで適用されることに" @@ -15275,8 +16870,13 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_sig #. type: Plain text #: text/chapter3.md:294 +#, fuzzy +#| msgid "" +#| "This type signature says that `showEntry` is a function, which takes an " +#| "`Entry` as an argument and returns a `String`. Here is the code for " +#| "`showEntry`:" 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 "" @@ -15417,9 +17017,13 @@ msgstr "住所録の作成" #. type: Plain text #: text/chapter3.md:351 +#, fuzzy +#| 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." 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" "空の住所録を表す値が必要ですが、これには空のリストを使います。" @@ -15447,9 +17051,14 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_s #. type: Plain text #: text/chapter3.md:363 +#, fuzzy +#| 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 " +#| "`AddressBook`." 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`、第二引数として " @@ -15457,11 +17066,19 @@ msgstr "" #. type: Plain text #: text/chapter3.md:365 +#, fuzzy +#| 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 reason effectively about its behavior, so we prefer pure functions and " +#| "immutable data where possible." 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 "" @@ -15503,8 +17120,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:378 +#, fuzzy +#| msgid "" +#| "This type signature says that `Cons` takes a value of some type `a`, and " +#| "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:" 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 "" @@ -15556,9 +17178,14 @@ msgstr "insertEntry entry book = Cons entry book\n" #. type: Plain text #: text/chapter3.md:398 -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 " +#, fuzzy +#| 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." +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." msgstr "" "等号の左側にある2つの引数`entry`と`book`がスコープに導入されますから、これら" @@ -15572,10 +17199,15 @@ msgstr "カリー化された関数" #. type: Plain text #: text/chapter3.md:402 +#, fuzzy +#| 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_." 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_." msgstr "" "PureScriptでは、関数は常に1つの引数だけを取ります。`insertEntry`関数は2つの引" "数を取るように見えますが、これは実際には*カリー化された関数*の一例となってい" @@ -15595,8 +17227,13 @@ msgstr "Entry -> (AddressBook -> AddressBook)\n" #. type: Plain text #: text/chapter3.md:410 +#, fuzzy +#| 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`." msgid "" -"That is, `insertEntry` is a function which returns a function! It takes a " +"That is, `insertEntry` is a function that 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`." msgstr "" @@ -15606,9 +17243,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:412 +#, fuzzy +#| 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:" 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でこの結果の型を見てみましょう。" @@ -15646,8 +17287,12 @@ msgstr "" #. type: Plain text #: text/chapter3.md:427 +#, fuzzy +#| msgid "" +#| "Note though that the parentheses here are unnecessary - the following is " +#| "equivalent:" 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 "ここで括弧は不要であることにも注意してください。次の式は同等です。" @@ -15663,18 +17308,24 @@ msgstr "" #. type: Plain text #: text/chapter3.md:434 +#, fuzzy +#| 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." 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 -#, 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" +#, fuzzy, 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" @@ -15710,12 +17361,19 @@ msgstr "" #. type: Plain text #: text/chapter3.md:447 +#, fuzzy +#| 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:" 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)`に渡されるような関数だ" @@ -15747,10 +17405,15 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}} #. type: Plain text #: text/chapter3.md:460 +#, fuzzy +#| 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." 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) " @@ -15758,10 +17421,16 @@ msgstr "" #. type: Plain text #: text/chapter3.md:462 +#, fuzzy +#| 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." 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だ」となり、関数の定義はとても明確になりました。しかし、一般的にポイン" @@ -15857,11 +17526,17 @@ msgstr "住所録に問い合わせる" #. type: Plain text #: text/chapter3.md:498 +#, fuzzy +#| 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." 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`を返すものです。これは小さな関数を組み合わせることでプログラ" @@ -15870,19 +17545,29 @@ msgstr "" #. type: Plain text #: text/chapter3.md:500 +#, fuzzy +#| 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." 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) 要素を返すだけです。" #. type: Plain text #: text/chapter3.md:502 +#, fuzzy +#| 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` " +#| "and `head` functions:" 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を起動し、 " @@ -15922,11 +17607,17 @@ msgstr "" #. type: Plain text #: text/chapter3.md:519 +#, fuzzy +#| 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." 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" @@ -15934,8 +17625,15 @@ msgstr "" #. type: Plain text #: text/chapter3.md:521 -msgid "" -"`head` takes a list as its argument, and returns a type we haven't seen " +#, fuzzy +#| msgid "" +#| "`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." +msgid "" +"`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 " @@ -15971,9 +17669,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:531 +#, fuzzy +#| 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." 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 @@ -15999,9 +17701,15 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_sig #. type: Plain text #: text/chapter3.md:541 -msgid "" -"This type signature says that `findEntry` takes two strings, the first and " -"last names, and a `AddressBook`, and returns an optional `Entry`. The " +#, fuzzy +#| msgid "" +#| "This type signature says that `findEntry` takes two strings, the first " +#| "and last names, and a `AddressBook`, and returns an optional `Entry`. The " +#| "optional result will contain a value only if the name is found in the " +#| "address book." +msgid "" +"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 "" @@ -16045,8 +17753,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:556 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -16073,8 +17786,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:560 +#, fuzzy +#| msgid "" +#| "Note that, just like for top-level declarations, it was not necessary to " +#| "specify a type signature for `filterEntry`. However, doing so is " +#| "recommended as a form of documentation." 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 "" @@ -16090,10 +17808,16 @@ msgstr "中置の関数適用" #. type: Plain text #: text/chapter3.md:564 -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 " +#, fuzzy +#| 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 `AddressBook`, we might write:" +msgid "" +"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 "" "これまでお話しした関数のほとんどは _前置_ 関数適用でした。関数名が引数の _前" @@ -16108,14 +17832,24 @@ msgstr "> book1 = insertEntry john emptyBook\n" #. type: Plain text #: text/chapter3.md:570 +#, fuzzy +#| 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:" 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/" "documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれて" @@ -16132,10 +17866,15 @@ msgstr "infix 4 eq as ==\n" #. type: Plain text #: text/chapter3.md:576 +#, fuzzy +#| 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." 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`で置き換えられます。この節の後のほうで中置演算子を定義す" @@ -16143,9 +17882,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:578 +#, fuzzy +#| 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:" 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" @@ -16163,8 +17907,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:585 +#, fuzzy +#| msgid "" +#| "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 (\\`):" 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 "" @@ -16257,8 +18006,12 @@ msgstr "book5 = john ++ (peggy ++ (ned ++ emptyBook))\n" #. type: Plain text #: text/chapter3.md:618 +#, fuzzy +#| msgid "" +#| "and the right associativity of our new `++` operator lets us get rid of " +#| "the parentheses without changing the meaning:" 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 "そして新しい`++`演算子が右結合なので意味を変えずに括弧を除去できます。" @@ -16304,8 +18057,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:634 +#, fuzzy +#| msgid "" +#| "Note that `$` isn't special syntax that's hardcoded into the language. " +#| "It's simply the infix operator for a regular function called `apply`, " +#| "which is defined in `Data.Function` as follows:" 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 "" @@ -16533,11 +18291,17 @@ msgstr "" #. type: Plain text #: text/chapter3.md:713 -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." +#, fuzzy +#| 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." +msgid "" +"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つの役目だけをこなし、機能を" @@ -16586,8 +18350,14 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter3.md:721 -msgid "" -"(Medium) Write a function `isInBook` which tests whether a name appears in a " +#, fuzzy +#| msgid "" +#| "(Medium) Write a function `isInBook` which 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." +msgid "" +"(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 "" @@ -16598,14 +18368,23 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter3.md:721 +#, fuzzy +#| 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." 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" @@ -16619,50 +18398,71 @@ msgstr "" #. type: Plain text #: text/chapter3.md:725 +#, fuzzy +#| msgid "" +#| "In this chapter, we covered several new functional programming concepts:" msgid "" -"In this chapter, we covered several new functional programming concepts:" +"In this chapter, we covered several new functional programming concepts and " +"learned how to:" msgstr "この章では、関数型プログラミングの新しい概念を幾つも導入しました。" #. type: Bullet: '- ' #: text/chapter3.md:733 +#, fuzzy +#| msgid "" +#| "How to use the interactive mode PSCi to experiment with functions and " +#| "test ideas." 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を使用して、関数を調べるなどの思いついたことを試す方法" #. type: Bullet: '- ' #: text/chapter3.md:733 -msgid "" -"The role of types as both a correctness tool, and an implementation tool." +#, fuzzy +#| 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 -msgid "" -"The use of curried functions to represent functions of multiple arguments." +#, fuzzy +#| 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 -msgid "Creating programs from smaller components by composition." +#, fuzzy +#| msgid "Creating programs from smaller components by composition." +msgid "Create programs from smaller components by composition." msgstr "関数合成で小さな部品を組み合わせてのプログラムの構築" #. type: Bullet: '- ' #: text/chapter3.md:733 -msgid "Structuring code neatly using `where` expressions." +#, fuzzy +#| msgid "Structuring code neatly using `where` expressions." +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." +#, fuzzy +#| msgid "How to avoid null values by using the `Maybe` type." +msgid "Avoid null values by using the `Maybe` type." msgstr "`Maybe`型を使用してnull値を回避する方法" #. type: Bullet: '- ' #: text/chapter3.md:733 +#, fuzzy +#| msgid "" +#| "Using techniques like eta conversion and function composition to refactor " +#| "code into a clear specification." 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 "" "イータ変換や関数合成のような手法を利用した、よりわかりやすいコードへの再構成" @@ -16673,8 +18473,9 @@ msgstr "次の章からは、これらの考えかたに基づいて進めてい #. type: Title # #: text/chapter4.md:1 -#, no-wrap -msgid "Recursion, Maps And Folds" +#, fuzzy, no-wrap +#| msgid "Recursion, Maps And Folds" +msgid "Recursion, Maps, And Folds" msgstr "再帰、マップ、畳み込み" #. type: Plain text @@ -16690,10 +18491,15 @@ msgstr "" #. type: Plain text #: text/chapter4.md:8 +#, fuzzy +#| 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`." 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`といった特別な場合" @@ -16701,10 +18507,16 @@ msgstr "" #. type: Plain text #: text/chapter4.md:10 +#, fuzzy +#| 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 " +#| "represented by a model of a filesystem." 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 "" "この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用" @@ -16805,10 +18617,15 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factorial}}\n" #. type: Plain text #: text/chapter4.md:38 +#, fuzzy +#| 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." 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 "" "部分問題へ問題を分割することによって階乗関数がどのように計算されるかがわかり" "ます。より小さい数へと階乗を計算していくということです。ゼロに到達すると、答" @@ -16816,8 +18633,10 @@ msgstr "" #. type: Plain text #: text/chapter4.md:40 -msgid "" -"Here is another common example, which computes the _Fibonacci function_:" +#, fuzzy +#| msgid "" +#| "Here is another common example, which computes the _Fibonacci function_:" +msgid "Here is another common example that computes the _Fibonacci function_:" msgstr "" "次は、 _フィボナッチ関数_ (Fibonacci function) を計算するという、これまたよく" "ある例です。" @@ -16844,15 +18663,10 @@ 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." -msgstr "" -"なお上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実" -"装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。パ" -"ターン照合の技法は後の章でお話しします。" +#, fuzzy, 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." +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`を使う代わりにパターン照合を使うものでしょう。パターン照合の技法は後の章でお話しします。" #. type: Title ## #: text/chapter4.md:49 @@ -16903,10 +18717,16 @@ msgstr "" #. type: Plain text #: text/chapter4.md:65 +#, fuzzy +#| 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 length that is one more than the length of its tail." 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`式を使って" @@ -16917,12 +18737,19 @@ msgstr "" #. type: Plain text #: text/chapter4.md:67 +#, fuzzy +#| 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`." 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`" @@ -16931,18 +18758,27 @@ msgstr "" #. type: Plain text #: text/chapter4.md:69 +#, fuzzy +#| 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:" 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 +#, fuzzy +#| msgid "" +#| "(Easy) Write a recursive function `isEven` which returns `true` if and " +#| "only if its input is an even integer." 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`に返すような再帰関数を" @@ -16950,8 +18786,14 @@ msgstr "" #. type: Bullet: ' 2. ' #: text/chapter4.md:74 -msgid "" -"(Medium) Write a recursive function `countEven` which counts the number of " +#, fuzzy +#| msgid "" +#| "(Medium) Write a recursive function `countEven` which 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." +msgid "" +"(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 "" @@ -16968,11 +18810,17 @@ msgstr "マップ" #. type: Plain text #: text/chapter4.md:78 +#, fuzzy +#| 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)." 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つです。この関数を使うと、配列の各要素に順" "番に関数を適用することで、配列の要素を変換できます。そのため、配列の*内容*は" @@ -16980,8 +18828,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:80 +#, fuzzy +#| msgid "" +#| "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_." 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 "" @@ -17012,8 +18865,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:92 +#, fuzzy +#| msgid "" +#| "Notice how `map` is used - we provide a function which should be \"mapped " +#| "over\" the array in the first argument, and the array itself in its " +#| "second." 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" @@ -17056,8 +18914,9 @@ 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" +#, fuzzy, 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" +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) @@ -17126,8 +18985,9 @@ 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" +#, fuzzy, 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" @@ -17364,11 +19224,17 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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`は(相異なる型の可能性がある)値からの値への関数を引数に" @@ -17451,9 +19317,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:229 +#, fuzzy +#| msgid "" +#| "We can perform this computation using an array comprehension. We will do " +#| "so in steps, using PSCi as our interactive development environment." 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 +19499,10 @@ 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." -msgstr "" -"*補足*:`map`と`concatMap`が _配列内包表記_ を書けるようにしているように、" -"もっと一般的な演算子である`map`と`bind`は _モナド内包表記_ (monad " -"comprehensions) と呼ばれているものを書けるようにします。本書の後半では _モナ" -"ド_ (monad) の例をたっぷり見ていくことになりますが、この章では配列のみを考え" -"ます。" +#, fuzzy, 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." +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) の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。" #. type: Plain text #: text/chapter4.md:294 @@ -17656,17 +19518,26 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factors}}\n" #. type: Plain text #: text/chapter4.md:300 +#, fuzzy +#| msgid "" +#| "The keyword `do` introduces a block of code which uses do notation. The " +#| "block consists of expressions of a few types:" 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記法を使うコードのブロックを導入します。このブロックは幾つ" "かの種類の式で構成されています。" #. type: Bullet: '- ' #: text/chapter4.md:304 +#, fuzzy +#| msgid "" +#| "Expressions which 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." 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 "" @@ -17676,8 +19547,13 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter4.md:304 +#, fuzzy +#| msgid "" +#| "Expressions which 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]`." 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 "" @@ -17687,7 +19563,10 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter4.md:304 -msgid "Expressions which give names to expressions, using the `let` keyword." +#, fuzzy +#| 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 @@ -17719,10 +19598,14 @@ msgstr "" #. type: Plain text #: text/chapter4.md:315 +#, fuzzy +#| 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`:" 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`の代わりにこの形式も使うようにできます。" @@ -17835,9 +19718,14 @@ 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 " +#, fuzzy +#| 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 `false`, then its result is empty." +msgid "" +"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`に評価される式を渡された場合、単一の要素を持つ配列を返" @@ -17864,9 +19752,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 +#, fuzzy +#| msgid "" +#| "(Easy) Write a function `isPrime` which tests if its integer argument is " +#| "prime or not. _Hint_: Use the `factors` function." 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" @@ -17874,11 +19766,17 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 +#, fuzzy +#| 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." 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" @@ -17887,10 +19785,17 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 -msgid "" -"(Medium) Write a function `triples :: Int -> Array (Array Int)` which takes " +#, fuzzy +#| msgid "" +#| "(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 triple_ is an array of numbers `[a, b, c]` such that `a² + " +#| "b² = c²`. _Hint_: Use the `guard` function in an array comprehension." +msgid "" +"(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 "" @@ -17902,12 +19807,19 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 +#, fuzzy +#| 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." 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`を定義して" @@ -17925,17 +19837,25 @@ msgstr "畳み込み" #. type: Plain text #: text/chapter4.md:373 +#, fuzzy +#| msgid "" +#| "Left and right folds over arrays provide another class of interesting " +#| "functions which can be implemented using recursion." 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 +#, fuzzy +#| msgid "" +#| "Start by importing the `Data.Foldable` module, and inspecting the types " +#| "of the `foldl` and `foldr` functions using PSCi:" 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`関数の" @@ -17963,10 +19883,15 @@ msgstr "" #. type: Plain text #: text/chapter4.md:387 +#, fuzzy +#| 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:" 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 assume that PSCi has given the following (more specific) " +"answer:" msgstr "" "これらの型は、現在興味があるものよりも一般化されています。\n" "この章の目的に対して、PSCiは以下の(より具体的な)答えをくれていると考えてお" @@ -17990,9 +19915,14 @@ msgstr "" #. 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\", " +#, fuzzy +#| 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\", which will accumulate a result as we traverse the array." +msgid "" +"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" @@ -18012,8 +19942,9 @@ 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" +#, fuzzy, 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" +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 "実際にこれらの関数の動きを見てみましょう。`foldl`を使用して数の配列の和を求めてみます。型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。ここでは、次の要素を累積器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累積器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。最初の引数としては、加算演算子を使用できますし、累積器の初期値はゼロになります。\n" #. type: Fenced code block (text) @@ -18047,10 +19978,15 @@ msgstr "" #. type: Plain text #: text/chapter4.md:415 +#, fuzzy +#| 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:" 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" @@ -18089,7 +20025,9 @@ 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:" +#, fuzzy +#| msgid "whereas the right fold is equivalent to this:" +msgid "Whereas the right fold is equivalent to this:" msgstr "それに対し、右畳み込みは以下に相当します。" #. type: Fenced code block (text) @@ -18106,9 +20044,14 @@ 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 " +#, fuzzy +#| msgid "" +#| "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." +msgid "" +"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" @@ -18117,7 +20060,9 @@ msgstr "" #. type: Plain text #: text/chapter4.md:441 -msgid "It is easy to verify this problem, with the following code in PSCi:" +#, fuzzy +#| 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) @@ -18152,18 +20097,27 @@ msgstr "" #. type: Plain text #: text/chapter4.md:458 +#, fuzzy +#| 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." 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 +#, fuzzy +#| msgid "" +#| "PureScript provides a partial solution to this problem in the form of " +#| "_tail recursion optimization_." 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) の形でこの問題に" @@ -18171,30 +20125,30 @@ msgstr "" #. 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." +#, fuzzy, 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." +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)パッケージのドキュメントを参照してみてください。" #. 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." +#, fuzzy +#| 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." +msgid "" +"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 "" "末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 _末尾位置_ " "(tail position) にある関数の再帰的な呼び出しは、スタックフレームが確保されな" @@ -18228,9 +20182,13 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}}\n #. type: Plain text #: text/chapter4.md:474 +#, fuzzy +#| msgid "" +#| "Notice that the recursive call to `factorialTailRec` is the last thing " +#| "that happens in this function - it is in tail position." 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`への再帰呼び出しは、この関数の中で起こる最後のものである、つまり末尾位" "置にあることに注意してください。" @@ -18243,12 +20201,18 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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) を使用する方法があります。累積器引数は関数に追加さ" @@ -18257,8 +20221,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:480 +#, fuzzy +#| msgid "" +#| "For example, consider again the `length` function presented in the " +#| "beginning of the chapter:" 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`関数を再考しましょう。" @@ -18299,11 +20267,17 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}}\n" #. type: Plain text #: text/chapter4.md:496 +#, fuzzy +#| 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." 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 "" "ここでは、配列を逆転させる作業を補助関数`length'`に委譲しています。`length'`" "は末尾再帰です。その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。こ" @@ -18312,11 +20286,17 @@ msgstr "" #. type: Plain text #: text/chapter4.md:498 +#, fuzzy +#| 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." 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'`に着目しましょう。この" "関数は必然的に累積器引数を使って追加の状態……これは部分的な結果です……を保持し" @@ -18325,9 +20305,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:500 +#, fuzzy +#| msgid "" +#| "Note also that while we might think of the accumulator as \"state\", " +#| "there is no direct mutation going on." 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 "" "累積器を「状態」と考えることもできますが、直接には変更されているわけではない" "ことにも注意してください。" @@ -18340,15 +20324,26 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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" @@ -18440,10 +20435,15 @@ msgstr "仮想ファイルシステム" #. type: Plain text #: text/chapter4.md:531 +#, fuzzy +#| 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." 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" @@ -18452,8 +20452,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:533 +#, fuzzy +#| 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:" +"The `Data.Path` module defines an API for a virtual filesystem as follows:" msgstr "" "`Data.Path`モジュールでは、次のように仮想ファイルシステムのAPIが定義されてい" "ます。" @@ -18480,9 +20484,12 @@ msgstr "`filename`関数は`Path`のファイル名を返します。" #. type: Bullet: '- ' #: text/chapter4.md:540 +#, fuzzy +#| 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` which represents a " -"file." +"The `size` function returns the file size for a `Path` representing a file." msgstr "`size`関数は`Path`が示すファイルの大きさを返します。" #. type: Bullet: '- ' @@ -18557,8 +20564,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:573 +#, fuzzy +#| msgid "" +#| "The `Test.Examples` module defines functions which 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." 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 "" @@ -18574,8 +20586,12 @@ msgstr "全てのファイルの一覧" #. type: Plain text #: text/chapter4.md:577 +#, fuzzy +#| msgid "" +#| "Let's write a function which performs a deep enumeration of all files " +#| "inside a directory. This function will have the following type:" 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 "" "それでは、ディレクトリの中身を含めた全てのファイルを列挙する関数を書いてみま" @@ -18589,12 +20605,19 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_signature}} #. type: Plain text #: text/chapter4.md:583 +#, fuzzy +#| 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." 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`を適用すると、それぞれ" @@ -18614,15 +20637,12 @@ 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." +#, fuzzy, 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." +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" +"連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させることができます。" #. type: Plain text #: text/chapter4.md:593 @@ -18659,12 +20679,19 @@ msgstr "" #. type: Plain text #: text/chapter4.md:606 +#, fuzzy +#| 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." 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" @@ -18685,8 +20712,12 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}}\n" #. type: Plain text #: text/chapter4.md:614 +#, fuzzy +#| msgid "" +#| "Try out the new version in PSCi - you should get the same result. I'll " +#| "let you decide which version you find clearer." 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で新しいコードを試してみてください。同じ結果が返ってくるはずです。どちら" @@ -18740,10 +20771,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:630 -#, no-wrap +#, fuzzy, 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" 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" @@ -18751,14 +20785,22 @@ msgstr "" #. 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." +#, fuzzy +#| 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." +msgid "" +"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" @@ -18775,8 +20817,13 @@ msgstr "パターン照合" #. type: Plain text #: text/chapter5.md:6 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -18786,10 +20833,15 @@ msgstr "" #. type: Plain text #: text/chapter5.md:8 +#, fuzzy +#| 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." 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 "" "パターン照合は関数型プログラミングにおける一般的な手法で、複数の場合に実装を" "分解することにより、開発者は水面下では複雑な動作をする関数を簡潔に書くことが" @@ -18797,19 +20849,29 @@ msgstr "" #. type: Plain text #: text/chapter5.md:10 +#, fuzzy +#| 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." 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の型システムの機能であり、型のある言語において同等" "の水準の表現力を可能にしています。パターン照合とも密接に関連しています。" #. type: Plain text #: text/chapter5.md:12 +#, fuzzy +#| 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." 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 "" "この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラ" "フィックスを描画し操作するためのライブラリを書くことです。" @@ -18824,8 +20886,13 @@ msgstr "" #. type: Plain text #: text/chapter5.md:18 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -18864,11 +20931,17 @@ msgstr "{{#include ../exercises/chapter5/src/Data/Picture.purs:picture_import_as #. type: Plain text #: text/chapter5.md:32 +#, fuzzy +#| 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." 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`の" "ように*修飾名*を使ったときに限定されます。重複したインポートを避けたり、どの" @@ -18876,13 +20949,11 @@ msgstr "" #. 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." +#, fuzzy, 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." +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" +"*補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありません。\n" "`import Math as M`などのより短い名前にできますし、かなりよく見掛けます。" #. type: Title ## @@ -18893,8 +20964,12 @@ msgstr "単純なパターン照合" #. type: Plain text #: text/chapter5.md:38 +#, fuzzy +#| msgid "" +#| "Let's begin by looking at an example. Here is a function which computes " +#| "the greatest common divisor of two integers using pattern matching:" 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" @@ -18909,12 +20984,20 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcd}}\n" #. type: Plain text #: text/chapter5.md:44 +#, fuzzy +#| 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." 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" "その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が" @@ -18924,11 +21007,21 @@ msgstr "" #. type: Plain text #: text/chapter5.md:46 +#, fuzzy +#| 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 " +#| "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 " +#| "match their inputs determines the return value." 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 " @@ -18976,11 +21069,18 @@ msgstr "それ以外の場合、関数は最後の行の式を評価して返し #. type: Plain text #: text/chapter5.md:54 -msgid "" -"Note that patterns can bind values to names - each line in the example binds " +#, fuzzy +#| msgid "" +#| "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." +msgid "" +"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`という名前の何れかまたは両方に入力された値を束縛して" @@ -19018,22 +21118,31 @@ msgstr "単純なパターンには他にも種類があります。" #. type: Bullet: '- ' #: text/chapter5.md:66 -msgid "`Number`, `String`, `Char` and `Boolean` literals" +#, fuzzy +#| 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 +#, fuzzy +#| msgid "" +#| "Wildcard patterns, indicated with an underscore (`_`), which match any " +#| "argument, and which do not bind any names." 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 +#, fuzzy +#| msgid "" +#| "Here are two more examples which demonstrate using these simple patterns:" msgid "" -"Here are two more examples which demonstrate using these simple patterns:" +"Here are two more examples that demonstrate using these simple patterns:" msgstr "ここではこれらの単純なパターンを使用して、もう2つ例を示します。" #. type: Fenced code block (haskell) @@ -19055,15 +21164,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" +#, fuzzy, 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" +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" #. 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 " +#, fuzzy +#| 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 rewritten to use a guard:" +msgid "" +"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" @@ -19077,11 +21192,17 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcdV2}}\n" #. type: Plain text #: text/chapter5.md:88 +#, fuzzy +#| 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`:" 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`を使っており、" @@ -19105,8 +21226,12 @@ msgstr "" #. type: Plain text #: text/chapter5.md:98 +#, fuzzy +#| msgid "" +#| "As this example demonstrates, guards appear on the left of the equals " +#| "symbol, separated from the list of patterns by a pipe character (`|`)." 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 "" "この例が示すように、ガードは等号の左側に現れ、パイプ文字 (`|`) でパターンのリ" @@ -19182,9 +21307,13 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}}\n" #. type: Plain text #: text/chapter5.md:114 +#, fuzzy +#| msgid "" +#| "Here is another function which matches arrays of length five, binding " +#| "each of its five elements in a different way:" 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つの要素をそれぞれ違った方法で束縛" "しています。" @@ -19197,11 +21326,17 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:takeFive}}\n" #. type: Plain text #: text/chapter5.md:120 +#, fuzzy +#| 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:" 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" @@ -19243,12 +21378,21 @@ msgstr "" #. type: Plain text #: text/chapter5.md:138 -msgid "" -"Array literal patterns allow us to match arrays of a fixed length, but " +#, fuzzy +#| msgid "" +#| "Array literal patterns allow us to match arrays of a fixed length, but " +#| "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 structures exist which provide improved asymptotic " +#| "performance for different operations." +msgid "" +"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 "" @@ -19268,7 +21412,9 @@ msgstr "レコードパターンと行多相" #. type: Plain text #: text/chapter5.md:142 -msgid "_Record patterns_ are used to match - you guessed it - records." +#, fuzzy +#| 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 @@ -19282,9 +21428,14 @@ 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` " +#, fuzzy +#| 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` " +#| "respectively:" +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`, " "respectively:" msgstr "" "例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレ" @@ -19352,11 +21503,18 @@ 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:" +#, fuzzy +#| 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:" +msgid "" +"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`であるようなフィールド " @@ -19405,7 +21563,9 @@ msgstr "> showPerson p = p.last <> \", \" <> p.first\n" #. type: Plain text #: text/chapter5.md:187 -msgid "and PSCi would have inferred the same type." +#, fuzzy +#| msgid "and PSCi would have inferred the same type." +msgid "And PSCi would have inferred the same type." msgstr "この場合も、 PSCiは先ほどと同じ型を推論するでしょう。" #. type: Title ## @@ -19416,11 +21576,17 @@ msgstr "レコード同名利用" #. type: Plain text #: text/chapter5.md:191 +#, fuzzy +#| 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:" 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`という名前の値に束縛していたのでした。別の方法として、フィールド名自体を再" @@ -19460,7 +21626,9 @@ 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." +#, fuzzy +#| msgid "This may improve readability of code in some circumstances." +msgid "This may improve the readability of code in some circumstances." msgstr "こうすると、状況によってはコードの可読性向上に役立ちます。" #. type: Title ## @@ -19471,12 +21639,20 @@ msgstr "入れ子になったパターン" #. type: Plain text #: text/chapter5.md:209 +#, fuzzy +#| 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." 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 "" "配列パターンとレコードパターンはどちらも小さなパターンを組み合わせることで大" "きなパターンを構成しています。これまでの例ではほとんどの場合で配列パターンと" @@ -19529,11 +21705,16 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}}\n" #. type: Plain text #: text/chapter5.md:227 +#, fuzzy +#| 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." 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つの要素を含んでいなければ、たとえ整列され" @@ -19550,9 +21731,14 @@ 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 " +#, fuzzy +#| msgid "" +#| "(Medium) What is the most general type of the `sameCity` function, taking " +#| "into account row polymorphism? What about the `livesInLA` function " +#| "defined above? _Note_: There is no test for this exercise." +msgid "" +"(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" @@ -19561,10 +21747,16 @@ 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 " +#, fuzzy +#| 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 function should have type `forall a. a -> Array a -> a`" +msgid "" +"(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要素の配列の唯一のメンバーを抽出する関数" @@ -19580,9 +21772,17 @@ msgstr "Case式" #. type: Plain text #: text/chapter5.md:237 +#, fuzzy +#| 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, 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." 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 " @@ -19596,8 +21796,12 @@ msgstr "" #. type: Plain text #: text/chapter5.md:239 +#, fuzzy +#| msgid "" +#| "Here is an example. This function computes \"longest zero suffix\" of an " +#| "array (the longest suffix which sums to zero):" 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" @@ -19634,11 +21838,18 @@ msgstr "" #. type: Plain text #: text/chapter5.md:257 +#, fuzzy +#| 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." 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つの場合に分けるためにま" @@ -19653,11 +21864,16 @@ msgstr "パターン照合の失敗と部分関数" #. type: Plain text #: text/chapter5.md:261 +#, fuzzy +#| 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_." 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" @@ -19682,9 +21898,14 @@ msgstr "" #. type: Plain text #: text/chapter5.md:271 +#, fuzzy +#| 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 " +#| "argument, we will see an error at runtime:" 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`にのみ照合しま" @@ -19705,9 +21926,13 @@ msgstr "" #. type: Plain text #: text/chapter5.md:279 +#, fuzzy +#| msgid "" +#| "Functions which return a value for any combination of inputs are called " +#| "_total_ functions, and functions which do not are called _partial_." 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) であると呼ばれます。" @@ -19731,11 +21956,19 @@ msgstr "" #. type: Plain text #: text/chapter5.md:283 +#, fuzzy +#| 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 " +#| "`unsafePartial` function above, then the compiler would generate the " +#| "following error:" 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 "" @@ -19799,16 +22032,22 @@ 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" +#, fuzzy, 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" +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 "本書ではのちに`=>`記号を含むいろいろな型を見ることになります(これらは*型クラス*に関連しています)。しかし、今のところは、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。\n" #. type: Plain text #: text/chapter5.md:310 +#, fuzzy +#| 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):" 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 "" "コンパイラは、定義されたパターンが _冗長_ であることを検出した場合(前の方に" "定義されたパターンのみに一致する場合)でも警告を生成します。" @@ -19846,12 +22085,10 @@ 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`." -msgstr "" -"*補足*:PSCiは警告を表示しないので、この例を再現するには、この関数をファイル" -"として保存し、 `pulp build`を使ってコンパイルします。" +#, fuzzy, 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`." +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`を使ってコンパイルします。" #. type: Title ## #: text/chapter5.md:328 @@ -19895,11 +22132,17 @@ msgstr "" #. type: Plain text #: text/chapter5.md:337 +#, fuzzy +#| 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." 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`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に" @@ -19908,10 +22151,16 @@ msgstr "" #. type: Plain text #: text/chapter5.md:339 +#, fuzzy +#| 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." 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`に新たな操作を定" @@ -19936,10 +22185,17 @@ msgstr "" #. type: Plain text #: text/chapter5.md:349 +#, fuzzy +#| 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 `Rectangle`, or a `Line`, or `Text`. There are no other " +#| "ways to construct a value of type `Shape`." 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 "" @@ -19951,10 +22207,18 @@ msgstr "" #. type: Plain text #: text/chapter5.md:351 +#, fuzzy +#| 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 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." 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." @@ -19995,9 +22259,14 @@ msgstr "" #. type: Plain text #: text/chapter5.md:361 +#, fuzzy +#| 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 defining ADTs with `data` or type aliases with `type`." 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" @@ -20126,9 +22395,13 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:397 +#, fuzzy +#| msgid "" +#| "(Easy) Write a function `circleAtOrigin` which constructs a `Circle` (of " +#| "type `Shape`) centered at the origin with radius `10.0`." 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" @@ -20136,8 +22409,12 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:397 +#, fuzzy +#| msgid "" +#| "(Medium) Write a function `doubleScaleAndCenter` which scales the size of " +#| "a `Shape` by a factor of `2.0` and centers it at the origin." 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`" @@ -20312,8 +22589,13 @@ msgstr "newtype CouldError err a = CouldError (Either err a)\n" #. type: Plain text #: text/chapter5.md:456 +#, fuzzy +#| msgid "" +#| "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:" 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 "" @@ -20328,14 +22610,23 @@ 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 " +#, fuzzy +#| msgid "" +#| "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." +msgid "" +"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`の例でそうだったよう" @@ -20397,7 +22688,9 @@ msgstr "" #. type: Plain text #: text/chapter5.md:480 -msgid "Define a type synonym for a `Picture` - just an array of `Shape`s:" +#, fuzzy +#| 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`という型同義語を定義しておきま" "す。" @@ -20563,20 +22856,24 @@ msgstr "" #. type: Plain text #: text/chapter5.md:534 +#, fuzzy 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 +#, fuzzy +#| msgid "" +#| "Finally, we covered _row polymorphism_, a powerful type of abstraction " +#| "which allows many idiomatic JavaScript functions to be given a type." 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 "" "最後に強力な抽象化である _行多相_ を扱いました。これにより多くの既存の" @@ -20603,18 +22900,28 @@ msgstr "型クラス" #. type: Plain text #: text/chapter6.md:6 +#, fuzzy +#| msgid "" +#| "This chapter will introduce a powerful form of abstraction which is " +#| "enabled by PureScript's type system - type classes." 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の型システムによって可能になる強力な抽象化の手法であ" "る、型クラスを導入します。" #. type: Plain text #: text/chapter6.md:8 +#, fuzzy +#| 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 complex data structures without having to think directly about " +#| "the structure of the data itself." 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 "" @@ -20676,7 +22983,9 @@ msgstr "`either`: 非交和を表す `Either`データ型が定義されてい #. type: Bullet: '- ' #: text/chapter6.md:24 -msgid "`strings`, which defines functions which operate on strings." +#, fuzzy +#| msgid "`strings`, which defines functions which operate on strings." +msgid "`strings`, which defines functions that operate on strings." msgstr "`strings`: 文字列を操作する関数が定義されています。" #. type: Bullet: '- ' @@ -20773,8 +23082,14 @@ msgstr "" #. type: Plain text #: text/chapter6.md:51 -msgid "" -"This code declares a type class instance called `showBoolean` - in " +#, fuzzy +#| msgid "" +#| "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_." +msgid "" +"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_." @@ -20852,12 +23167,19 @@ msgstr "" #. type: Plain text #: text/chapter6.md:82 +#, fuzzy +#| 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`." 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`を使って" @@ -20922,10 +23244,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:109 +#, fuzzy +#| 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." 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がこの型を推論できなかったということです。このエ" @@ -20933,8 +23260,12 @@ msgstr "" #. type: Plain text #: text/chapter6.md:111 +#, fuzzy +#| msgid "" +#| "We can annotate the expression with a type, using the `::` operator, so " +#| "that PSCi can choose the correct type class instance:" 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が正しい型クラスインスタン" @@ -21053,9 +23384,13 @@ msgstr "Eq" #. type: Plain text #: text/chapter6.md:145 +#, fuzzy +#| msgid "" +#| "The `Eq` type class defines the `eq` function, which tests two values for " +#| "equality. The `==` operator is actually just an alias for `eq`." 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`の別名にすぎません。" @@ -21072,9 +23407,13 @@ msgstr "" #. type: Plain text #: text/chapter6.md:152 +#, fuzzy +#| 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." 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つの引数は同じ型を持つ必要があります。" @@ -21108,8 +23447,9 @@ 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" +#, fuzzy, 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" +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`型クラスは順序付け可能な型に対して2つの値を比較する `compare`関数を定義します。比較演算子 `<`、 `>`と、その仲間の厳密な大小比較ではない`<=`、 `>=`も、`compare`を使って定義されます。\n" #. type: Plain text @@ -21137,25 +23477,35 @@ msgstr "" #. type: Plain text #: text/chapter6.md:177 +#, fuzzy +#| msgid "" +#| "The `compare` function compares two values, and returns an `Ordering`, " +#| "which has three alternatives:" 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つの値のうち何れかを返します。" #. type: Bullet: '- ' #: text/chapter6.md:181 -msgid "`LT` - if the first argument is less than the second." +#, fuzzy +#| msgid "`LT` - if the first argument is less than the second." +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." +#, fuzzy +#| msgid "`EQ` - if the first argument is equal to the second." +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." +#, fuzzy +#| msgid "`GT` - if the first argument is greater than the second." +msgid "`GT` – if the first argument is greater than the second." msgstr "`GT`- 最初の引数が2番目の値より大きいとき" #. type: Plain text @@ -21187,9 +23537,15 @@ msgstr "Field" #. type: Plain text #: text/chapter6.md:195 +#, fuzzy +#| msgid "" +#| "The `Field` type class identifies those types which support numeric " +#| "operators such as addition, subtraction, multiplication and division. It " +#| "is provided to abstract over those operators, so that they can be reused " +#| "where appropriate." 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 "" @@ -21198,15 +23554,11 @@ msgstr "" #. 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." +#, fuzzy, 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." +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" "型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。" #. type: Fenced code block (haskell) @@ -21217,9 +23569,18 @@ msgstr "class EuclideanRing a <= Field a\n" #. type: Plain text #: text/chapter6.md:203 +#, fuzzy +#| 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 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`." 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 " @@ -21279,10 +23640,14 @@ msgstr "" #. type: Plain text #: text/chapter6.md:216 +#, fuzzy +#| msgid "" +#| "Strings form a semigroup under regular string concatenation, and so do " +#| "arrays. Several other standard instances are provided by the `prelude` " +#| "package." 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`パッケージで提供されています。" @@ -21319,11 +23684,17 @@ msgstr "ここでも文字列や配列はモノイドの簡単な例になって #. type: Plain text #: text/chapter6.md:229 +#, fuzzy +#| 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:" 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" @@ -21415,11 +23786,17 @@ msgstr "" #. type: Plain text #: text/chapter6.md:260 +#, fuzzy +#| 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." 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" @@ -21429,8 +23806,9 @@ msgstr "" #. 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" +#, fuzzy, 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" @@ -21458,9 +23836,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:273 +#, fuzzy +#| 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 in an array of integers, we see that the results of " +#| "`show`ing each integer have been concatenated into a single `String`." 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 "" @@ -21470,8 +23854,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:275 -msgid "" -"But arrays are not the only types which are foldable. `foldable-traversable` " +#, fuzzy +#| msgid "" +#| "But arrays are not the only types which 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_." +msgid "" +"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_." @@ -21484,16 +23875,25 @@ msgstr "" #. type: Title ### #: text/chapter6.md:276 -#, no-wrap -msgid "Functor, and Type Class Laws" +#, fuzzy, 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 " +#, fuzzy +#| msgid "" +#| "The Prelude also defines a collection of type classes which enable a " +#| "functional style of programming with side-effects in PureScript: " +#| "`Functor`, `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:" +msgid "" +"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 "" @@ -21600,10 +24000,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:312 +#, fuzzy +#| 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." 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つの関数の合成で構造を写すのと同じだ、と言っています。" @@ -21756,9 +24161,14 @@ msgstr "型クラス制約" #. type: Plain text #: text/chapter6.md:348 +#, fuzzy +#| 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 equal, by using equality defined using an `Eq` type class instance." 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" @@ -21886,8 +24296,9 @@ msgstr "" #. 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" +#, fuzzy, 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" +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`と注釈を付けることが考えられますが、最も一般的な型が`Semiring`で動作するため、PSCiでは`Int`と `Number`の両方で関数を実行させることができます。\n" #. type: Title ## @@ -21932,15 +24343,16 @@ msgstr "" " ...\n" #. type: Plain text -#: text/chapter6.md:402 -#, 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" +#: text/chapter6.md:401 +#, fuzzy, 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" +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 +24362,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 +24380,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 +24399,16 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:421 -#, 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" +#: text/chapter6.md:420 +#, fuzzy, 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" #. 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 +24417,25 @@ 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 +#, fuzzy +#| 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:" 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 +24447,14 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:433 -#, no-wrap -msgid " Write an `Ord` instance for `Extended a` which reuses the `Ord` instance for `a`.\n" +#: text/chapter6.md:432 +#, fuzzy, 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,10 +24463,15 @@ msgstr "" "*手掛かり*:配列への`Foldable`インスタンスを再利用してください。" #. type: Bullet: '1. ' -#: text/chapter6.md:437 +#: text/chapter6.md:436 +#, fuzzy +#| 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 includes an extra element at the front:" 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`のインスタンスを持って" @@ -22056,7 +24479,7 @@ msgstr "" "なコンテナ型を作ることができます。" #. type: Plain text -#: text/chapter6.md:441 +#: text/chapter6.md:440 #, no-wrap msgid "" " ```haskell\n" @@ -22068,7 +24491,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 +24500,7 @@ msgstr "" " この `OneMore f`の `Foldable`インスタンスを書いてみましょう。\n" #. type: Plain text -#: text/chapter6.md:448 +#: text/chapter6.md:447 #, no-wrap msgid "" " ```haskell\n" @@ -22091,16 +24514,20 @@ msgstr "" " ```\n" #. type: Bullet: '1. ' -#: text/chapter6.md:450 +#: text/chapter6.md:449 +#, fuzzy +#| msgid "" +#| "(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function " +#| "which removes duplicate `Shape`s from an array using the `nubEq` function." 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,16 +24536,22 @@ msgstr "" "`dedupShapes`とほぼ同じですが、より効率の良い`nub`関数を使います。" #. type: Title ## -#: text/chapter6.md:453 -#, no-wrap -msgid "Multi Parameter Type Classes" +#: text/chapter6.md:452 +#, fuzzy, no-wrap +#| msgid "Multi Parameter Type Classes" +msgid "Multi-Parameter Type Classes" msgstr "多変数型クラス" #. type: Plain text -#: text/chapter6.md:456 +#: text/chapter6.md:455 +#, fuzzy +#| 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 " +#| "parameterized by _zero or more_ type arguments." 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" @@ -22126,12 +24559,12 @@ msgstr "" "とができます。" #. 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 +24598,14 @@ msgstr "" " uncons = String.uncons\n" #. type: Plain text -#: text/chapter6.md:477 +#: text/chapter6.md:476 +#, fuzzy +#| msgid "" +#| "The `Stream` module defines a class `Stream` which identifies types which " +#| "look like streams of elements, where elements can be pulled from the " +#| "front of the stream using the `uncons` function." 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 +24614,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 +24625,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 +24636,22 @@ msgstr "" "と、文字列から最初の文字を取り除くような文字列のインスタンスです。" #. type: Plain text -#: text/chapter6.md:483 +#: text/chapter6.md:482 +#, fuzzy +#| 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 elements of a stream:" 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`に結果を累積する関数は次のようになります。" #. type: Fenced code block (haskell) -#: text/chapter6.md:484 +#: text/chapter6.md:483 #, no-wrap msgid "" "import Prelude\n" @@ -22230,7 +24673,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,15 +24682,21 @@ 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 +#, fuzzy +#| msgid "" +#| "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:" 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:" @@ -22258,18 +24707,18 @@ 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 "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 "これはやや複雑なエラーメッセージを出力します。" #. type: Fenced code block (text) -#: text/chapter6.md:507 +#: text/chapter6.md:506 #, no-wrap msgid "" "The inferred type\n" @@ -22285,7 +24734,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 +24744,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 +24752,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 +24772,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,11 +24784,16 @@ msgstr "" "てはなりません。" #. type: Plain text -#: text/chapter6.md:532 +#: text/chapter6.md:531 +#, fuzzy +#| 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:" 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" @@ -22347,7 +24801,7 @@ 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" @@ -22357,13 +24811,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,7 +24826,7 @@ msgstr "" "のに充分です。" #. type: Fenced code block (text) -#: text/chapter6.md:542 +#: text/chapter6.md:541 #, no-wrap msgid "" "> :type genericTail\n" @@ -22388,39 +24842,55 @@ msgstr "" "(Just \"esting\")\n" #. type: Plain text -#: text/chapter6.md:551 +#: text/chapter6.md:550 +#, fuzzy +#| msgid "" +#| "Functional dependencies can be quite useful when using multi-parameter " +#| "type classes to design certain APIs." 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を設計する場合、関数従属性は非常に有用で" "す。" #. 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 +#, fuzzy +#| 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." 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 +#, fuzzy +#| 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:" 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`を例に取りましょ" @@ -22428,7 +24898,7 @@ 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" @@ -22440,7 +24910,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 +24922,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 +24938,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 +24947,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 +24957,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 +24967,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 +24984,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 +25000,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 +25017,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,31 +25025,53 @@ msgstr "" "そしてクラス定義で逆向きの太い矢印 (`<=`) を使って上位クラス関係を示します。\n" #. type: Plain text -#: text/chapter6.md:604 +#: text/chapter6.md:603 +#, fuzzy +#| 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 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." 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`クラスを使いたいことが多いでしょうから。" - -#. type: Plain text -#: text/chapter6.md:606 +"`compare`関数が2つの値の大小を付けられないと報告した時は、それらが実は同値で" +"あるかどうかを判定するために `Eq`クラスを使いたいことが多いでしょうから。" + +#. type: Plain text +#: text/chapter6.md:605 +#, fuzzy +#| 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 superclass relationship between `Eq` and " +#| "`Ord`." 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 "" "一般に、下位クラスの法則が上位クラスのメンバに言及しているとき、上位クラス関" @@ -22592,21 +25084,32 @@ msgstr "" "法則のレベルでのこの関係は`Eq`と`Ord`の間の上位クラス関係の正当性を示します。" #. type: Plain text -#: text/chapter6.md:608 +#: text/chapter6.md:607 +#, fuzzy +#| 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." 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" "下位クラスの全てのメンバは、上位クラスのメンバでもあるということです。" #. type: Bullet: '1. ' -#: text/chapter6.md:612 +#: text/chapter6.md:611 +#, fuzzy +#| 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 function in PSCi using `unsafePartial`. _Hint_: Use the " +#| "`maximum` function from `Data.Foldable`." 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 "" @@ -22616,16 +25119,20 @@ msgstr "" "使います。" #. type: Bullet: '1. ' -#: text/chapter6.md:614 +#: text/chapter6.md:613 +#, fuzzy +#| msgid "" +#| "(Medium) The `Action` class is a multi-parameter type class which defines " +#| "an action of one type on another:" 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) を定義する、多" "変数型クラスです。" #. type: Plain text -#: text/chapter6.md:618 +#: text/chapter6.md:617 #, no-wrap msgid "" " ```haskell\n" @@ -22637,23 +25144,24 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:620 -#, 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" +#: text/chapter6.md:619 +#, fuzzy, 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" +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 " *動作*はモノイドな値を使って他の型の値を変更する方法を決めるやり方を記述する関数です。`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 +25170,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 +25186,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 +25202,14 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter6.md:637 -#, no-wrap -msgid " Write an instance which implements this action:\n" +#: text/chapter6.md:636 +#, fuzzy, 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,18 +25223,25 @@ 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" #. type: Bullet: '1. ' -#: text/chapter6.md:646 -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." +#: text/chapter6.md:645 +#, fuzzy +#| 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." +msgid "" +"(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" @@ -22735,15 +25251,19 @@ msgstr "" "*補足*:テストでは4つの実装を押さえています。" #. type: Bullet: '1. ' -#: text/chapter6.md:648 +#: text/chapter6.md:647 +#, fuzzy +#| msgid "" +#| "(Medium) Write an `Action` instance which repeats an input string some " +#| "number of times:" 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,7 +25277,7 @@ 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 "" @@ -22765,13 +25285,13 @@ msgstr "" " なお`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 +25300,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 +25310,7 @@ msgstr "" "ここでモノイド`m`はそれ自体が持つ`append`を用いて動作します。" #. type: Plain text -#: text/chapter6.md:665 +#: text/chapter6.md:664 #, no-wrap msgid "" " ```haskell\n" @@ -22802,7 +25322,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 +25330,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 +25342,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 +25357,32 @@ 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 +#, fuzzy, no-wrap +#| msgid "Note that this library is for demonstration purposes only, and is not intended to provide a robust hashing mechanism." +msgid "> 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 msgid "What properties might we expect of a hash function?" msgstr "ハッシュ関数に期待される性質とはどのようなものでしょうか。" #. type: Bullet: '- ' -#: text/chapter6.md:680 +#: text/chapter6.md:679 +#, fuzzy +#| msgid "" +#| "A hash function should be deterministic, and map equal values to equal " +#| "hash codes." 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,10 +25391,16 @@ msgstr "" "ん。" #. type: Plain text -#: text/chapter6.md:682 +#: text/chapter6.md:681 +#, fuzzy +#| 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 " +#| "certainly would not be enforceable by PureScript's type system. However, " +#| "this should provide the intuition for the following type class:" 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 "" @@ -22882,20 +25410,20 @@ 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 "{{#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 +25432,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,9 +25451,15 @@ msgstr "" "`combineHashes`関数は2つのハッシュ値を混ぜて結果を0-65535の間に分布します。" #. type: Plain text -#: text/chapter6.md:700 +#: text/chapter6.md:699 +#, fuzzy +#| msgid "" +#| "Let's write a function which 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:" 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:" @@ -22936,18 +25470,25 @@ msgstr "" "`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 +#, fuzzy +#| 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." 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,11 +25497,17 @@ msgstr "" "の値は「ハッシュ同値」です。" #. type: Plain text -#: text/chapter6.md:708 +#: text/chapter6.md:707 +#, fuzzy +#| 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:" 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" @@ -22968,26 +25515,26 @@ msgstr "" "`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 +25543,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 +25561,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,18 +25579,25 @@ 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 +#, fuzzy +#| 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 `Eq` but not equal identically." 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`インスタンスが先ほどの型クラスの法則を満たしていることを証" @@ -23053,11 +25607,22 @@ msgstr "" "は同じではない、というような型の値は存在しないので簡単です。" #. type: Plain text -#: text/chapter6.md:740 +#: text/chapter6.md:739 +#, fuzzy +#| 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 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 must satisfy the law. Therefore, the two arrays " +#| "have equal hashes, and so the `Hashable (Array a)` obeys the type class " +#| "law as well." 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 " @@ -23076,7 +25641,7 @@ msgstr "" "ラス法則を満たしています。" #. 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 +25650,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,10 +25660,17 @@ msgstr "" "*補足*:この演習には単体試験がありません。" #. type: Bullet: ' 1. ' -#: text/chapter6.md:748 -msgid "" -"(Medium) Write a function `arrayHasDuplicates` which tests if an array has " -"any duplicate elements based on both hash and value equality. First check " +#: text/chapter6.md:747 +#, fuzzy +#| msgid "" +#| "(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." +msgid "" +"(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." @@ -23111,7 +25683,7 @@ msgstr "" "しょう。" #. 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 +25692,7 @@ msgstr "" "ください。" #. type: Plain text -#: text/chapter6.md:751 +#: text/chapter6.md:750 #, no-wrap msgid "" " ```haskell\n" @@ -23130,7 +25702,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 +25712,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,11 +25725,18 @@ msgstr "" " *補足*:この演習にテストはありません。\n" #. type: Plain text -#: text/chapter6.md:761 +#: text/chapter6.md:760 +#, fuzzy +#| 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, and defined our own library based on a type class for " +#| "computing hash codes." 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 "" "この章では、型に基づく抽象化で、コードの再利用のための強力な形式化を可能にす" @@ -23166,15 +25745,23 @@ msgstr "" "リを定義しました。" #. type: Plain text -#: text/chapter6.md:762 -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." +#: text/chapter6.md:761 +#, fuzzy +#| 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." +msgid "" +"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" @@ -23190,11 +25777,19 @@ msgstr "アプリカティブによる検証" #. type: Plain text #: text/chapter7.md:6 -msgid "" -"In this chapter, we will meet an important new abstraction - the " +#, fuzzy +#| msgid "" +#| "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 " +#| "convert code which usually involves a lot of boilerplate checking into a " +#| "simple, declarative description of our form." +msgid "" +"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 "" @@ -23217,11 +25812,19 @@ msgstr "" #. type: Plain text #: text/chapter7.md:10 +#, fuzzy +#| 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 " +#| "user interface, to display errors to the user as part of a data entry " +#| "form." 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" @@ -23268,9 +25871,14 @@ msgstr "" #. type: Plain text #: text/chapter7.md:21 +#, fuzzy +#| msgid "" +#| "The `Data.AddressBook` module defines data types and `Show` instances for " +#| "the types in our project, and the `Data.AddressBook.Validation` module " +#| "contains validation rules for those types." 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`モジュールには、このプロジェクトのデータ型とそれらの型に対" @@ -23294,8 +25902,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:27 +#, fuzzy +#| msgid "" +#| "The source code for this module defines a function `address` which has " +#| "the following type:" 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`関数が定義されて" @@ -23382,8 +25994,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:61 +#, fuzzy +#| msgid "" +#| "Of course, this is an expected type error - `address` takes strings as " +#| "arguments, not values of type `Maybe String`." 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`型ではなく文字列型の引数を取るので、もちろんこれは期" @@ -23498,8 +26114,13 @@ msgstr "forall a b c d. (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> M #. type: Plain text #: text/chapter7.md:99 +#, fuzzy +#| msgid "" +#| "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`." 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 "" @@ -23605,16 +26226,22 @@ msgstr "" #. type: Plain text #: text/chapter7.md:129 +#, fuzzy +#| msgid "" +#| "Now we'll see how `map` and `apply` can be used together to lift " +#| "functions of arbitrary number of arguments." 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." +#, fuzzy +#| 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 +26286,10 @@ 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 "" -"この式の型がちゃんと整合しているかの確認は、読者への演習として残しておきま" -"す。" +#, fuzzy, no-wrap +#| msgid "It is left as an exercise for the reader to verify the types involved in this expression." +msgid "> It is left as an exercise for the reader to verify the types involved in this expression.\n" +msgstr "この式の型がちゃんと整合しているかの確認は、読者への演習として残しておきます。" #. type: Plain text #: text/chapter7.md:152 @@ -23699,8 +26324,14 @@ msgstr "" #. type: Plain text #: text/chapter7.md:164 -msgid "" -"Alternatively _applicative do notation_ can be used for the same purpose in " +#, fuzzy +#| msgid "" +#| "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:" +msgid "" +"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:" @@ -23790,8 +26421,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:199 +#, fuzzy +#| msgid "" +#| "If we think of applicative functors as functors which allow lifting of " +#| "functions, then `pure` can be thought of as lifting functions of zero " +#| "arguments." 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 "" @@ -23817,8 +26453,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" +#, fuzzy, 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" "その他の例としては、型`err`のエラーの可能性の副作用を表す`Either err`や、大域的な構成を読み取る副作用を表すArrow関手 (arrow functor) `r ->`があります。\n" @@ -23838,9 +26475,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:209 +#, fuzzy +#| msgid "" +#| "`pure` lifts pure (side-effect free) values into the larger language, and " +#| "for functions, we can use `map` and `apply` as described above." 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`を使うことができます。" @@ -23918,13 +26559,22 @@ msgstr "" #. 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:" +#, fuzzy +#| 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:" +msgid "" +"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" @@ -23955,8 +26605,10 @@ 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 +#, fuzzy +#| msgid "or with _applicative do_" +msgid "Or with _applicative do_:" msgstr "または*アプリカティブdo*で次のようにします。" #. type: Fenced code block (text) @@ -24012,8 +26664,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:267 +#, fuzzy +#| msgid "" +#| "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." 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 "" @@ -24115,9 +26772,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:307 +#, fuzzy +#| msgid "" +#| "Now our function takes three optional arguments using `Maybe`, and " +#| "returns either a `String` error message or a `String` result." 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`の結果のどちらかを返します。" @@ -24151,10 +26812,15 @@ msgstr "" #. type: Plain text #: text/chapter7.md:322 +#, fuzzy +#| 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:" 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 "" "このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省" "略されたフィールドのうち最初のものに対応するエラーメッセージが表示されま" @@ -24191,10 +26857,15 @@ msgstr "作用の結合" #. type: Plain text #: text/chapter7.md:333 +#, fuzzy +#| 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`." 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`によって表現さ" "れた副作用を一般的に組み合わせる関数を書く方法をこの節では示します。" @@ -24224,8 +26895,9 @@ 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" +#, fuzzy, 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`が`3`なら、関数は`\\x y z -> x : y : z : Nil`です。\n" @@ -24329,11 +27001,18 @@ msgstr "" #. type: Plain text #: text/chapter7.md:376 +#, fuzzy +#| msgid "" +#| "When specialized to `Maybe`, our function returns a `Just` only if every " +#| "list element was `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 result itself if every computation contained a result." 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`であるときに限りこの関" @@ -24345,16 +27024,21 @@ msgstr "" #. 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" +#, fuzzy, 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" #. type: Plain text #: text/chapter7.md:380 +#, fuzzy +#| msgid "" +#| "We will see the `combineList` function again later, when we consider " +#| "`Traversable` functors." 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`関手について考えるときに再訪" @@ -24362,11 +27046,17 @@ 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`." +#, fuzzy +#| 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`." +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`." msgstr "" "(普通)数値演算子`+`、`-`、`*`、`/`のオプショナル引数(つまり`Maybe`に包まれ" "た引数)を扱って`Maybe`に包まれた値を返す版を書いてください。\n" @@ -24388,11 +27078,17 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:386 +#, fuzzy +#| 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." 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" @@ -24402,11 +27098,17 @@ msgstr "" #. type: Plain text #: text/chapter7.md:390 +#, fuzzy +#| 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:" 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" @@ -24431,7 +27133,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:400 -msgid "where `PhoneType` is defined as an algebraic data type:" +#, fuzzy +#| 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) @@ -24442,10 +27146,14 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook.purs:PhoneType}}\n #. type: Plain text #: text/chapter7.md:406 +#, fuzzy +#| 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`:" 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`には次のような値が定義されています。" @@ -24537,10 +27245,16 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:450 +#, fuzzy +#| 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 " +#| "with the `Right` constructor." 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" @@ -24559,8 +27273,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:454 +#, fuzzy +#| msgid "" +#| "This function can be seen to work in PSCi, but has a limitation which we " +#| "have seen before:" 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でうまく動作するように見えますが、以前見たような制限がありま" @@ -24578,10 +27296,15 @@ msgstr "" #. type: Plain text #: text/chapter7.md:461 +#, fuzzy +#| 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." 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つのエラーがわかるようにしたくな" @@ -24589,12 +27312,18 @@ msgstr "" #. 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." +#, fuzzy +#| 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." +msgid "" +"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" @@ -24648,10 +27377,15 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:485 +#, fuzzy +#| 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." 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であるかどうかを" @@ -24803,10 +27537,16 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:545 +#, fuzzy +#| 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 cheatsheet and interactive test environment." 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 +27599,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 @@ -24867,8 +27612,12 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:563 +#, fuzzy +#| msgid "" +#| "`validatePhoneNumbers` uses a new function we haven't seen before - " +#| "`traverse`." 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`を使い" @@ -24908,12 +27657,18 @@ msgstr "" #. type: Plain text #: text/chapter7.md:575 +#, fuzzy +#| msgid "" +#| "Every traversable functor is both a `Functor` and `Foldable` (recall that " +#| "a _foldable functor_ was a type constructor which 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." 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つの値へと纏める畳み込み操作を提供する型構築子であったことを" @@ -24970,12 +27725,20 @@ msgstr "traverse :: forall a b. (a -> V Errors b) -> Array a -> V Errors (Array #. type: Plain text #: text/chapter7.md:591 +#, fuzzy +#| msgid "" +#| "This type signature says that if we have a validation function `m` for a " +#| "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 successively." msgid "" "This type signature says that if we have a validation function `m` for a " "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`は型" @@ -25023,11 +27786,18 @@ msgstr "" #. type: Plain text #: text/chapter7.md:607 +#, fuzzy +#| 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 as an exercise for the interested reader." 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 "" "巡回可能関手は、作用のある計算を集めてその作用を結合するという、データ構造走" @@ -25069,12 +27839,19 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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`の計算を作成できま" @@ -25125,11 +27902,18 @@ msgstr "" #. type: Plain text #: text/chapter7.md:639 +#, fuzzy +#| 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 for optional values of type `a`." 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`" @@ -25139,8 +27923,14 @@ msgstr "" #. type: Plain text #: text/chapter7.md:641 -msgid "" -"Other traversable functors include `Array`, and `Tuple a` and `Either a` for " +#, fuzzy +#| msgid "" +#| "Other traversable functors include `Array`, and `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." +msgid "" +"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." @@ -25173,14 +27963,16 @@ 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" +#, fuzzy, 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" +#, fuzzy, 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" @@ -25200,9 +27992,14 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:659 +#, fuzzy +#| msgid "" +#| "(Medium) Write a `Traversable` instance for `Tree a`, which combines side-" +#| "effects from left-to-right. _Hint_: There are some additional instance " +#| "dependencies that need to be defined for `Traversable`." 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" @@ -25212,14 +28009,24 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:661 +#, fuzzy +#| msgid "" +#| "(Medium) Write a function `traversePreOrder :: forall a m b. Applicative " +#| "m => (a -> m b) -> Tree a -> m (Tree b)` that performs a pre-order " +#| "traversal 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." msgid "" "(Medium) Write a function `traversePreOrder :: forall a m b. Applicative m " "=> (a -> m b) -> Tree a -> m (Tree b)` that performs a pre-order traversal " "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" @@ -25298,11 +28105,17 @@ msgstr "" #. type: Plain text #: text/chapter7.md:675 +#, fuzzy +#| 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." 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" "アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しませ" @@ -25325,11 +28138,17 @@ msgstr "" #. type: Plain text #: text/chapter7.md:679 +#, fuzzy +#| 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_:" 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" @@ -25368,8 +28187,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:690 +#, fuzzy +#| msgid "" +#| "Applicative functors are a natural way to capture side-effects which can " +#| "be combined in parallel." 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 "" "アプリカティブ関手は並列に結合できる副作用を一纏めにする自然な方法です。" @@ -25381,9 +28204,14 @@ msgstr "この章では新しい考え方を沢山扱いました。" #. type: Bullet: '- ' #: text/chapter7.md:698 +#, fuzzy +#| msgid "" +#| "We introduced the concept of an _applicative functor_ which generalizes " +#| "the idea of function application to type constructors which capture some " +#| "notion of side-effect." 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 "" "関数適用の概念を副作用の観念を捉えた型構築子へと一般化する、 _アプリカティブ" @@ -25391,10 +28219,16 @@ msgstr "" #. 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 " +#, fuzzy +#| 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 structure." +msgid "" +"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 "" "データ構造の検証という課題にアプリカティブ関手がどのような解決策を与えるか、" @@ -25413,14 +28247,23 @@ msgstr "" #. type: Plain text #: text/chapter7.md:700 -msgid "" -"Applicative functors are an interesting abstraction which provide neat " +#, fuzzy +#| msgid "" +#| "Applicative functors are an interesting abstraction which provide 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_." +msgid "" +"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" @@ -25448,11 +28291,17 @@ 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_." +#, fuzzy +#| 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_." +msgid "" +"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 "" "前章では、オプショナルな型やエラーメッセージ、データの検証など、 _副作用_ を" "扱いを抽象化するアプリカティブ関手を導入しました。この章では、より表現力の高" @@ -25460,8 +28309,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:8 +#, fuzzy +#| msgid "" +#| "The goal of this chapter is to explain why monads are a useful " +#| "abstraction, and their connection with _do notation_." 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記法_ との関" @@ -25474,11 +28327,17 @@ msgstr "このプロジェクトでは、以下の依存関係が追加されて #. type: Bullet: '- ' #: text/chapter8.md:15 -msgid "" -"`effect` - defines the `Effect` monad, the subject of the second half of the " +#, fuzzy +#| msgid "" +#| "`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." +msgid "" +"`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`モナドを定義しています。この依存関係は" "全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存" @@ -25486,9 +28345,12 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:15 +#, fuzzy +#| msgid "" +#| "`react-basic-hooks` - a web framework that we will use for our Address " +#| "Book app." msgid "" -"`react-basic-hooks` - a web framework that we will use for our Address Book " -"app." +"`react-basic-hooks` – a web framework we will use for our Address Book app." msgstr "`react-basic-hooks`: アドレス帳アプリに使うWebフレームワークです。" #. type: Title ## @@ -25531,16 +28393,22 @@ 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." +#, fuzzy +#| 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 "" "もし `x`と `y`の和が `n`なら組 `[x, y]`を返し、そうでなければ失敗します。" #. type: Plain text #: text/chapter8.md:27 +#, fuzzy +#| msgid "" +#| "Array comprehensions allow us to write this non-deterministic algorithm " +#| "in a natural way:" 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 "" "配列内包表記を使うと、この非決定的アルゴリズムを自然に書くことができます。" @@ -25605,14 +28473,24 @@ msgstr "" #. type: Plain text #: text/chapter8.md:52 -msgid "" -"In general, a _monad_ for some type constructor `m` provides a way to use do " +#, fuzzy +#| msgid "" +#| "In general, 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 types)." +msgid "" +"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記法を使う手段を提供" @@ -25644,8 +28522,12 @@ msgstr "child :: XML -> String -> Maybe XML\n" #. type: Plain text #: text/chapter8.md:60 +#, fuzzy +#| msgid "" +#| "which looks for a child element of a node, and returns `Nothing` if no " +#| "such element exists." 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 "" "この関数はノードの子の要素を探し、もしそのような要素が存在しなければ " @@ -25653,9 +28535,14 @@ 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 " +#, fuzzy +#| 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 encoded as an XML document:" +msgid "" +"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" @@ -25682,12 +28569,19 @@ msgstr "" #. type: Plain text #: text/chapter8.md:73 +#, fuzzy +#| 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." 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" @@ -25740,9 +28634,13 @@ msgstr "ここで鍵となる関数は `Bind`型クラスで定義されてい #. type: Plain text #: text/chapter8.md:90 +#, fuzzy +#| msgid "" +#| "The `Monad` type class extends `Bind` with the operations of the " +#| "`Applicative` type class that we have already seen." 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`を拡張し" "ます。" @@ -25803,9 +28701,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:111 +#, fuzzy +#| 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 some computation:" 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記法がどのように関係しているかを見て行きましょう。最初に何" @@ -25883,8 +28786,9 @@ 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" +#, fuzzy, 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" +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" #. type: Title ## @@ -26016,10 +28920,15 @@ msgstr "" #. type: Plain text #: text/chapter8.md:192 +#, fuzzy +#| 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`." 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`に束縛され" @@ -26036,8 +28945,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:196 +#, fuzzy +#| msgid "" +#| "In `c2`, all three expressions `m1`, `m2` and `m3` appear in the same do " +#| "notation block." 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記法ブロックに現れています。" @@ -26084,10 +28997,17 @@ msgstr "モナドで畳み込む" #. type: Plain text #: text/chapter8.md:212 +#, fuzzy +#| 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." 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 "" @@ -26099,10 +29019,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:214 +#, fuzzy +#| 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:" 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`関数を" "モナドの文脈へと一般化します。型シグネチャは次のようになっています。" @@ -26137,9 +29061,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:225 +#, fuzzy +#| 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 result, and the result of the fold is therefore also optional." 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`であるとすると、この畳み込みはそれぞれの段階で " @@ -26149,10 +29078,17 @@ msgstr "" #. type: Plain text #: text/chapter8.md:227 +#, fuzzy +#| 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 of results would consist of all folds over all possible paths. " +#| "This corresponds to a traversal of a graph!" 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 "" @@ -26220,17 +29156,27 @@ msgstr "" #. type: Plain text #: text/chapter8.md:249 +#, fuzzy +#| msgid "" +#| "Note that this implementation is almost identical to that of `foldl` on " +#| "lists, with the exception of do notation." 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`の実装とほとんど同じで" "す。" #. type: Plain text #: text/chapter8.md:251 -msgid "" -"We can define and test this function in PSCi. Here is an example - suppose " +#, fuzzy +#| msgid "" +#| "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:" +msgid "" +"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 "" @@ -26273,9 +29219,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:270 +#, fuzzy +#| msgid "" +#| "The `foldM safeDivide` function returns `Nothing` if a division by zero " +#| "was attempted at any point. Otherwise it returns the result of repeatedly " +#| "dividing the accumulator, wrapped in the `Just` constructor." 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`" @@ -26333,9 +29284,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:288 +#, fuzzy +#| msgid "" +#| "The interested reader can check that `ap` agrees with `apply` for the " +#| "monads we have already encountered: `Array`, `Maybe` and `Either e`." 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`と一致することを確かめてみてください。" @@ -26359,11 +29314,17 @@ msgstr "" #. type: Plain text #: text/chapter8.md:292 +#, fuzzy +#| 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:" 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" @@ -26399,12 +29360,20 @@ msgstr "" #. type: Plain text #: text/chapter8.md:307 +#, fuzzy +#| msgid "" +#| "In the last chapter, we saw that the `Applicative` type class can be used " +#| "to 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." msgid "" "In the last chapter, we saw that the `Applicative` type class can be used to " "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" "持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りで" @@ -26415,8 +29384,15 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter8.md:312 -msgid "" -"(Easy) Write a function `third` which returns the third element of an array " +#, fuzzy +#| msgid "" +#| "(Easy) Write a function `third` which 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 the `Maybe` monad to combine these functions." +msgid "" +"(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 " @@ -26468,9 +29444,14 @@ msgstr "" #. type: Plain text #: 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" +#, fuzzy, 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" +#| " 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" +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.\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" @@ -26539,8 +29520,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" +#, fuzzy, 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" " `lift2`が次のように定義されていたことを思い出してください。\n" @@ -26573,9 +29555,13 @@ msgstr "ネイティブな作用" #. type: Plain text #: text/chapter8.md:356 +#, fuzzy +#| msgid "" +#| "We will now look at one particular monad which is of central importance " +#| "in PureScript - the `Effect` monad." 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`モナドについて見ていきま" "す。" @@ -26593,8 +29579,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:360 +#, fuzzy +#| msgid "" +#| "What are native side-effects? They are the side-effects which distinguish " +#| "JavaScript expressions from idiomatic PureScript expressions, which " +#| "typically are free from side-effects. Some examples of native effects are:" 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 "" @@ -26665,14 +29656,24 @@ msgstr "配列やリストで表現される多値関数" #. type: Plain text #: text/chapter8.md:380 +#, fuzzy +#| 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 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 is implemented at runtime." 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" @@ -26693,20 +29694,30 @@ msgstr "副作用と純粋性" #. type: Plain text #: text/chapter8.md:384 +#, fuzzy +#| msgid "" +#| "In a pure language like PureScript, one question which presents itself " +#| "is: without side-effects, how can one write useful real-world code?" 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のような言語が純粋であるとすると、疑問が浮かんできます。副作用がな" "いなら、どうやって役に立つ実際のコードを書くことができるというのでしょうか。" #. 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." +#, fuzzy +#| 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." +msgid "" +"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の目的は副作用を排除することではないということです。これ" "は、純粋な計算と副作用のある計算とを型システムにおいて区別できるような方法" @@ -26715,10 +29726,15 @@ msgstr "" #. type: Plain text #: text/chapter8.md:388 +#, fuzzy +#| 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." 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 "" "副作用のある値は、純粋な値とは異なる型を持っています。そういうわけで、例えば" "副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起" @@ -26726,17 +29742,27 @@ msgstr "" #. type: Plain text #: text/chapter8.md:390 +#, fuzzy +#| 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." 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から実行することです。" #. type: Plain text #: text/chapter8.md:392 -msgid "" -"The Spago build tool (and other tools) provide a shortcut, by generating " +#, fuzzy +#| msgid "" +#| "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." +msgid "" +"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 "" @@ -26754,13 +29780,18 @@ msgstr "" "JavaScriptを生成します。" #. type: Plain text -#: text/chapter8.md:399 +#: text/chapter8.md:398 +#, fuzzy +#| 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." 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" "`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコ" @@ -26769,14 +29800,35 @@ msgstr "" "`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられ" "ます。" -#. type: Fenced code block (hs) +#. type: Plain text #: text/chapter8.md:400 +#, fuzzy +#| 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." +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 "" +"馴染みのある`log`関数から返る型をもう少し見てみましょう。\n" +"`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコ" +"ンソールIOです。\n" +"`Unit`はいかなる*意味のある*データも返らないことを示しています。\n" +"`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられ" +"ます。" + +#. type: Fenced code block (hs) +#: 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 +29847,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 +29856,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 +29871,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 +29888,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 +29898,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 +29917,17 @@ msgstr "" "コンソールに出力 `0.0`と `1.0`の間で無作為に選ばれた数が表示されるでしょう。" #. type: Plain text -#: text/chapter8.md:438 -#, 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" +#: text/chapter8.md:439 +#, fuzzy, 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" #. 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,17 +29938,29 @@ msgstr "" "この技法は「テストを生成する」章で押さえます。" #. type: Plain text -#: text/chapter8.md:442 +#: text/chapter8.md:443 +#, fuzzy +#| 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 " +#| "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 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." 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の`外部関数インターフェース`とやりとりす" @@ -26909,27 +29974,31 @@ msgstr "" "し置いても副作用を内包すること以外には大したことはしません。" #. type: Plain text -#: text/chapter8.md:446 +#: text/chapter8.md:447 +#, fuzzy +#| msgid "" +#| "Let's examine a function from the `node-fs` package that involves two " +#| "_native_ side effects: reading mutable state, and exceptions:" 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`パッケージの関数を調べましょう。こ" "こでの副作用は可変状態の読み取りと例外です。" #. 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 +30018,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 +30045,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 +30054,7 @@ msgstr "" "な出力でも制御できます。" #. type: Fenced code block (hs) -#: text/chapter8.md:478 +#: text/chapter8.md:479 #, no-wrap msgid "" "main :: Effect Unit\n" @@ -27003,7 +30072,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 +30081,29 @@ 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 +#, fuzzy +#| 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`." 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 +30117,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 +30130,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,7 +30156,7 @@ 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:" @@ -27091,7 +30165,7 @@ 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" @@ -27111,13 +30185,20 @@ 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 +#, fuzzy +#| 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." 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`アクション" @@ -27126,17 +30207,22 @@ msgstr "" "ヒープ*)を表しています。" #. type: Plain text -#: text/chapter8.md:525 +#: text/chapter8.md:526 +#, fuzzy +#| 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." 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 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 +30232,7 @@ msgstr "" "新するのにforループを使うことでこれを実現できます。" #. type: Fenced code block (hs) -#: text/chapter8.md:528 +#: text/chapter8.md:529 #, no-wrap msgid "" "import Prelude\n" @@ -27188,39 +30274,49 @@ msgstr "" " pure final.x\n" #. type: Plain text -#: text/chapter8.md:550 +#: text/chapter8.md:551 +#, fuzzy +#| msgid "" +#| "At the end of the computation, we read the final value of the reference " +#| "cell, and return the position of the particle." 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 +#, fuzzy +#| msgid "" +#| "Note that even though this function uses 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." 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`作用が禁止するものが正確には何であるのかについては後ほど見ます。" #. 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 " @@ -27232,12 +30328,18 @@ msgstr "" "とを意味しています。" #. type: Plain text -#: text/chapter8.md:562 +#: text/chapter8.md:563 +#, fuzzy +#| 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!" 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`によって限定されたコードの外側で参照領域を使おうとしても型エ" @@ -27246,7 +30348,7 @@ msgstr "" "なのです。" #. type: Fenced code block (hs) -#: text/chapter8.md:563 +#: text/chapter8.md:564 #, no-wrap msgid "" "simulate' :: Number -> Number -> Int -> Number\n" @@ -27256,12 +30358,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 +30401,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 +30410,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,11 +30444,16 @@ msgstr "" " pure final.x\n" #. type: Plain text -#: text/chapter8.md:609 +#: text/chapter8.md:610 +#, fuzzy +#| 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`:" 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" @@ -27354,7 +30461,7 @@ msgstr "" "す。" #. type: Fenced code block (javascript) -#: text/chapter8.md:610 +#: text/chapter8.md:611 #, no-wrap msgid "" "var simulate = function (x0) {\n" @@ -27404,26 +30511,23 @@ 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 +#, fuzzy, 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." +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" +"詳細は[この課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。\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 +30577,23 @@ msgstr "" "};\n" #. type: Plain text -#: text/chapter8.md:665 +#: text/chapter8.md:666 +#, fuzzy +#| 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." 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を生成する良い方法となります。" #. 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 +30604,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 +30620,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 +30632,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 +30647,51 @@ msgstr "" "際のDOM操作の問題に応用します。" #. type: Plain text -#: text/chapter8.md:677 +#: text/chapter8.md:678 +#, fuzzy +#| msgid "" +#| "There are a number of PureScript packages for working directly with the " +#| "DOM, or with open-source DOM libraries. For example:" 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 +#, fuzzy +#| msgid "" +#| "[`web-dom`](https://github.com/purescript-web/purescript-web-dom) " +#| "provides type definitions and low level interface implementations for the " +#| "W3C DOM spec." 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規格に向けた型定義と低水準インターフェース実装を提供します。" #. type: Bullet: '- ' -#: text/chapter8.md:681 +#: text/chapter8.md:682 +#, fuzzy +#| msgid "" +#| "[`web-html`](https://github.com/purescript-web/purescript-web-html) " +#| "provides type definitions and low level interface implementations for the " +#| "W3C HTML5 spec." 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 +30700,26 @@ msgstr "" "jquery.org)ライブラリのバインディングの集まりです。" #. type: Plain text -#: text/chapter8.md:683 +#: text/chapter8.md:684 +#, fuzzy +#| msgid "" +#| "There are also PureScript libraries which build abstractions on top of " +#| "these libraries, such as" 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" "以下のようなものです。" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 +#, fuzzy +#| msgid "" +#| "[`thermite`](https://github.com/paf31/purescript-thermite), which builds " +#| "on [`react`](https://github.com/purescript-contrib/purescript-react)" 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 +30727,30 @@ msgstr "" "ます。" #. type: Bullet: '- ' -#: text/chapter8.md:687 +#: text/chapter8.md:688 +#, fuzzy +#| msgid "" +#| "[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-" +#| "hooks), which builds on [`react-basic`](https://github.com/lumihq/" +#| "purescript-react-basic)" 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 -msgid "" -"[`halogen`](https://github.com/purescript-halogen/purescript-halogen) which " +#: text/chapter8.md:688 +#, fuzzy +#| msgid "" +#| "[`halogen`](https://github.com/purescript-halogen/purescript-halogen) " +#| "which provides a type-safe set of abstractions on top of a custom virtual " +#| "DOM library." +msgid "" +"[`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 +30758,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 +30769,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 +30792,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,11 +30804,18 @@ msgstr "" "目的に応じて、Reactは `Effect`モナドの実用的な例を提供してくれます。" #. type: Plain text -#: text/chapter8.md:697 +#: text/chapter8.md:698 +#, fuzzy +#| msgid "" +#| "We are going to build a form which 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 errors will be displayed. As the user types text into the text " +#| "boxes, the validation errors will be updated." 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 "" @@ -27677,7 +30825,7 @@ msgstr "" "テキストボックスに利用者がテキストを入力すると、検証エラーが更新されます。" #. 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,7 +30835,7 @@ 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:" @@ -27696,7 +30844,7 @@ msgstr "" "ができます。" #. type: Fenced code block (shell) -#: text/chapter8.md:702 +#: text/chapter8.md:703 #, no-wrap msgid "" "$ npm install\n" @@ -27708,7 +30856,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 +30869,21 @@ msgstr "" "`parcel`についても同じことができるでしょう。" #. type: Plain text -#: text/chapter8.md:711 +#: text/chapter8.md:712 +#, fuzzy +#| 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 " +#| "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/documentation/blob/master/ecosystem/Editor-and-tool-support." +#| "md#editors) that supports [`purs ide`](https://github.com/purescript/" +#| "purescript/tree/master/psc-ide) or are running [`pscid`](https://github." +#| "com/kRITZCREEK/pscid)." 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 +30902,48 @@ msgstr "" "る)ように設定できます。" #. type: Plain text -#: text/chapter8.md:713 +#: text/chapter8.md:714 +#, fuzzy +#| 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." 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 +31027,21 @@ msgstr "" "途中の`w`や`doc`変数が読みやすさの助けになるかは主観的な好みの問題です。" #. type: Plain text -#: text/chapter8.md:762 +#: text/chapter8.md:763 +#, fuzzy +#| 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`." 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 +31050,7 @@ msgstr "" "遠慮なく全体のコンポーネントをこれに置き換えて実行の様子を見てみましょう。" #. type: Fenced code block (hs) -#: text/chapter8.md:765 +#: text/chapter8.md:766 #, no-wrap msgid "" "mkAddressBookApp :: Effect (ReactComponent {})\n" @@ -27899,12 +31066,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 +31093,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 +31105,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 +31126,25 @@ msgstr "" "これで`component`には`ReactComponent`を生成するのに必要な全てがあります。" #. type: Plain text -#: text/chapter8.md:797 +#: text/chapter8.md:798 +#, fuzzy +#| msgid "" +#| "Next we'll examine some of the additional complexities of the full " +#| "Address Book component." 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,24 +31158,30 @@ 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 +#, fuzzy +#| 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." 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" @@ -28014,7 +31191,7 @@ msgstr "" "す。" #. 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 +31200,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 +31217,7 @@ msgstr "" "ます。" #. type: Fenced code block (hs) -#: text/chapter8.md:823 +#: text/chapter8.md:824 #, no-wrap msgid "" "useState ::\n" @@ -28054,7 +31231,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 +31242,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 +31257,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 +31266,23 @@ 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`はそれぞれの再描画の時点で現在の状態にアクセスする方法です。" #. type: Plain text -#: text/chapter8.md:844 -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:" +#: text/chapter8.md:845 +#, fuzzy +#| 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:" +msgid "" +"`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 +31291,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 +31301,20 @@ msgstr "" "\n" #. type: Plain text -#: text/chapter8.md:851 -msgid "or as shorthand:" +#: text/chapter8.md:852 +#, fuzzy +#| 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 "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 +31326,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 +31344,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 +31353,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,12 +31420,20 @@ msgstr "" " }\n" #. type: Plain text -#: text/chapter8.md:896 +#: text/chapter8.md:897 +#, fuzzy +#| msgid "" +#| "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, converted to JSX. There are usually three variants " +#| "of each of these functions:" 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 "" @@ -28251,14 +31444,14 @@ msgstr "" "ぞれ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 +31460,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 +31468,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 +31479,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 +31494,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 +31515,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 +31530,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 +31545,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 +31554,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 +31573,41 @@ 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 +#, fuzzy +#| 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." 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`が使わ" "れています。" #. 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 +31618,7 @@ msgstr "" "ます。" #. type: Fenced code block (hs) -#: text/chapter8.md:949 +#: text/chapter8.md:950 #, no-wrap msgid "" "onChange:\n" @@ -28440,7 +31638,7 @@ 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." @@ -28449,18 +31647,18 @@ msgstr "" "`setPerson`フックに適切なレコード更新呼び出しを実施します。" #. type: Plain text -#: text/chapter8.md:962 +#: text/chapter8.md:963 msgid "Note that `handleValue` can be substituted as:" 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." @@ -28469,17 +31667,22 @@ msgstr "" "い。" #. type: Plain text -#: text/chapter8.md:970 +#: text/chapter8.md:971 +#, fuzzy +#| 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." 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 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 +31692,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,16 +31701,21 @@ 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 -msgid "" -"(Medium) Right now the application shows validation errors collected in a " +#: text/chapter8.md:980 +#, fuzzy +#| msgid "" +#| "(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." +msgid "" +"(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 "" @@ -28517,7 +31725,7 @@ msgstr "" "うに変更してください。" #. 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" @@ -28527,13 +31735,14 @@ msgstr "" "1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。コードを変更してこの問題を解決してください。\n" #. type: Plain text -#: text/chapter8.md:984 -#, 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" +#: text/chapter8.md:985 +#, fuzzy, 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" +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" #. type: Plain text -#: text/chapter8.md:992 +#: text/chapter8.md:993 #, no-wrap msgid "" " ```hs\n" @@ -28553,13 +31762,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 +31778,14 @@ msgstr "" " ```\n" #. type: Plain text -#: text/chapter8.md:999 -#, no-wrap -msgid " You will need to write a function which extracts the validation error for a particular `Field` from the `Errors` structure.\n" +#: text/chapter8.md:1000 +#, fuzzy, 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 +31793,38 @@ msgstr "" "この章ではPureScriptでの副作用の扱いについての多くの考え方を導入しました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 -msgid "We met the `Monad` type class, and its connection to do notation." +#: text/chapter8.md:1011 +#, fuzzy +#| 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 "`Monad`型クラスとdo記法との関係性に出会いました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 +#, fuzzy +#| msgid "" +#| "We introduced the monad laws, and saw how they allow us to transform code " +#| "written using do notation." 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記法を使って書かれたコードを変換する方法を見ました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 +#, fuzzy +#| msgid "" +#| "We saw how monads can be used abstractly, to write code which works with " +#| "different side-effects." 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,16 +31833,20 @@ msgstr "" "を可能にするのかということ、そして2つの手法の違いを説明しました。" #. type: Bullet: '- ' -#: text/chapter8.md:1010 +#: text/chapter8.md:1011 +#, fuzzy +#| msgid "" +#| "The concept of native effects was defined, and we met the `Effect` monad, " +#| "which is used to handle native side-effects." 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`モナドを導入しました。" #. 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 " @@ -28632,7 +31856,7 @@ msgstr "" "いった、さまざまな作用を扱うために `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 " @@ -28649,12 +31873,19 @@ msgstr "非同期作用" #. type: Plain text #: text/chapter9.md:6 +#, fuzzy +#| 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." 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リクエストを" @@ -28688,9 +31919,14 @@ msgstr "`parallel` - `Aff`の並列実行。" #. type: Plain text #: text/chapter9.md:17 +#, fuzzy +#| 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 " +#| "dependency in the `package.json` of this chapter. Install that by running:" 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`ライブラリは" @@ -28764,9 +32000,13 @@ msgstr "" #. type: Plain text #: text/chapter9.md:43 +#, fuzzy +#| msgid "" +#| "It is also possible to use callbacks or synchronous functions, but those " +#| "are less desireable because:" msgid "" "It is also possible to use callbacks or synchronous functions, but those are " -"less desireable because:" +"less desirable because:" msgstr "" "コールバックや同期関数を使うことも可能ですが、以下の理由から望ましくありませ" "ん。" @@ -28819,11 +32059,17 @@ msgstr "" #. type: Plain text #: text/chapter9.md:58 +#, fuzzy +#| 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` respectively), but those share the same downsides as discussed " +#| "earlier with JavaScript, and so that coding style is not recommended." 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で前にお話し" @@ -28832,9 +32078,14 @@ msgstr "" #. type: Plain text #: text/chapter9.md:60 +#, fuzzy +#| 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." 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記法で書くことができます。" @@ -28906,18 +32157,26 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter9.md:90 +#, fuzzy +#| msgid "" +#| "(Easy) Write a `concatenateFiles` function which concatenates two text " +#| "files." msgid "" -"(Easy) Write a `concatenateFiles` function which concatenates two text files." +"(Easy) Write a `concatenateFiles` function that concatenates two text files." msgstr "" "(簡単)2つのテキストファイルを連結する関数`concatenateFiles`を書いてくださ" "い。" #. type: Bullet: ' 1. ' #: text/chapter9.md:92 +#, fuzzy +#| 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`." 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" @@ -28941,12 +32200,18 @@ 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." +#, fuzzy +#| 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." +msgid "" +"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" @@ -28985,18 +32250,25 @@ msgid "A HTTP Client" msgstr "HTTPクライアント" #. type: Plain text -#: text/chapter9.md:109 +#: text/chapter9.md:107 +#, fuzzy +#| msgid "" +#| "The `affjax` library offers a convenient way to make asynchronous AJAX " +#| "HTTP 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:" 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:" +"github.com/purescript-contrib/purescript-affjax-node) library." msgstr "" "`affjax`ライブラリは`Aff`で非同期AJAX HTTP要求する便利な手段を提供します。\n" "対象としている環境が何であるかによって、[purescript-affjax-web](https://" @@ -29010,14 +32282,47 @@ msgstr "" "以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例" "です。" -#. type: Fenced code block (hs) +#. type: Plain text #: text/chapter9.md:110 +#, fuzzy +#| msgid "" +#| "The `affjax` library offers a convenient way to make asynchronous AJAX " +#| "HTTP 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:" +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 "" +"`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`を使いま" +"す。\n" +"より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript." +"org/packages/purescript-affjax)にあたってください。\n" +"以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例" +"です。" + +#. type: Fenced code block (hs) +#: 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 +32331,7 @@ msgstr "" "と変換する必要があります。" #. type: Fenced code block (shell) -#: text/chapter9.md:116 +#: text/chapter9.md:117 #, no-wrap msgid "" "$ spago repl\n" @@ -29060,7 +32365,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 +32374,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,14 +32393,23 @@ msgstr "" "`Aff`があれば2つの計算を次々に開始するだけで並列に計算できます。" #. type: Plain text -#: text/chapter9.md:142 -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 " +#: text/chapter9.md:143 +#, fuzzy +#| 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 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:" +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 " "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" @@ -29105,7 +32419,7 @@ msgstr "" "成するために使われるアプリカティブ関手`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 +32431,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,15 +32445,22 @@ 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 +#, fuzzy +#| msgid "" +#| "The `aff` library provides a `Parallel` instance for the `Aff` monad. It " +#| "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." 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." @@ -29150,7 +32471,7 @@ msgstr "" "両方の結果が返されたら、最終結果を計算してメインの継続に渡すことができます。" #. 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,9 +32484,15 @@ msgstr "" "関数から恩恵を受けることもできます。" #. type: Plain text -#: text/chapter9.md:159 +#: text/chapter9.md:160 +#, fuzzy +#| msgid "" +#| "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." 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." @@ -29175,7 +32502,7 @@ msgstr "" "を結合したり、またはその逆を行ったりできます。" #. 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 +32516,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 +32546,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 +32560,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 +32590,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 +32604,22 @@ msgstr "" "contrib/purescript-aff#parallel-execution)にもより多くの例が含まれています。" #. type: Bullet: '1. ' -#: text/chapter9.md:203 +#: text/chapter9.md:204 +#, fuzzy +#| msgid "" +#| "(Easy) Write a `concatenateManyParallel` function which has the same " +#| "signature as the earlier `concatenateMany` function, but reads all input " +#| "files in parallel." 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 +32630,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 +32638,22 @@ 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 -msgid "" -"(Difficult) Write a `recurseFiles` function which takes a \"root\" file and " +#: text/chapter9.md:210 +#, fuzzy +#| msgid "" +#| "(Difficult) Write a `recurseFiles` function which 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 some helpful functions for negotiating directories." +msgid "" +"(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 " @@ -29330,12 +32668,12 @@ msgstr "" "す。" #. 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 +32711,34 @@ 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:" +#: text/chapter9.md:241 +#, fuzzy +#| 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 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リクエストを行う。" #. type: Bullet: '- ' -#: text/chapter9.md:243 +#: text/chapter9.md:244 msgid "Run asynchronous code in parallel with the `parallel` library." msgstr "`parallel`ライブラリを使って並列に非同期コードを走らせる。" From 44d6780dc03bf13b9b575ffb1c4e1a253e48db9b Mon Sep 17 00:00:00 2001 From: gemmaro Date: Tue, 11 Jul 2023 20:15:44 +0900 Subject: [PATCH 03/29] =?UTF-8?q?[=20change=20]=20'=E3=81=93=E3=81=AE?= =?UTF-8?q?=E6=9C=AC'=20->=20'=E6=9C=AC=E6=9B=B8'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- translation/ja.po | 136 ++++++++++++---------------------------------- 1 file changed, 36 insertions(+), 100 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index ecf0debb..9a1510a5 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-11 19:41+0900\n" +"PO-Revision-Date: 2023-07-11 20:15+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -154,11 +154,8 @@ 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" +"より初心者にやさしくできそうな分かりづらい節を指摘するような単純なものであれ、共有いただいたどんなフィードバックにも感謝します。" #. type: Plain text #: README.md:12 @@ -211,9 +208,7 @@ msgid "" "This book will show you how to get started with the PureScript programming " "language, from the basics (setting up a development environment) to the " "advanced." -msgstr "" -"この本は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラ" -"ミング言語の始め方を示します。" +msgstr "本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。" #. type: Plain text #: README.md:22 @@ -223,9 +218,8 @@ msgid "" "be introduced. Here are some examples of problems that will be solved in " "this book:" msgstr "" -"それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程に" -"おいて、新しい関数型プログラミングの道具と技法が導入されていきます。\n" -"以下はこの本で解いていく課題の幾つかの例です。" +"それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。\n" +"以下は本書で解いていく課題の幾つかの例です。" #. type: Bullet: '- ' #: README.md:31 @@ -663,10 +657,8 @@ msgid "" "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" -"ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、" -"JavaScriptからPureScriptコードを呼び出す方法、及びその逆についても見ていきま" -"す。" +"本書では小規模な課題をPureScriptで解決することに焦点を当てます。\n" +"ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、JavaScriptからPureScriptコードを呼び出す方法、及びその逆についても見ていきます。" #. type: Title ## #: text/chapter1.md:82 @@ -682,10 +674,9 @@ msgid "" "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 @@ -875,9 +866,9 @@ msgid "" "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." msgstr "" -"この本は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。\n" -"初心者にとって、本書は楽しい挑戦になるはずです。\n" -"本書の内容を読み、演習に挑戦すれば得るものがあることでしょう。\n" +"本書は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。\n" +"初心者にとっては楽しい挑戦になるはずです。\n" +"内容を読んで演習に挑戦すれば得るものがあることでしょう。\n" "そして何よりも大切なのは、自分自身でコードを書いてみることです。" #. type: Title ## @@ -920,10 +911,8 @@ msgid "" "into great depth. If a concept in this book is difficult to understand, " "consider reading the corresponding section in that reference." msgstr "" -"[PureScript: Jordan's Reference](https://github.com/jordanmartinez/" -"purescript-jordans-reference)は別のかなり深く踏み込んだ学習資料です。\n" -"この本の中のある概念が理解しにくかったら、そちらの参考書の対応する節を読むと" -"よいでしょう。" +"[PureScript: Jordan's Reference](https://github.com/jordanmartinez/purescript-jordans-reference)は別のかなり深く踏み込んだ学習資料です。\n" +"本書中の概念で理解しにくいものがあったら、そちらの参考書の対応する節を読むとよいでしょう。" #. type: Bullet: '- ' #: text/chapter1.md:146 @@ -1069,16 +1058,14 @@ msgid "" "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/licenses/by/4.0/)の条件の下で再利用させて頂いています 。" +msgstr "本書の表紙に示されたPureScriptのロゴはGareth Hughesによって作成されたもので、[Creative Commons Attribution 4.0 license](https://creativecommons.org/licenses/by/4.0/)の条件の下で再利用させて頂いています 。" #. type: Plain text #: text/chapter1.md:165 msgid "" "Finally, I would like to thank everyone who has given me feedback and " "corrections on the contents of this book." -msgstr "" -"最後に、この本の内容に関する反応や訂正をくださった全ての方に、心より感謝した" -"いと思います。" +msgstr "最後に、本書の内容に関する反応や訂正をくださった全ての方に、心より感謝したいと思います。" #. type: Title # #: text/chapter10.md:1 @@ -1158,11 +1145,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:17 #, fuzzy -#| 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:" msgid "" "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 " @@ -1170,8 +1152,7 @@ msgid "" "less relevant to your learning objectives:" msgstr "" "さらに一般にはそこまで重用されない幾つかの話題を押さえた補遺もあります。\n" -"ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本の" -"残りを読み進める妨げにならないようにしてください。" +"ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本書の残りを読み進める妨げにならないようにしてください。" #. type: Bullet: '- ' #: text/chapter10.md:20 @@ -15399,10 +15380,8 @@ 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 @@ -15472,9 +15451,7 @@ msgstr "演習を解く" msgid "" "Now that you've installed the necessary development tools, clone this book's " "repo." -msgstr "" -"ここまでで必要な開発ツールをインストールできているので、この本のリポジトリを" -"クローンしてください。" +msgstr "ここまでで必要な開発ツールをインストールできているので、本書のリポジトリをクローンしてください。" #. type: Fenced code block (sh) #: text/chapter2.md:23 @@ -15484,16 +15461,6 @@ msgstr "git clone https://github.com/purescript-contrib/purescript-book.git\n" #. type: Plain text #: text/chapter2.md:28 -#, fuzzy -#| 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):" msgid "" "The book repo contains PureScript example code and unit tests for the " "exercises that accompany each chapter. There's some initial setup required " @@ -15504,13 +15471,10 @@ msgid "" "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 @@ -15596,9 +15560,8 @@ msgid "" "solutions in the `Test.MySolutions` module (`test/MySolutions.purs`), you " "can check your work against the provided test suite." msgstr "" -"本の残りの部分には多くの演習が含まれます。\n" -"`Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、" -"提供されているテストスートを使って確認できます。" +"本書の残りの部分には多くの演習が含まれます。\n" +"`Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、提供されているテストスートを使って確認できます。" #. type: Plain text #: text/chapter2.md:59 @@ -15826,15 +15789,6 @@ msgstr "" #. type: Plain text #: text/chapter2.md:134 #, fuzzy -#| 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." msgid "" "There will be many more exercises in the chapters ahead, and working through " "those helps with learning the material. If any of the exercises stumps you, " @@ -15844,26 +15798,13 @@ msgid "" "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" -"こうした演習の敷居を下げることに繋がる読者のフィードバックが、本の向上の助け" -"になっています。" +"この先の章にはもっと沢山の演習があり、それらに取り組むうちに学習の助けになっているでしょう。\n" +"演習のどこかでお手上げになったら、本書の[困ったときは](chapter1.ja.md#getting-help)の節に挙げられているコミュニティの資料のどれかを見てみたり、[本書のリポジトリ](https://github.com/purescript-contrib/purescript-book/issues)にイシューを報告したりできます。\n" +"こうした演習の敷居を下げることに繋がる読者のフィードバックが、本書の向上の助けになっています。" #. type: Plain text #: text/chapter2.md:136 #, fuzzy -#| 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 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), please send us a PR." 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, " @@ -15873,15 +15814,11 @@ msgid "" "elegant solution (that only requires knowledge of the covered content), " "please send us a PR." msgstr "" -"章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べ" -"られます。\n" -"ただしカンニングしてはだめで、これらの演習を誠実に自力で解く労力を払わないこ" -"とがないようにしてください。\n" -"そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるよう" -"にしてください。\n" +"章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べられます。\n" +"ただしカンニングしてはだめで、これらの演習を誠実に自力で解く労力を払わないことがないようにしてください。\n" +"そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるようにしてください。\n" "演習のネタバレをするよりも、小さな手掛かりをあげたいからです。\n" -"もっとエレガントな解法(とはいえ本の内容で押さえられている知識のみを必要とす" -"るもの)を見つけたときはPRを送ってください。" +"もっとエレガントな解法(とはいえ本書の内容で押さえられている知識のみを必要とするもの)を見つけたときはPRを送ってください。" #. type: Plain text #: text/chapter2.md:137 @@ -18485,9 +18422,8 @@ msgid "" "structure algorithms. Recursion is a basic technique used in functional " "programming, which we will use throughout this book." msgstr "" -"この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて" -"見ていきましょう。再帰は関数型プログラミングの基本的な手法であり、この本の全" -"体に亙って使われます。" +"この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて見ていきましょう。\n" +"再帰は関数型プログラミングの基本的な手法であり、本書全体にわたって使われます。" #. type: Plain text #: text/chapter4.md:8 From 5350bfa7955f7579a6fcb65458884fd08276f26d Mon Sep 17 00:00:00 2001 From: gemmaro Date: Wed, 12 Jul 2023 08:37:58 +0900 Subject: [PATCH 04/29] [ update ] chapter 2 translation --- text-ja/chapter1.md | 16 +++++------ text-ja/chapter2.md | 67 ++++++++++++++++++--------------------------- text-ja/index.md | 6 ++-- translation/ja.po | 52 +++++++++-------------------------- 4 files changed, 50 insertions(+), 91 deletions(-) diff --git a/text-ja/chapter1.md b/text-ja/chapter1.md index a04f7ff2..3a1a805a 100644 --- a/text-ja/chapter1.md +++ b/text-ja/chapter1.md @@ -102,12 +102,12 @@ PureScriptのような関数型言語でアプリケーション開発の最初 - JavaScriptや、他のJavaScriptにコンパイルする言語でアプリケーションを書き、PureScriptでそのテストを書く - 既存のアプリケーションのユーザインターフェースのテストを自動化するためにPureScriptを使用する -この本では小規模な課題をPureScriptで解決することに焦点を当てます。 +本書では小規模な課題をPureScriptで解決することに焦点を当てます。 ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、JavaScriptからPureScriptコードを呼び出す方法、及びその逆についても見ていきます。 ## ソフトウェア要件 -この本でのソフトウェア要件は最小限です。 +本書のソフトウェア要件は最小限です。 第1章では開発環境の構築を一から案内します。 これから使用するツールは、ほとんどの現代のオペレーティングシステムの標準リポジトリで使用できるものです。 @@ -172,9 +172,9 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 各章には演習が含まれており、それぞれ難易度も示されています。 内容を完全に理解するために、各章の演習に取り組むことを強くお勧めします。 -この本は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。 -初心者にとって、本書は楽しい挑戦になるはずです。 -本書の内容を読み、演習に挑戦すれば得るものがあることでしょう。 +本書は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。 +初心者にとっては楽しい挑戦になるはずです。 +内容を読んで演習に挑戦すれば得るものがあることでしょう。 そして何よりも大切なのは、自分自身でコードを書いてみることです。 ## 困ったときには @@ -186,7 +186,7 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 - [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 @@ -222,8 +222,8 @@ JavaScriptでの経験をもとに、私は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/chapter2.md b/text-ja/chapter2.md index 31854009..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,20 +22,16 @@ PureScriptを書く上で(例えば本書の演習を解くなど)お好み ## 演習を解く -ここまでで必要な開発ツールをインストールできているので、この本のリポジトリをクローンしてください。 +ここまでで必要な開発ツールをインストールできているので、本書のリポジトリをクローンしてください。 ```sh git clone https://github.com/purescript-contrib/purescript-book.git ``` -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 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): +本書のリポジトリにはPureScriptのコード例と各章に付属する演習のための単体テストが含まれます。 +演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準備ができます。 +この工程は`resetSolutions.sh`スクリプトを使えば簡単にできます。 +また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくと良いでしょう(これらのアンカーはコード片を本書のMarkdownから書き出した媒体に複製するために使われており、自分のローカルリポジトリではこのアンカーで散らかっていないほうが良いでしょう)。 ```sh cd purescript-book @@ -62,19 +58,15 @@ spago test All 2 tests passed! 🎉 ``` -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 -(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. +なお、(`src/Euler.purs`にある)`answer`関数は任意の整数以下の3と5の倍数を見付けるように変更されています。 +(`test/Main.purs`にある)この`answer`関数のためのテストスートははじめの手引きの冒頭にあるテストよりも網羅的です。 +前の方の章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い詰めなくて大丈夫です。 -本の残りの部分には多くの演習が含まれます。 +本書の残りの部分には多くの演習が含まれます。 `Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、提供されているテストスートを使って確認できます。 -Let's work through this next exercise together in a test-driven-development -style. +テスト駆動開発でこの次の演習を一緒に進めてみましょう。 ## 演習 @@ -82,9 +74,9 @@ style. ## 解法 -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 -`{-` and end with `-}`: +この演習のテストを有効にするところから始めます。 +以下に示すようにブロックコメントの開始を数行下に下げてください。 +ブロックコメントは`{-`から始まり`-}`で終わります。 ```hs {{#include ../exercises/chapter2/test/Main.purs:diagonalTests}} @@ -104,8 +96,8 @@ at test/Main.purs:21:27 - 21:35 (line 21, column 27 - line 21, column 35) Unknown value diagonal ``` -Let's first look at what happens with a faulty version of this function. Add -the following code to `test/MySolutions.purs`: +まずはこの関数に欠陥があるときに何が起こるのか見てみましょう。 +以下のコードを`test/MySolutions.purs`に追加してください。 ```hs import Data.Number (sqrt) @@ -159,21 +151,14 @@ All 4 tests passed! 🎉 この章ではPureScriptコンパイラとSpagoツールをインストールしました。 演習の解答の書き方と正しさの確認方法も学びました。 -There will be many more exercises in the chapters ahead, and working through -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. - -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. 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 only requires knowledge of the covered content), -please send us a PR. +この先の章にはもっと沢山の演習があり、それらに取り組むうちに内容を学ぶ助けになっているでしょう。 +演習のどこかでお手上げになったら、本書の[困ったときは](chapter1.ja.md#getting-help)の節に挙げられているコミュニティの資料のどれかに手を伸ばしたり、[本書のリポジトリ](https://github.com/purescript-contrib/purescript-book/issues)でイシューを報告したりできます。 +こうした演習の敷居を下げることに繋がる読者のフィードバックのお陰で本書が改善されています。 + +章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べられます。 +カンニングはせず、演習を誠実に自力で解く労力を割いてください。 +そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるようにしてください。 +ネタバレをするよりも小さな手掛かりをあげたいからです。 +もっとエレガントな解法(とはいえ本書で押さえられている知識のみで済むもの)を見つけたときはPRを送ってください。 リポジトリは継続して改訂されているため、それぞれの新しい章を始める前に更新を確認するようにしてください。 diff --git a/text-ja/index.md b/text-ja/index.md index b2a34cad..73f5b14d 100644 --- a/text-ja/index.md +++ b/text-ja/index.md @@ -10,7 +10,7 @@ PureScriptのエコシステムの最新の機能を紹介すべく書き直さ ## 現状 -この本は言語の進化に伴って継続的に更新されているため、内容に関して発見したどんな[問題](https://github.com/purescript-contrib/purescript-book/issues)でもご報告ください。 +本書は言語の進化に伴って継続的に更新されているため、内容に関して発見したどんな[問題](https://github.com/purescript-contrib/purescript-book/issues)でもご報告ください。 より初心者にやさしくできそうな分かりづらい節を指摘するような単純なものであれ、共有いただいたどんなフィードバックにも感謝します。 それぞれの章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確かめることができます。 @@ -25,10 +25,10 @@ Haskellで書かれ、またこの言語から着想を得ています。 JavaScriptでの関数型プログラミングは最近かなりの人気を誇るようになりましたが、コードを書く上で統制された環境が欠けていることが大規模なアプリケーション開発の妨げとなっています。 PureScriptは、強力に型付けされた関数型プログラミングの力をJavaScriptでの開発の世界に持ち込むことにより、この問題の解決を目指しています。 -この本は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。 +本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。 それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。 -以下はこの本で解いていく課題の幾つかの例です。 +以下は本書で解いていく課題の幾つかの例です。 - マップと畳み込みを使ったデータ構造の変換 - アプリカティブ関手を使ったフォームフィールドの検証 diff --git a/translation/ja.po b/translation/ja.po index 9a1510a5..f4975cda 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-11 20:15+0900\n" +"PO-Revision-Date: 2023-07-12 08:37+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -15530,14 +15530,6 @@ msgstr "" #. type: Plain text #: text/chapter2.md:55 -#, fuzzy -#| 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." 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 " @@ -15546,12 +15538,9 @@ msgid "" "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" -"はじめの章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い" -"詰めなくて大丈夫です。" +"なお、(`src/Euler.purs`にある)`answer`関数は任意の整数以下の3と5の倍数を見付けるように変更されています。\n" +"(`test/Main.purs`にある)この`answer`関数のためのテストスートははじめの手引きの冒頭にあるテストよりも網羅的です。\n" +"前の方の章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い詰めなくて大丈夫です。" #. type: Plain text #: text/chapter2.md:57 @@ -15565,14 +15554,10 @@ msgstr "" #. type: Plain text #: text/chapter2.md:59 -#, fuzzy -#| msgid "" -#| "Let's work through this next exercise together in test-driven-development " -#| "style." msgid "" "Let's work through this next exercise together in a test-driven-development " "style." -msgstr "テスト駆動開発のスタイルでこの次の演習を一緒に進めてみましょう。" +msgstr "テスト駆動開発でこの次の演習を一緒に進めてみましょう。" #. type: Title ## #: text/chapter2.md:60 @@ -15598,11 +15583,6 @@ msgstr "解法" #. type: Plain text #: text/chapter2.md:67 -#, fuzzy -#| 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 `{-` and end with `-}`:" 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 `{-" @@ -15653,16 +15633,12 @@ msgstr "" #. type: Plain text #: text/chapter2.md:86 -#, fuzzy -#| 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`:" msgid "" "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 @@ -15788,7 +15764,6 @@ msgstr "" #. type: Plain text #: text/chapter2.md:134 -#, fuzzy msgid "" "There will be many more exercises in the chapters ahead, and working through " "those helps with learning the material. If any of the exercises stumps you, " @@ -15798,13 +15773,12 @@ msgid "" "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" -"こうした演習の敷居を下げることに繋がる読者のフィードバックが、本書の向上の助けになっています。" +"この先の章にはもっと沢山の演習があり、それらに取り組むうちに内容を学ぶ助けになっているでしょう。\n" +"演習のどこかでお手上げになったら、本書の[困ったときは](chapter1.ja.md#getting-help)の節に挙げられているコミュニティの資料のどれかに手を伸ばしたり、[本書のリポジトリ](https://github.com/purescript-contrib/purescript-book/issues)でイシューを報告したりできます。\n" +"こうした演習の敷居を下げることに繋がる読者のフィードバックのお陰で本書が改善されています。" #. type: Plain text #: text/chapter2.md:136 -#, fuzzy 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, " @@ -15815,10 +15789,10 @@ msgid "" "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 From f3c53c2b4152866981e6d64ec8ed82a5152fc39b Mon Sep 17 00:00:00 2001 From: gemmaro Date: Thu, 13 Jul 2023 08:50:19 +0900 Subject: [PATCH 05/29] [ add ] terms list --- translation/terms.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 translation/terms.txt diff --git a/translation/terms.txt b/translation/terms.txt new file mode 100644 index 00000000..57945f69 --- /dev/null +++ b/translation/terms.txt @@ -0,0 +1 @@ +primitive type: 原始型 From be3e6ff13ce4cc347866362f4db0bab85c299fde Mon Sep 17 00:00:00 2001 From: gemmaro Date: Thu, 13 Jul 2023 08:50:27 +0900 Subject: [PATCH 06/29] [ update ] chapter 3 translation --- text-ja/chapter3.md | 858 ++++++++++++++++++++++++++++++++++++++++++ translation/ja.po | 740 ++++++++---------------------------- translation/terms.txt | 2 + 3 files changed, 1012 insertions(+), 588 deletions(-) create mode 100644 text-ja/chapter3.md diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md new file mode 100644 index 00000000..12269aca --- /dev/null +++ b/text-ja/chapter3.md @@ -0,0 +1,858 @@ +# 関数とレコード + +## この章の目標 + +この章では、関数及びレコードというPureScriptプログラムの2つの構成要素を導入します。更に、どのようにPureScriptプログラムを構造化するのか、どのように型をプログラム開発に役立てるかを見ていきます。 + +連絡先のリストを管理する簡単な住所録アプリケーションを作成していきます。 +このコード例により、PureScriptの構文から幾つかの新しい概念を導入します。 + +このアプリケーションのフロントエンドは対話式モードであるPSCiを使うようにしていますが、このコードを土台にJavaScriptでフロントエンドを書くこともできるでしょう。 +実際に後の章で、フォームの検証と保存及び復元の機能を追加します。 + +## プロジェクトの準備 + +この章のソースコードは `src/Data/AddressBook.purs`というファイルに含まれています。 +このファイルは次のようなモジュール宣言とインポート一覧から始まります。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:imports}} +``` + +ここでは、幾つかのモジュールをインポートします。 + +- `Control.Plus`モジュールには`empty`値が定義されています。 +- `Data.List`モジュールは`lists`パッケージで提供されています。 + またこのパッケージはSpagoを使ってインストールできます。 + モジュールには連結リストを使うために必要な幾つかの関数が含まれています。 +- `Data.Maybe`モジュールは、省略可能な値を扱うためのデータ型と関数を定義しています。 + +訳者注:ダブルドット (`..`) を使用すると、 +指定された型コンストラクタのすべてのデータコンストラクタをインポートできます。 + +このモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください。明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。 + +ソースコードリポジトリをクローンしたと仮定すると、この章のプロジェクトは次のコマンドでSpagoを使用して構築できます。 + +```text +$ cd chapter3 +$ spago build +``` + +## 単純な型 + +JavaScriptの原始型に対応する組み込みデータ型として、PureScriptでは数値型と文字列型、真偽型の3つが定義されています。 +これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポートされます。 +それぞれ`Number`、`String`、`Boolean`と呼ばれており、PSCiで簡単な値の型を表示するのに`:type`コマンドを使うと確認できます。 + +```text +$ spago repl + +> :type 1.0 +Number + +> :type "test" +String + +> :type true +Boolean +``` + +PureScriptには他にも、整数、文字、配列、レコード、関数といった組み込み型が定義されています。 + +小数点以下を省くと整数になり、型 `Number`の浮動小数点数の値と区別されます。 + +```text +> :type 1 +Int +``` + +二重引用符を使用する文字列直値とは異なり、文字直値は一重引用符で囲みます。 + +```text +> :type 'a' +Char +``` + +配列はJavaScriptの配列に対応していますが、JavaScriptの配列とは異なり、PureScriptの配列の全ての要素は同じ型を持つ必要があります。 + +```text +> :type [1, 2, 3] +Array Int + +> :type [true, false] +Array Boolean + +> :type [1, false] +Could not match type Int with type Boolean. +``` + +最後の例は型検証器によるエラーを示しています。 +配列の2つの要素の型を*単一化*(つまり等価にする意)するのに失敗したのです。 + +レコードはJavaScriptのオブジェクトに対応しており、レコード直値はJavaScriptのオブジェクト直値と同じ構文になっています。 + +```text +> author = { name: "Phil", interests: ["Functional Programming", "JavaScript"] } + +> :type author +{ name :: String +, interests :: Array String +} +``` + +この型が示しているのは指定されたオブジェクトが2つの*フィールド*を持っているということです。 +それぞれ`String`型のフィールド`name`と`Array +String`型のフィールド`interests`で、後者は`String`の配列ということです。 + +ドットに続けて参照したいフィールドのラベルを書くとレコードのフィールドを参照できます。 + +```text +> author.name +"Phil" + +> author.interests +["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 +``` + +ファイルのトップレベルでは、等号の直前に引数を指定することで関数を定義できます。 + +```haskell +add :: Int -> Int -> Int +add x y = x + y +``` + +代えて、バックスラッシュ文字に続けて空白文字で区切られた引数名のリストを書くことで、関数をインラインでも定義できます。 +PSCiで複数行の宣言を入力するには、`:paste`コマンドを使用して「貼り付けモード」に入ります。 +このモードでは、*Control-D*キーシーケンスを使って宣言を終了します。 + +```text +> :paste +… add :: Int -> Int -> Int +… add = \x y -> x + y +… ^D +``` + +PSCiでこの関数が定義されていると、次のように関数の隣に2つの引数を空白で区切って書くことで、関数をこれらの引数に*適用* (apply) できます。 + +```text +> add 10 20 +30 +``` + +## 量化された型 + +前の節ではPreludeで定義された関数の型を幾つか見てきました。 +例えば`flip`関数は次のような型を持っていました。 + +```text +> :type flip +forall a b c. (a -> b -> c) -> b -> a -> c +``` + +この`forall`キーワードは、`flip`が*全称量化された型*を持つことを示しています。 +つまり`a`や`b`や`c`をどの型に置き換えても良く、`flip`はその型で動作するのです。 + +例えば、`a`を`Int`、`b`を`String`、`c`を`String`と選んだとします。 +その場合、`flip`の型を次のように*特殊化*できます。 + +```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コードです。 + +```haskell +add x y z = x + + y + z +``` + +しかし、次は正しいコードではありません。 + +```haskell +add x y z = x + +y + z +``` + +後者では、PureScriptコンパイラはそれぞれの行ごとに1つ、つまり*2つ*の宣言であると構文解析します。 + +一般に、同じブロック内で定義された宣言は同じ深さで字下げする必要があります。 +例えばPSCiでlet文の宣言は同じ深さで字下げしなければなりません。 +次は正しいコードです。 + +```text +> :paste +… x = 1 +… y = 2 +… ^D +``` + +しかし、これは正しくありません。 + +```text +> :paste +… x = 1 +… y = 2 +… ^D +``` + +PureScriptの幾つかの予約語(例えば `where`や `of`、 +`let`)は新たなコードのまとまりを導入しますが、そのコードのまとまり内の宣言はそれより深く字下げされている必要があります。 + +```haskell +example x y z = foo + bar + where + foo = x * y + bar = y * z +``` + +ここで `foo`や `bar`の宣言は `example`の宣言より深く字下げされていることに注意してください。 + +ただし、ソースファイルの先頭、最初の `module`宣言における予約語 `where`だけは、この規則の唯一の例外になっています。 + +## 独自の型の定義 + +PureScriptで新たな問題に取り組むときは、まずはこれから扱おうとする値の型の定義を書くことから始めるのがよいでしょう。最初に、住所録に含まれるレコードの型を定義してみます。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}} +``` + +これは`Entry`という*型同義語*を定義しています。 +型`Entry`は等号の右辺と等価ということです。 +レコードの型は`firstName`、`lastName`、`phone`という3つのフィールドからなります。 +2つの名前のフィールドは型`String`を持ち、`address`は以下で定義された型`Address`を持ちます。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Address}} +``` + +なお、レコードには他のレコードを含めることができます。 + +それでは、住所録のデータ構造として3つめの型同義語も定義してみましょう。 +単に項目の連結リストとして表すことにします。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}} +``` + +なお、`List Entry`は `Array Entry`とは同じではありません。 +後者は項目の*配列*を表しています。 + +## 型構築子と種 + +`List`は*型構築子*(type constructor、型コンストラクタ)の一例になっています。`List`そのものは型ではなく、何らかの型 +`a`があるとき `List a`が型になっています。つまり、 `List`は _型引数_ (type argument) `a`をとり、新たな型 +`List a`を _構築_ するのです。 + +なお、ちょうど関数適用と同じように、型構築子は他の型に並置するだけで適用されます。 +実際、型`List Entry`は型構築子`List`が型`Entry`に*適用*されたもので、項目のリストを表しています。 + +もし間違って(型注釈演算子 `::`を使って)型 `List`の値を定義しようとすると、今まで見たことのない種類のエラーが表示されるでしょう。 + +```text +> import Data.List +> Nil :: List +In a type-annotated expression x :: t, the type t must have kind Type +``` + +これは*種エラー*です。値がその*型*で区別されるのと同じように、型はその*種*によって区別されます。間違った型の値が*型エラー*になるように、*間違った種*の型は*種エラー*を引き起こします。 + +`Number`や `String`のような、値を持つ全ての型の種を表す `Type`と呼ばれる特別な種があります。 + +型構築子にも種があります。 +例えば種 `Type -> Type`はちょうど `List`のような型から型への関数を表しています。 +ここでエラーが発生したのは、値が種 `Type`であるような型を持つと期待されていたのに、 `List`は種 `Type -> Type`を持っているためです。 + +PSCiで型の種を調べるには、 `:kind`命令を使用します。例えば次のようになります。 + +```text +> :kind Number +Type + +> import Data.List +> :kind List +Type -> Type + +> :kind List String +Type +``` + +PureScriptの _種システム_ は他にも面白い種に対応していますが、それらについては本書の他の部分で見ていくことになるでしょう。 + +## 住所録の項目の表示 + +それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。 +まずは関数に型を与えることから始めます。 +型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくようにすると良いでしょう。 +実際、トップレベルの宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。 +型宣言は関数の名前とその型を `::`記号で区切るようにして書きます。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_signature}} +``` + +この型シグネチャが言っているのは、`showEntry`は引数として`Entry`を取り`String`を返す関数であるということです。 +以下は`showEntry`のコードです。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_implementation}} +``` + +この関数は`Entry`レコードの3つのフィールドを連結し、単一の文字列にします。 +ここで使用される`showAddress`関数は`address`フィールド中のレコードを文字列に変えます。 +`showAddress`の定義は次の通りです。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showAddress}} +``` + +関数定義は関数の名前で始まり、引数名のリストが続きます。関数の結果は等号の後ろに定義します。フィールドはドットに続けてフィールド名を書くことで参照できます。PureScriptでは、文字列連結はJavaScriptのような単一のプラス記号ではなく、ダイアモンド演算子(`<>`)を使用します。 + +## はやめにテスト、たびたびテスト + +PSCi対話式モードでは反応を即座に得られるので、素早い試作開発に向いています。 +それではこの最初の関数が正しく動作するかをPSCiを使用して確認してみましょう。 + +まず、これまでに書いたコードをビルドします。 + +```text +$ spago build +``` + +次に、PSCiを起動し、この新しいモジュールをインポートするために `import`命令を使います。 + +```text +$ spago repl + +> import Data.AddressBook +``` + +レコード直値を使うと、住所録の項目を作成できます。レコード直値はJavaScriptの無名オブジェクトと同じような構文で名前に束縛します。 + +```text +> address = { street: "123 Fake St.", city: "Faketown", state: "CA" } +``` + +それでは、この例に関数を適用してみてください。 + +```text +> showAddress address + +"123 Fake St., Faketown, CA" +``` + +`showEntry`も、住所の例を含む住所録項目レコードを作って試しましょう。 + +```text +> entry = { firstName: "John", lastName: "Smith", address: address } +> showEntry entry + +"Smith, John: 123 Fake St., Faketown, CA" +``` + +## 住所録の作成 + +今度は住所録を扱う補助関数を幾つか書いてみましょう。 +空の住所録を表す値が必要ですが、これは空のリストです。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:emptyBook}} +``` + +既存の住所録に値を挿入する関数も必要でしょう。この関数を `insertEntry`と呼ぶことにします。関数の型を与えることから始めましょう。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}} +``` + +この型シグネチャに書かれているのは、最初の引数として`Entry`、第2引数として`AddressBook`を取り、新しい`AddressBook`を返すということです。 + +既存の`AddressBook`を直接変更することはしません。 +代わりに、同じデータが含まれている新しい`AddressBook`を返します。 +このように`AddressBook`は*不変データ構造*の一例となっています。 +これはPureScriptにおける重要な考え方です。 +変更はコードの副作用であり、効率良く挙動を探る上で妨げになります。 +そのため可能な限り純粋関数や不変なデータにする方が好ましいのです。 + +`insertEntry`を実装するのに`Data.List`の`Cons`関数が使えます。 +この関数の型を見るには、PSCiを起動し `:type`コマンドを使います。 + +```text +$ spago repl + +> import Data.List +> :type Cons + +forall a. a -> List a -> List a +``` + +この型シグネチャで書かれているのは、`Cons`が何らかの型`a`の値と型`a`の要素のリストを取り、同じ型の項目を持つ新しいリストを返すということです。 +`a`を`Entry`型として特殊化してみましょう。 + +```haskell +Entry -> List Entry -> List Entry +``` + +しかし、 `List Entry`はまさに `AddressBook`ですから、次と同じになります。 + +```haskell +Entry -> AddressBook -> AddressBook +``` + +今回の場合、既に適切な入力があります。 +`Entry`と `AddressBook`に `Cons`を適用すると、新しい `AddressBook`を得ることができます。 +これこそがまさに求めていた関数です。 + +`insertEntry`の実装は次のようになります。 + +```haskell +insertEntry entry book = Cons entry book +``` + +こうすると、等号の左側にある2つの引数`entry`と`book`がスコープに導入されます。 +それから`Cons`関数を適用し、結果を作成しています。 + +## カリー化された関数 + +PureScriptでは、関数は常に1つの引数だけを取ります。 +`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。 + +`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。 + +```haskell +Entry -> (AddressBook -> AddressBook) +``` + +すなわち、`insertEntry`は関数を返す関数なのです。 +この関数は単一の引数`Entry`を取り、新しい関数を返します。 +今度はこの関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。 + +これはつまり、最初の引数だけを与えて`insertEntry`を*部分適用*できたりするということです。 +PSCiで結果の型が見られます。 + +```text +> :type insertEntry entry + +AddressBook -> AddressBook +``` + +期待した通り、戻り値の型は関数になっていました。 +この結果の関数に2つ目の引数も適用できます。 + +```text +> :type (insertEntry entry) emptyBook +AddressBook +``` + +ただし、ここでの括弧は不要です。 +以下は等価です。 + +```text +> :type insertEntry entry emptyBook +AddressBook +``` + +これは関数適用が左に結合するためで、なぜ空白で区切った引数を次々に関数に指定するだけでいいのかの説明にもなっています。 + +関数の型の`->`演算子は関数の*型構築子*です。 +この演算子は2つの型引数を取ります。 +左右の被演算子はそれぞれ関数の引数の型と返り値の型です。 + +本書では今後、「2引数の関数」というように表現することがあることに注意してください。 +しかしそれはカリー化された関数を意味していると考えるべきで、その関数は最初の引数を取り2つ目の引数を取る別の関数を返すのです。 + +今度は `insertEntry`の定義について考えてみます。 + +```haskell +insertEntry :: Entry -> AddressBook -> AddressBook +insertEntry entry book = Cons entry book +``` + +もし式の右辺に明示的に括弧をつけるなら、`(Cons entry) book`となります。 +つまり`insertEntry entry`はその引数が単に関数`(Cons entry)`に渡されるような関数だということです。 +ところがこの2つの関数はどんな入力についても同じ結果を返すので、となると同じ関数ではないですか。 +よって、両辺から引数`book`を削除できます。 + +```haskell +insertEntry :: Entry -> AddressBook -> AddressBook +insertEntry entry = Cons entry +``` + +しかし今や同様の議論により、両辺から `entry`も削除できます。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}} +``` + +この処理は*イータ変換*と呼ばれ、(その他の技法を併用して)*ポイントフリー形式*へと関数を書き換えるのに使えます。 +つまり、引数を参照せずに関数を定義できるのです。 + +`insertEntry`の場合、イータ変換によって「`insertEntry`は単にリストにおけるconsだ」となり、とても明快な関数の定義になりました。 +しかし、一般にポイントフリー形式のほうがいいのかどうかには議論の余地があります。 + +## プロパティ取得子 + +よくあるパターンの1つとして、レコード中の個別のフィールド(または「プロパティ」)を取得することがあります。 +`Entry`から`Address`を取り出すインライン関数は次のように書けます。 + +```haskell +\entry -> entry.address +``` + +PureScriptでは[_プロパティ取得子_](https://github.com/purescript/documentation/blob/master/language/Syntax.md#property-accessors)という略記が使えます。この略記では下線文字は無名関数の引数として振舞うため、上記のインライン関数は次と等価です。 + +```haskell +_.address +``` + +これは何段階のプロパティでも動くため、`Entry`に関連する街を取り出す関数は次のように書けます。 + +```haskell +_.address.city +``` + +以下は一例です。 + +```text +> address = { street: "123 Fake St.", city: "Faketown", state: "CA" } +> entry = { firstName: "John", lastName: "Smith", address: address } +> _.lastName entry +"Smith" + +> _.address.city entry +"Faketown" +``` + +## 住所録に問い合わせる + +最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索し適切な`Entry`を返すものです。 +これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるでしょう。 + +住所録を絞り込めば該当する姓名を持つ項目だけを保持するようにできます。 +そうすれば結果のリストの先頭(つまり最初)の要素を返せます。 + +この大まかな道筋の仕様があれば関数の型を計算できます。 +まずPSCiを開いて`filter`関数と`head`関数の型を探してみましょう。 + +```text +$ spago repl + +> import Data.List +> :type filter + +forall a. (a -> Boolean) -> List a -> List a + +> :type head + +forall a. List a -> Maybe a +``` + +型の意味を理解するために、これらの2つの型の一部を取り出してみましょう。 + +`filter`は2引数のカリー化された関数です。 +最初の引数は関数で、リストの要素を取り`Boolean`値を返します。 +第2引数は要素のリストで、返り値は別のリストです。 + +`head`は引数としてリストを取り、 `Maybe a`という今までに見たことがない型を返します。 +`Maybe +a`は型`a`の省略可能な値を表しており、JavaScriptのような言語で値がないことを示すための`null`を使う代わりとなる、型安全な代替を提供します。 +後の章で改めて詳しく見ていきます。 + +`filter`と `head`の全称量化された型は、PureScriptコンパイラによって次のように _特殊化_ (specialized) +されます。 + +```haskell +filter :: (Entry -> Boolean) -> AddressBook -> AddressBook + +head :: AddressBook -> Maybe Entry +``` + +関数の引数として姓名を渡す必要があるだろうということは分かっています。 + +`filter`に渡す関数も必要になることもわかります。この関数を `filterEntry`と呼ぶことにしましょう。 `filterEntry`は `Entry -> Boolean`という型を持っています。 `filter filterEntry`という関数適用の式は、 `AddressBook -> AddressBook`という型を持つでしょう。もしこの関数の結果を `head`関数に渡すと、型 `Maybe Entry`の結果を得ることになります。 + +これまでのことを纏めると、関数の妥当な型シグネチャは次のようになります。`findEntry`と呼ぶことにしましょう。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_signature}} +``` + +この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び`AddressBook`を引数に取り、省略可能な`Entry`を返すということです。 +省略可能な結果は名前が住所録に見付かった場合にのみ値を持ちます。 + +そして、 `findEntry`の定義は次のようになります。 + +```haskell +findEntry firstName lastName book = head (filter filterEntry book) + where + filterEntry :: Entry -> Boolean + filterEntry entry = entry.firstName == firstName && entry.lastName == lastName +``` + +一歩ずつこのコードを調べてみましょう。 + +`findEntry`は、どちらも文字列型である `firstName`と `lastName`、`AddressBook`型の +`book`という3つの名前をスコープに導入します。 + +定義の右辺では`filter`関数と`head`関数が組み合わさっています。 +まず項目のリストを絞り込み、その結果に`head`関数を適用しています。 + +真偽型を返す関数 `filterEntry`は `where`節の内部で補助的な関数として定義されています。 +このため、 `filterEntry`関数はこの定義の内部では使用できますが、外部では使用できません。 +また、`filterEntry`はそれを包む関数の引数に依存でき、 `filterEntry`は指定された `Entry`を絞り込むために引数 +`firstName`と `lastName`を使用しているので、 `filterEntry`が +`findEntry`の内部にあることは必須になっています。 + +なお、最上位での宣言と同じように、必ずしも`filterEntry`の型シグネチャを指定しなくても構いません。 +ただし、ドキュメントの一形態として指定しておくことが推奨されます。 + +## 中置の関数適用 + +これまでお話しした関数のほとんどは*前置*関数適用でした。 +関数名が引数の*前*に置かれていたということです。 +例えば`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`関数の中置別称として定義されています。 + +```haskell +infix 4 eq as == +``` + +したがって`filterEntry`中の`entry.firstName == firstName`は`eq entry.firstName +firstName`で置き換えられます。 +この節の後のほうで中置演算子を定義する例にもう少し触れます。 + +前置関数を演算子としての中置の位置に置くと、より読みやすいコードになる場面があります。 +その一例が`mod`関数です。 + +```text +> mod 8 3 +2 +``` + +上の用例でも充分動作しますが、読みにくいです。 +より馴染みのある表現の仕方は「8 mod 3」です。 +バックスラッシュ (\`) の中に前置関数を包むとそのように書けます。 + +```text +> 8 `mod` 3 +2 +``` + +同様に、`insertEntry`をバックスラッシュで包むと中置演算子に変わります。 +例えば以下の`book1`と`book2`は等価です。 + +```haskell +book1 = insertEntry john emptyBook +book2 = john `insertEntry` emptyBook +``` + +複数回`insertEntry`を適用することで複数の項目がある`AddressBook`を作ることができますが、以下のように前置関数 +(`book3`) として適用するか中置演算子 (`book4`) として適用するかの2択があります。 + +```haskell +book3 = insertEntry john (insertEntry peggy (insertEntry ned emptyBook)) +book4 = john `insertEntry` (peggy `insertEntry` (ned `insertEntry` emptyBook)) +``` + +`insertEntry`には中置演算子別称(または同義語)も定義できます。 +この演算子の名前に適当に`++`を選び、[優先度](https://github.com/purescript/documentation/blob/master/language/Syntax.md#precedence)を`5`にし、そして`infixr`を使って右[結合](https://github.com/purescript/documentation/blob/master/language/Syntax.md#associativity)とします。 + +```haskell +infixr 5 insertEntry as ++ +``` + +この新しい演算子で上の`book4`の例を次のように書き直せます。 + +```haskell +book5 = john ++ (peggy ++ (ned ++ emptyBook)) +``` + +新しい`++`演算子の右結合性により、意味を変えずに括弧を除去できます。 + +```haskell +book6 = john ++ peggy ++ ned ++ emptyBook +``` + +括弧を消去する他のよくある技法は、いつもの前置関数と一緒に`apply`の中置演算子`$`を使うというものです。 + +例えば前の`book3`の例は以下のように書き直せます。 + +```haskell +book7 = insertEntry john $ insertEntry peggy $ insertEntry ned emptyBook +``` + +括弧を`$`で置き換えるのは大抵入力しやすくなりますし(議論の余地がありますが)読みやすくなります。 +この記号の意味を覚えるための記憶術として、ドル記号を2つの括弧に打ち消し線が引かれたものと見ることで、これで括弧が不必要になったのだと推測できるという方法があります。 + +なお、`($)`は言語にハードコードされた特別な構文ではありません。 +単に`apply`という名前の普通の関数のための中置演算子であって、`Data.Function`で以下のように定義されています。 + +```haskell +apply :: forall a b. (a -> b) -> a -> b +apply f x = f x + +infixr 0 apply as $ +``` + +`apply`関数は、他の関数(型は`(a -> b)`)を最初の引数に、値(型は`a`)を2つ目の引数に取って、その値に対して関数を呼びます。 +この関数が何ら意味のあることをしていないようだと思ったら、全くもって正しいです。 +この関数がなくてもプログラムは論理的に同一です([参照透過性](https://en.wikipedia.org/wiki/Referential_transparency)も見てください)。 +この関数の構文的な利便性はその中置演算子に割り当てられた特別な性質からきています。 +`$`は右結合 (`infixr`) で低い優先度 (`0`) の演算子ですが、これにより深い入れ子になった適用から括弧の束を削除できるのです。 + +さらなる`$`演算子を使った括弧退治のチャンスは以前の`findEntry`関数にあります。 + +```haskell +findEntry firstName lastName book = head $ filter filterEntry book +``` + +この行をより簡潔に書き換える方法を次節の「関数合成」で見ていきます。 + +名前の短い中置演算子を前置関数として使いたければ括弧で囲むことができます。 + +```text +> 8 + 3 +11 + +> (+) 8 3 +11 +``` + +その代わりの手段として演算子は部分適用でき、これには式を括弧で囲んで[演算子節](https://github.com/purescript/documentation/blob/master/language/Syntax.md#operator-sections)中の引数として`_`を使います。これは簡単な無名関数を作るより便利な方法として考えることができます(以下の例ではそこから無名関数を名前に束縛しているので、もはや別に無名とも言えなくなっていますが)。 + +```text +> add3 = (3 + _) +> add3 2 +5 +``` + +纏めると、以下は引数に`5`を加える関数の等価な定義です。 + +```haskell +add5 x = 5 + x +add5 x = add 5 x +add5 x = (+) 5 x +add5 x = 5 `add` x +add5 = add 5 +add5 = \x -> 5 + x +add5 = (5 + _) +add5 x = 5 `(+)` x -- よおポチ、中置に目がないっていうから、中置の中に中置を入れといたぜ +``` + +## 関数合成 + +イータ変換を使うと `insertEntry`関数を簡略化できたのと同じように、引数をよく考察すると `findEntry`の定義を簡略化できます。 + +なお、引数 `book`は関数 `filter filterEntry`に渡され、この適用の結果が `head`に渡されます。これは言いかたを変えれば、 +`filter filterEntry`と `head`の _合成_ (composition) に `book`が渡されるということです。 + +PureScriptの関数合成演算子は `<<<`と `>>>`です。前者は「逆方向の合成」であり、後者は「順方向の合成」です。 + +何れかの演算子を使用して `findEntry`の右辺を書き換えることができます。 +逆順の合成を使用すると、右辺は次のようになります。 + +```haskell +(head <<< filter filterEntry) book +``` + +この形式なら最初の定義にイータ変換の技を適用でき、 `findEntry`は最終的に次のような形式に到達します。 + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_implementation}} + ... +``` + +右辺を次のようにしても同じく妥当です。 + +```haskell +filter filterEntry >>> head +``` + +どちらにしても、これは「`findEntry`は絞り込み関数と`head`関数の合成である」という +`findEntry`関数のわかりやすい定義を与えます。 + +どちらの定義のほうが分かりやすいかの判断はお任せしますが、このように関数を部品として捉えるとしばしば有用です。 +各関数は1つの役目をこなすようにし、解法を関数合成を使って組み立てるのです。 + +## 演習 + + 1. (簡単)`findEntry`関数の定義の主な部分式の型を書き下し、 `findEntry`関数についてよく理解しているか試してみましょう。 + 例えば`findEntry`の定義の中にある `head`関数の型は `AddressBook -> Maybe + Entry`と特殊化されています。 + *補足*:この問題にはテストがありません。 + 1. (普通)関数`findEntryByStreet :: String -> AddressBook -> Maybe + Entry`を書いてください。 + この関数は与えられた通りの住所から`Entry`を見付け出します。 + *手掛かり*:`findEntry`にある既存のコードを再利用してください。 + 実装した関数をPSCiと`spago test`を走らせてテストしてください。 + 1. (普通)`filterEntry`を(`<<<`や`>>>`を使った)合成で置き換えて、`findEntryByStreet`を書き直してください。 + 合成の対象は、プロパティ取得子(`_.`記法を使います)と、与えられた文字列引数が与えられた通りの住所に等しいかを判定する関数です。 + 1. (普通)名前が`AddressBook`に存在するかどうかを調べて真偽値で返す関数`isInBook`を書いてみましょう。 + *手掛かり*:PSCiを使って`Data.List.null`関数の型を見付けてください。 + この関数はリストが空かどうかを調べます。 + 1. (難しい)「重複」している住所録の項目を削除する関数`removeDuplicates`を書いてみましょう。 + 項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複していると考えます。 + *手掛かり*:`Data.List.nubByEq`関数の型をPSCiを使って調べましょう。 + この関数は等価性の述語に基づいてリストから重複要素を削除します。 + なお、それぞれの重複する項目の集合において最初の要素(リストの先頭に最も近い)が保持する項目です。 + +## まとめ + +この章では関数型プログラミングの新しい概念を幾つか押さえ、以下の方法を学びました。 + +- 対話的モードのPSCiを使用して、関数で実験したり思いついたことを試したりする。 +- 正確さのための道具として、また実装のための道具として型を使う。 +- 多引数の関数を表現するためにカリー化された関数を使う。 +- 合成により小さな部品からプログラムを作る。 +- `where`式を使ってコードを手際良く構造化する。 +- `Maybe`型を使用してnull値を回避する。 +- イータ変換や関数合成のような技法を使ってより分かりやすい仕様にリファクタする。 + +次の章からは、これらの考えかたに基づいて進めていきます。 diff --git a/translation/ja.po b/translation/ja.po index f4975cda..497155ed 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-12 08:37+0900\n" +"PO-Revision-Date: 2023-07-14 21:38+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -8484,20 +8484,14 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_case}}\n" #. type: Plain text #: text/chapter11.md:803 #, fuzzy -#| 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 the `Just` constructor." 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 " "the `Just` constructor." msgstr "" -"`lookup`関数は `Maybe`型構築子で示されたオプショナルな結果を返します。\n" -"`lookup`関数は、キーがマップにない場合は `Nothing`を返し、それ以外の場合は " -"`Just`構築子で対応する値を返します。" +"`lookup`関数は `Maybe`型構築子で示された省略可能な結果を返します。\n" +"`lookup`関数は、キーがマップにない場合は `Nothing`を返し、それ以外の場合は `Just`構築子で対応する値を返します。" #. type: Plain text #: text/chapter11.md:805 @@ -11453,7 +11447,7 @@ msgid "" "This approach is taken in the `drawing` package, and it brings the " "flexibility of manipulating the scene as data in various ways before " "rendering." -msgstr "この手法は `drawing`パッケージでも採用されており、描画前にさまざまな方法でデータとしてシーンを操作できる柔軟性を齎しています。" +msgstr "この手法は `drawing`パッケージでも採用されており、描画前に様々な方法でデータとしてシーンを操作できる柔軟性を齎しています。" #. type: Plain text #: text/chapter12.md:612 @@ -14777,12 +14771,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:580 #, fuzzy -#| msgid "" -#| "Suppose we want to generate HTML documents which 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:" msgid "" "Suppose we want to generate HTML documents that contain hyperlinks to " "different sections of the document using _anchors_. We can accomplish this " @@ -14790,11 +14778,9 @@ msgid "" "document: once at the anchor's definition and once in each hyperlink. " "However, this approach has some basic issues:" msgstr "" -"*アンカー*を使用して文書のさまざまな節へのハイパーリンクが含まれているHTML文" -"書を生成するとします。\n" +"*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を生成するとします。\n" "これは既に達成できています。\n" -"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めればよいので" -"す。\n" +"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めればよいのです。\n" "1つはアンカーの定義自身に、もう1つはそれぞれのハイパーリンクにあります。\n" "しかし、この方法には根本的な問題が幾つかあります。" @@ -15872,28 +15858,21 @@ msgstr "`Control.Plus`モジュールには`empty`値が定義されています #. type: Bullet: '- ' #: text/chapter3.md:24 -#, fuzzy -#| 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 working with linked lists." msgid "" "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 msgid "" "The `Data.Maybe` module, which defines data types and functions for working " "with optional values." -msgstr "" -"`Data.Maybe`モジュールは、オプショナルな値を扱うためのデータ型と関数を定義し" -"ています。" +msgstr "`Data.Maybe`モジュールは、省略可能な値を扱うためのデータ型と関数を定義しています。" #. type: Plain text #: text/chapter3.md:26 @@ -15933,14 +15912,6 @@ msgstr "単純な型" #. type: Plain text #: text/chapter3.md:37 -#, fuzzy -#| msgid "" -#| "PureScript defines three built-in types which correspond 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:" msgid "" "PureScript defines three built-in types corresponding to JavaScript's " "primitive types: numbers, strings, and booleans. These are defined in the " @@ -15948,12 +15919,9 @@ msgid "" "`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" -"これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポート" -"されます。\n" -"これらはそれぞれ `Number`、 `String`、 `Boolean`と呼ばれており、PSCiで`:type`" -"コマンドを使うと簡単な値の型を表示させて確認できます。" +"JavaScriptの原始型に対応する組み込みデータ型として、PureScriptでは数値型と文字列型、真偽型の3つが定義されています。\n" +"これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポートされます。\n" +"それぞれ`Number`、`String`、`Boolean`と呼ばれており、PSCiで簡単な値の型を表示するのに`:type`コマンドを使うと確認できます。" #. type: Fenced code block (text) #: text/chapter3.md:38 @@ -15983,10 +15951,6 @@ msgstr "" #. type: Plain text #: text/chapter3.md:52 -#, fuzzy -#| msgid "" -#| "PureScript defines some other built-in types: integers, characters, " -#| "arrays, records, and functions." msgid "" "PureScript defines other built-in types: integers, characters, arrays, " "records, and functions." @@ -16063,18 +16027,12 @@ msgstr "" #. type: Plain text #: text/chapter3.md:81 -#, fuzzy -#| 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." msgid "" "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 @@ -16105,19 +16063,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:94 -#, fuzzy -#| 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." msgid "" "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 @@ -16194,24 +16146,15 @@ msgstr "" #. type: Plain text #: text/chapter3.md:124 -#, fuzzy -#| 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:" msgid "" "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" -"このモードでは、*Control-D*キーシーケンスを使用して宣言を終了します。" +"代えて、バックスラッシュ文字に続けて空白文字で区切られた引数名のリストを書くことで、関数をインラインでも定義できます。\n" +"PSCiで複数行の宣言を入力するには、`:paste`コマンドを使用して「貼り付けモード」に入ります。\n" +"このモードでは、*Control-D*キーシーケンスを使って宣言を終了します。" #. type: Fenced code block (text) #: text/chapter3.md:125 @@ -16273,34 +16216,23 @@ msgstr "" #. type: Plain text #: text/chapter3.md:149 -#, fuzzy -#| 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." msgid "" "The keyword `forall` here indicates that `flip` has a _universally " "quantified type_. It means 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`はその型でうまく動作するという意味です。" +"この`forall`キーワードは、`flip`が*全称量化された型*を持つことを示しています。\n" +"つまり`a`や`b`や`c`をどの型に置き換えても良く、`flip`はその型で動作するのです。" #. type: Plain text #: text/chapter3.md:151 -#, fuzzy -#| 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" 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) できます。" +"例えば、`a`を`Int`、`b`を`String`、`c`を`String`と選んだとします。\n" +"その場合、`flip`の型を次のように*特殊化*できます。" #. type: Fenced code block (text) #: text/chapter3.md:152 @@ -16310,11 +16242,6 @@ msgstr "(Int -> String -> String) -> String -> Int -> String\n" #. type: Plain text #: text/chapter3.md:157 -#, fuzzy -#| 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:" 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 `flip` as if it had " @@ -16322,8 +16249,7 @@ msgid "" msgstr "" "量化された型を特殊化したいということをコードで示す必要はありません。\n" "特殊化は自動的に行われます。\n" -"例えば次のように単に`flip`を使用できます。\n" -"あたかも既にその型の`flip`を持っていたかのようです。" +"例えば、あたかも既にその型の`flip`を持っていたかのように、`flip`を使えます。" #. type: Fenced code block (text) #: text/chapter3.md:158 @@ -16339,13 +16265,6 @@ msgstr "" #. type: Plain text #: text/chapter3.md:165 -#, fuzzy -#| 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:" 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 " @@ -16353,11 +16272,9 @@ msgid "" "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" +"`a`、`b`、`c`の型はどんな型でも選べるといっても、一貫していなければなりません。\n" +"`flip`に渡す関数の型は他の引数の型と整合性がなくてはなりません。\n" +"第2引数として文字列`\"Ten\"`、第3引数として数`10`を渡したのはそれが理由です。\n" "もし引数が逆になっているとうまくいかないでしょう。" #. type: Fenced code block (text) @@ -16402,8 +16319,6 @@ msgstr "" #. type: Plain text #: text/chapter3.md:179 -#, fuzzy -#| msgid "Therefore, the following is valid PureScript code:" msgid "Therefore, the following is a valid PureScript code:" msgstr "したがって、次は正しいPureScriptコードです。" @@ -16419,8 +16334,6 @@ msgstr "" #. type: Plain text #: text/chapter3.md:186 -#, fuzzy -#| msgid "But this is not valid code:" msgid "But this is not a valid code:" msgstr "しかし、次は正しいコードではありません。" @@ -16471,8 +16384,6 @@ msgstr "" #. type: Plain text #: text/chapter3.md:204 -#, fuzzy -#| msgid "but this is not:" msgid "But this is not:" msgstr "しかし、これは正しくありません。" @@ -16557,13 +16468,6 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:Entry}}\n" #. type: Plain text #: text/chapter3.md:234 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 " @@ -16571,13 +16475,10 @@ msgid "" "will have the type `String`, and the `address` field will have the type " "`Address`, defined as follows:" msgstr "" -"これは `Entry`という*型同義語*(type synonym、型シノニム)を定義していま" -"す。\n" -"型 `Entry`は等号の右辺と同じ型ということです。\n" -"レコードの型は何れも文字列である `firstName`、 `lastName`、 `phone`という3つ" -"のフィールドからなります。\n" -"前者の2つのフィールドは型 `String`を持ち、 `address`は以下のように定義された" -"型 `Address`を持っています。" +"これは`Entry`という*型同義語*を定義しています。\n" +"型`Entry`は等号の右辺と等価ということです。\n" +"レコードの型は`firstName`、`lastName`、`phone`という3つのフィールドからなります。\n" +"2つの名前のフィールドは型`String`を持ち、`address`は以下で定義された型`Address`を持ちます。" #. type: Fenced code block (haskell) #: text/chapter3.md:235 @@ -16592,16 +16493,12 @@ msgstr "なお、レコードには他のレコードを含めることができ #. type: Plain text #: text/chapter3.md:242 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 @@ -16611,16 +16508,12 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:AddressBook}} #. type: Plain text #: text/chapter3.md:248 -#, fuzzy -#| msgid "" -#| "Note that `List Entry` is not the same as `Array Entry`, which represents " -#| "an _array_ of entries." msgid "" "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 @@ -16642,21 +16535,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:254 -#, fuzzy -#| 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 of entries." 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 " "of entries." msgstr "" -"ちょうど関数適用と同じように、型構築子は他の型に並べることで適用されることに" -"注意してください。型 `List Entry`は実は型構築子 `List`が型 `Entry`に _適用_ " -"されたものです。これは住所録項目のリストを表しています。" +"なお、ちょうど関数適用と同じように、型構築子は他の型に並置するだけで適用されます。\n" +"実際、型`List Entry`は型構築子`List`が型`Entry`に*適用*されたもので、項目のリストを表しています。" #. type: Plain text #: text/chapter3.md:256 @@ -16781,19 +16667,13 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:showEntry_sig #. type: Plain text #: text/chapter3.md:294 -#, fuzzy -#| msgid "" -#| "This type signature says that `showEntry` is a function, which takes an " -#| "`Entry` as an argument and returns a `String`. Here is the code for " -#| "`showEntry`:" msgid "" "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 @@ -16928,16 +16808,12 @@ msgstr "住所録の作成" #. type: Plain text #: text/chapter3.md:351 -#, fuzzy -#| 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." msgid "" "Now let's write some utility functions for working with address books. We " "will need a value representing an empty address book: an empty list." msgstr "" -"今度は住所録の操作を支援する関数を幾つか書いてみましょう。\n" -"空の住所録を表す値が必要ですが、これには空のリストを使います。" +"今度は住所録を扱う補助関数を幾つか書いてみましょう。\n" +"空の住所録を表す値が必要ですが、これは空のリストです。" #. type: Fenced code block (haskell) #: text/chapter3.md:352 @@ -16962,29 +16838,14 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_s #. type: Plain text #: text/chapter3.md:363 -#, fuzzy -#| 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 " -#| "`AddressBook`." msgid "" "This type signature says that `insertEntry` takes an `Entry` as its first " "argument, an `AddressBook` as a second argument, and returns a new " "`AddressBook`." -msgstr "" -"この型シグネチャに書かれているのは、最初の引数として `Entry`、第二引数として " -"`AddressBook`を取り、新しい `AddressBook`を返すということです。" +msgstr "この型シグネチャに書かれているのは、最初の引数として`Entry`、第2引数として`AddressBook`を取り、新しい`AddressBook`を返すということです。" #. type: Plain text #: text/chapter3.md:365 -#, fuzzy -#| 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 reason effectively about its behavior, so we prefer pure functions and " -#| "immutable data where possible." msgid "" "We don't modify the existing `AddressBook` directly. Instead, we return a " "new `AddressBook`, which contains the same data. As such, `AddressBook` is " @@ -16993,14 +16854,12 @@ msgid "" "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 @@ -17031,19 +16890,12 @@ msgstr "" #. type: Plain text #: text/chapter3.md:378 -#, fuzzy -#| msgid "" -#| "This type signature says that `Cons` takes a value of some type `a`, and " -#| "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:" msgid "" "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) @@ -17089,18 +16941,13 @@ msgstr "insertEntry entry book = Cons entry book\n" #. type: Plain text #: text/chapter3.md:398 -#, fuzzy -#| 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." 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." msgstr "" -"等号の左側にある2つの引数`entry`と`book`がスコープに導入されますから、これら" -"に `Cons`関数を適用して結果の値を作成しています。" +"こうすると、等号の左側にある2つの引数`entry`と`book`がスコープに導入されます。\n" +"それから`Cons`関数を適用し、結果を作成しています。" #. type: Title ## #: text/chapter3.md:399 @@ -17110,19 +16957,13 @@ msgstr "カリー化された関数" #. type: Plain text #: text/chapter3.md:402 -#, fuzzy -#| 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_." msgid "" "Functions in PureScript take exactly one argument. While it looks like the " "`insertEntry` function takes two arguments, it is an example of a _curried " "function_." msgstr "" -"PureScriptでは、関数は常に1つの引数だけを取ります。`insertEntry`関数は2つの引" -"数を取るように見えますが、これは実際には*カリー化された関数*の一例となってい" -"ます。" +"PureScriptでは、関数は常に1つの引数だけを取ります。\n" +"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。" #. type: Plain text #: text/chapter3.md:404 @@ -17138,32 +16979,23 @@ msgstr "Entry -> (AddressBook -> AddressBook)\n" #. type: Plain text #: text/chapter3.md:410 -#, fuzzy -#| 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`." msgid "" "That is, `insertEntry` is a function that 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`." msgstr "" -"すなわち、 `insertEntry`は関数を返す関数である、ということです。\n" -"この関数は単一の引数 `Entry`を取り、それから単一の引数 `AddressBook`を取り新" -"しい `AddressBook`を返す新しい関数を返すのです。" +"すなわち、`insertEntry`は関数を返す関数なのです。\n" +"この関数は単一の引数`Entry`を取り、新しい関数を返します。\n" +"今度はこの関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。" #. type: Plain text #: text/chapter3.md:412 -#, fuzzy -#| 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:" msgid "" "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 @@ -17198,14 +17030,12 @@ msgstr "" #. type: Plain text #: text/chapter3.md:427 -#, fuzzy -#| msgid "" -#| "Note though that the parentheses here are unnecessary - the following is " -#| "equivalent:" msgid "" "Note though, that the parentheses here are unnecessary – the following is " "equivalent:" -msgstr "ここで括弧は不要であることにも注意してください。次の式は同等です。" +msgstr "" +"ただし、ここでの括弧は不要です。\n" +"以下は等価です。" #. type: Fenced code block (text) #: text/chapter3.md:428 @@ -17219,23 +17049,15 @@ msgstr "" #. type: Plain text #: text/chapter3.md:434 -#, fuzzy -#| 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." msgid "" "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 "" -"これは関数適用が左結合であるためで、なぜ空白で区切った引数を関数に指定するだ" -"けでいいのかの説明にもなっています。" +msgstr "これは関数適用が左に結合するためで、なぜ空白で区切った引数を次々に関数に指定するだけでいいのかの説明にもなっています。" #. type: Plain text #: text/chapter3.md:436 -#, fuzzy, 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" +#, 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" msgstr "" "関数の型の`->`演算子は関数の*型構築子*です。\n" @@ -17272,13 +17094,6 @@ msgstr "" #. type: Plain text #: text/chapter3.md:447 -#, fuzzy -#| 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:" 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 " @@ -17286,12 +17101,10 @@ msgid "" "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 @@ -17316,36 +17129,23 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry}} #. type: Plain text #: text/chapter3.md:460 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| 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." 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 the point-free form is better in general." msgstr "" -"`insertEntry`の場合には、イータ変換によって「`insertEntry`は単にリストに対す" -"るconsだ」となり、関数の定義はとても明確になりました。しかし、一般的にポイン" -"トフリー形式のほうがいいのかどうかには議論の余地があります。" +"`insertEntry`の場合、イータ変換によって「`insertEntry`は単にリストにおけるconsだ」となり、とても明快な関数の定義になりました。\n" +"しかし、一般にポイントフリー形式のほうがいいのかどうかには議論の余地があります。" #. type: Title ## #: text/chapter3.md:463 @@ -17437,52 +17237,34 @@ msgstr "住所録に問い合わせる" #. type: Plain text #: text/chapter3.md:498 -#, fuzzy -#| 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." 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." msgstr "" -"最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索" -"し適切な `Entry`を返すものです。これは小さな関数を組み合わせることでプログラ" -"ムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるで" -"しょう。" +"最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索し適切な`Entry`を返すものです。\n" +"これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるでしょう。" #. type: Plain text #: text/chapter3.md:500 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| 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` " -#| "and `head` functions:" 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` " "and `head` functions:" msgstr "" -"この大まかな仕様に従って、この関数の型を計算できます。まずPSCiを起動し、 " -"`filter`関数と `head`関数の型を見てみましょう。" +"この大まかな道筋の仕様があれば関数の型を計算できます。\n" +"まずPSCiを開いて`filter`関数と`head`関数の型を探してみましょう。" #. type: Fenced code block (text) #: text/chapter3.md:503 @@ -17518,31 +17300,18 @@ msgstr "" #. type: Plain text #: text/chapter3.md:519 -#, fuzzy -#| 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." 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. " "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 -#, fuzzy -#| msgid "" -#| "`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." msgid "" "`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 " @@ -17550,12 +17319,9 @@ msgid "" "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 @@ -17580,14 +17346,10 @@ msgstr "" #. type: Plain text #: text/chapter3.md:531 -#, fuzzy -#| 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." 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 "検索する関数の引数として姓と名前を渡す必要があるのもわかっています。" +msgstr "関数の引数として姓名を渡す必要があるだろうということは分かっています。" #. type: Plain text #: text/chapter3.md:533 @@ -17612,22 +17374,14 @@ msgstr "{{#include ../exercises/chapter3/src/Data/AddressBook.purs:findEntry_sig #. type: Plain text #: text/chapter3.md:541 -#, fuzzy -#| msgid "" -#| "This type signature says that `findEntry` takes two strings, the first " -#| "and last names, and a `AddressBook`, and returns an optional `Entry`. The " -#| "optional result will contain a value only if the name is found in the " -#| "address book." msgid "" "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" -"オプショナルな結果は名前が住所録で発見された場合にのみ値を持ちます。" +"この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び`AddressBook`を引数に取り、省略可能な`Entry`を返すということです。\n" +"省略可能な結果は名前が住所録に見付かった場合にのみ値を持ちます。" #. type: Plain text #: text/chapter3.md:543 @@ -17664,18 +17418,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:556 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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 @@ -17697,19 +17446,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:560 -#, fuzzy -#| msgid "" -#| "Note that, just like for top-level declarations, it was not necessary to " -#| "specify a type signature for `filterEntry`. However, doing so is " -#| "recommended as a form of documentation." msgid "" "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 @@ -17719,21 +17462,15 @@ msgstr "中置の関数適用" #. type: Plain text #: text/chapter3.md:564 -#, fuzzy -#| 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 `AddressBook`, we might write:" msgid "" "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 @@ -17743,16 +17480,6 @@ msgstr "> book1 = insertEntry john emptyBook\n" #. type: Plain text #: text/chapter3.md:570 -#, fuzzy -#| 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:" msgid "" "However, this chapter has also included examples of _infix_ [binary " "operators](https://github.com/purescript/documentation/blob/master/language/" @@ -17762,12 +17489,10 @@ msgid "" "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/" -"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)の例も含まれています。\n" +"例えば`filterEntry`の定義中の`==`演算子で、2つの引数の*間*に置かれています。\n" +"PureScriptのソースコードでこうした中置演算子は隠れた*前置*の実装への中置別称として定義されています。\n" +"例えば`==`は以下の行により前置の`eq`関数の中置別称として定義されています。" #. type: Fenced code block (haskell) #: text/chapter3.md:571 @@ -17777,33 +17502,21 @@ msgstr "infix 4 eq as ==\n" #. type: Plain text #: text/chapter3.md:576 -#, fuzzy -#| 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." msgid "" "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`で置き換えられます。この節の後のほうで中置演算子を定義す" -"る例にもう少し触れます。" +"したがって`filterEntry`中の`entry.firstName == firstName`は`eq entry.firstName firstName`で置き換えられます。\n" +"この節の後のほうで中置演算子を定義する例にもう少し触れます。" #. type: Plain text #: text/chapter3.md:578 -#, fuzzy -#| 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:" msgid "" "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) @@ -17818,19 +17531,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:585 -#, fuzzy -#| msgid "" -#| "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 (\\`):" msgid "" "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 @@ -17917,14 +17625,10 @@ msgstr "book5 = john ++ (peggy ++ (ned ++ emptyBook))\n" #. type: Plain text #: text/chapter3.md:618 -#, fuzzy -#| msgid "" -#| "and the right associativity of our new `++` operator lets us get rid of " -#| "the parentheses without changing the meaning:" msgid "" "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 @@ -17968,19 +17672,13 @@ msgstr "" #. type: Plain text #: text/chapter3.md:634 -#, fuzzy -#| msgid "" -#| "Note that `$` isn't special syntax that's hardcoded into the language. " -#| "It's simply the infix operator for a regular function called `apply`, " -#| "which is defined in `Data.Function` as follows:" msgid "" "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 @@ -18202,21 +17900,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:713 -#, fuzzy -#| 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." msgid "" "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 @@ -18261,33 +17952,17 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter3.md:721 -#, fuzzy -#| msgid "" -#| "(Medium) Write a function `isInBook` which 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." msgid "" "(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 -#, fuzzy -#| 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." msgid "" "(Difficult) Write a function `removeDuplicates` which removes \"duplicate\" " "address book entries. We'll consider entries duplicated if they share the " @@ -18297,85 +17972,56 @@ msgid "" "first element in each set of duplicates (closest to the list head) is the " "one that is kept." msgstr "" -"(難しい)「重複」している項目を住所録から削除する関数 `removeDuplicates`を書" -"いてみましょう。\n" -"項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複してい" -"ると考えます。\n" -"*手掛かり*:関数 `Data.List.nubBy`の型を、PSCiを使用して調べてみましょう。\n" -"この関数は値同士の等価性を定義する述語関数に基づいてリストから重複要素を削除" -"します。\n" -"なお、それぞれの重複する項目の集合における最初の要素(リストの先頭に最も近" -"い)が保持する項目です。" +"(難しい)「重複」している住所録の項目を削除する関数`removeDuplicates`を書いてみましょう。\n" +"項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複していると考えます。\n" +"*手掛かり*:`Data.List.nubByEq`関数の型をPSCiを使って調べましょう。\n" +"この関数は等価性の述語に基づいてリストから重複要素を削除します。\n" +"なお、それぞれの重複する項目の集合において最初の要素(リストの先頭に最も近い)が保持する項目です。" #. type: Plain text #: text/chapter3.md:725 -#, fuzzy -#| 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 "この章では、関数型プログラミングの新しい概念を幾つも導入しました。" +msgstr "この章では関数型プログラミングの新しい概念を幾つか押さえ、以下の方法を学びました。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| 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 "" -"対話的モードのPSCiを使用して、関数を調べるなどの思いついたことを試す方法" +msgstr "対話的モードのPSCiを使用して、関数で実験したり思いついたことを試したりする。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| 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 "検証や実装の道具としての型の役割" +msgstr "正確さのための道具として、また実装のための道具として型を使う。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| msgid "" -#| "The use of curried functions to represent functions of multiple arguments." msgid "Use curried functions to represent functions of multiple arguments." -msgstr "多引数関数を表現する、カリー化された関数の使用" +msgstr "多引数の関数を表現するためにカリー化された関数を使う。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| msgid "Creating programs from smaller components by composition." msgid "Create programs from smaller components by composition." -msgstr "関数合成で小さな部品を組み合わせてのプログラムの構築" +msgstr "合成により小さな部品からプログラムを作る。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| msgid "Structuring code neatly using `where` expressions." msgid "Structure code neatly using `where` expressions." -msgstr "`where`節を利用したコードの構造化" +msgstr "`where`式を使ってコードを手際良く構造化する。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| msgid "How to avoid null values by using the `Maybe` type." msgid "Avoid null values by using the `Maybe` type." -msgstr "`Maybe`型を使用してnull値を回避する方法" +msgstr "`Maybe`型を使用してnull値を回避する。" #. type: Bullet: '- ' #: text/chapter3.md:733 -#, fuzzy -#| msgid "" -#| "Using techniques like eta conversion and function composition to refactor " -#| "code into a clear specification." msgid "" "Use techniques like eta conversion and function composition to refactor code " "into a clear specification." -msgstr "" -"イータ変換や関数合成のような手法を利用した、よりわかりやすいコードへの再構成" +msgstr "イータ変換や関数合成のような技法を使ってより分かりやすい仕様にリファクタする。" #. type: Plain text #: text/chapter3.md:734 @@ -20980,12 +20626,6 @@ msgstr "それ以外の場合、関数は最後の行の式を評価して返し #. type: Plain text #: text/chapter5.md:54 #, fuzzy -#| msgid "" -#| "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." msgid "" "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 " @@ -20993,10 +20633,8 @@ msgid "" "different ways to choose names from the input arguments." msgstr "" "なお、パターンでは値を名前に束縛できます。\n" -"この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛して" -"います。\n" -"さまざまな種類のパターンについて学んでいくうちに、それぞれの種類のパターンが" -"入力の引数から名前を選ぶさまざまな方法に対応することがわかるでしょう。" +"この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛しています。\n" +"様々な種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力の引数から名前を選ぶ様々な方法に対応することがわかるでしょう。" #. type: Title ## #: text/chapter5.md:55 @@ -22147,7 +21785,7 @@ msgid "" "Here is its definition from the `maybe` package:" msgstr "" "それではPureScriptの標準ライブラリから別の例を見てみましょう。\n" -"オプショナルな値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。\n" +"省略可能な値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。\n" "`maybe`パッケージでは `Maybe`を次のように定義しています。" #. type: Fenced code block (haskell) @@ -22875,7 +22513,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 @@ -23047,9 +22685,7 @@ msgstr "" 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`できます。" +msgstr "この例では様々な原始型の値を `show`しましたが、もっと複雑な型を持つ値も`show`できます。" #. type: Fenced code block (text) #: text/chapter6.md:69 @@ -23911,17 +23547,11 @@ msgstr "" #. type: Plain text #: text/chapter6.md:312 #, fuzzy -#| 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." 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 as mapping the " "composition of the two functions over the structure." -msgstr "" -"第二の法則は _合成律_ (composition law) です。構造を1つの関数で写してから2つ" -"めの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。" +msgstr "第2の法則は _合成律_ (composition law) です。構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。" #. type: Plain text #: text/chapter6.md:314 @@ -26129,10 +25759,7 @@ msgstr "" 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 "" -"この型クラスのインスタンスで書かれているのは、任意のオプショナルな値にオプ" -"ショナルな関数を適用でき、その両方が定義されている時に限り結果も定義される、" -"ということです。" +msgstr "この型クラスのインスタンスで書かれているのは、任意の省略可能な値に省略可能な関数を適用でき、その両方が定義されている時に限り結果も定義される、ということです。" #. type: Plain text #: text/chapter7.md:129 @@ -26364,10 +25991,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:205 #, fuzzy, 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" @@ -26597,10 +26223,8 @@ msgid "" "convert optional inputs into computations which can signal an error using " "`Either String`:" msgstr "" -"`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エ" -"ラーメッセージを返すことができるようになります。\n" -"まずは`Either String`を使ってオプショナルな入力をエラーを発信できる計算に変換" -"する演算子を書きましょう。" +"`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エラー文言を返せるようになります。\n" +"まずは`Either String`を使い、省略可能な入力からエラーを発信できる計算に変換する演算子を書きましょう。" #. type: Fenced code block (text) #: text/chapter7.md:270 @@ -26912,12 +26536,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:376 #, fuzzy -#| msgid "" -#| "When specialized to `Maybe`, our function returns a `Just` only if every " -#| "list element was `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 result itself if every computation contained a result." msgid "" "When specialized to `Maybe`, our function returns a `Just` only if every " "list element is `Just`; otherwise, it returns `Nothing`. This is consistent " @@ -26925,12 +26543,9 @@ msgid "" "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 @@ -26957,21 +26572,14 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:386 #, fuzzy -#| 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`." 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`." msgstr "" -"(普通)数値演算子`+`、`-`、`*`、`/`のオプショナル引数(つまり`Maybe`に包まれ" -"た引数)を扱って`Maybe`に包まれた値を返す版を書いてください。\n" -"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けま" -"す。\n" +"(普通)数値演算子`+`、`-`、`*`、`/`の省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返す版を書いてください。\n" +"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けます。\n" "*手掛かり*:`lift2`を使ってください。" #. type: Bullet: ' 1. ' @@ -26989,22 +26597,15 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:386 #, fuzzy -#| 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." 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 with an optional result." msgstr "" -"(難しい)型`combineMaybe : forall a f. (Applicative f) => Maybe (f a) -> f " -"(Maybe a)`\n" +"(難しい)型`combineMaybe : forall a f. (Applicative f) => Maybe (f a) -> f (Maybe a)`\n" "を持つ関数`combineMaybe`を書いてください。\n" -"この関数は副作用をもつオプショナルな計算をとり、オプショナルな結果をもつ副作" -"用のある計算を返します。" +"この関数は副作用をもつ省略可能な計算をとり、省略可能な結果をもつ副作用のある計算を返します。" #. type: Plain text #: text/chapter7.md:390 @@ -27813,12 +27414,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:639 #, fuzzy -#| 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 for optional values of type `a`." msgid "" "These examples show that traversing the `Nothing` value returns `Nothing` " "with no validation, and traversing `Just x` uses the validation function to " @@ -27826,10 +27421,8 @@ msgid "" "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`のオプショナルな値についての検証関数を返すのです。" +"これらの例では、`Nothing`の値の走査は検証なしで`Nothing`の値を返し、`Just x`を走査すると`x`を検証するのに検証関数が使われるということを示しています。\n" +"要は、`traverse`は型`a`についての検証関数をとり、`Maybe a`についての検証関数、つまり型`a`の省略可能な値についての検証関数を返すのです。" #. type: Plain text #: text/chapter7.md:641 @@ -27964,10 +27557,8 @@ msgid "" "this new `Person`. _Hint_: Use `traverse` to validate a field of type `Maybe " "a`." msgstr "" -"(普通)`homeAddress`フィールドがオプショナル(`Maybe`を使用)な新しい版の" -"`Person`型をつくってください。\n" -"それからこの新しい`Person`を検証する新しい版の`validatePerson`" -"(`validatePersonOptionalAddress`と改名します)を書いてください。\n" +"(普通)`homeAddress`フィールドが省略可能(`Maybe`を使用)な新しい版の`Person`型をつくってください。\n" +"それからこの新しい`Person`を検証する新しい版の`validatePerson`(`validatePersonOptionalAddress`と改名します)を書いてください。\n" "*手掛かり*:`traverse`を使って型`Maybe a`のフィールドを検証してください。" #. type: Bullet: ' 1. ' @@ -28202,20 +27793,14 @@ msgstr "作用モナド" #. type: Plain text #: text/chapter8.md:6 #, fuzzy -#| 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_." msgid "" "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" +"この章では、より表現力の高い方法で副作用を扱うための別の抽象化、*モナド*を導入します。" #. type: Plain text #: text/chapter8.md:8 @@ -28374,12 +27959,8 @@ msgid "" "the _array monad_, embedding PureScript functions into a larger programming " "language supporting _non-deterministic choice_." msgstr "" -"前の章では、*オプショナルな値*に対応したより大きなプログラミング言語へと" -"PureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養" -"いました。\n" -"同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング" -"言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができま" -"す。" +"前の章では、*省略可能な値*に対応したより大きなプログラミング言語へとPureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養いました。\n" +"同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができます。" #. type: Plain text #: text/chapter8.md:52 @@ -28965,26 +28546,18 @@ msgstr "" msgid "" "Intuitively, `foldM` performs a fold over a list in some context supporting " "some set of side-effects." -msgstr "" -"直感的には、 `foldM`はさまざまな副作用の組み合わせに対応した文脈での配列の畳" -"み込みを行うと捉えることができます。" +msgstr "直感的には、`foldM`は様々な副作用の組み合わせに対応した文脈で配列を畳み込むものと捉えられます。" #. type: Plain text #: text/chapter8.md:225 #, fuzzy -#| 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 result, and the result of the fold is therefore also optional." 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 " "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 @@ -30716,12 +30289,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:698 #, fuzzy -#| msgid "" -#| "We are going to build a form which 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 errors will be displayed. As the user types text into the text " -#| "boxes, the validation errors will be updated." msgid "" "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 " @@ -30730,8 +30297,7 @@ msgid "" "validation errors will be updated." msgstr "" "利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。\n" -"フォームには、さまざまなフィールド(姓、名前、都市、州など)のテキストボック" -"ス、及び検証エラーが表示される領域が含まれます。\n" +"フォームには、様々なフィールド(姓、名前、都市、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。\n" "テキストボックスに利用者がテキストを入力すると、検証エラーが更新されます。" #. type: Plain text @@ -31761,9 +31327,7 @@ 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`モナドを使いました。" +msgstr "乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作といった、様々な作用を扱うために `Effect`モナドを使いました。" #. type: Plain text #: text/chapter8.md:1012 diff --git a/translation/terms.txt b/translation/terms.txt index 57945f69..b39e68fc 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -1 +1,3 @@ primitive type: 原始型 +type synonym: 型同義語 +optional: 省略可能な From ad7e9ee9273634c44001947cc7c96a74cadc453e Mon Sep 17 00:00:00 2001 From: gemmaro Date: Sun, 16 Jul 2023 08:51:54 +0900 Subject: [PATCH 07/29] =?UTF-8?q?[=20change=20]=20'=E7=B4=AF=E7=A9=8D'=20-?= =?UTF-8?q?>=20'=E7=B4=AF=E7=AE=97'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- translation/ja.po | 430 ++++++++++-------------------------------- translation/terms.txt | 1 + 2 files changed, 97 insertions(+), 334 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index 497155ed..ccae0dfa 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-14 21:38+0900\n" +"PO-Revision-Date: 2023-07-16 08:51+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -6440,26 +6440,14 @@ msgstr "Writerモナド" #. type: Plain text #: text/chapter11.md:278 #, fuzzy -#| msgid "" -#| "The `Writer` monad provides the ability to accumulate a secondary value " -#| "in addition to the return value of a computation." msgid "" "The `Writer` monad allows accumulating a secondary value in addition to the " "return value of a computation." -msgstr "" -"`Writer`モナドは、計算の返り値に加えて、もう1つの値を累積していく機能を提供し" -"ます。" +msgstr "`Writer`モナドは、計算の返り値に加えて、もう1つの値を累算していく機能を提供します。" #. type: Plain text #: text/chapter11.md:280 #, fuzzy -#| 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." 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 accumulate a value " @@ -6467,12 +6455,8 @@ msgid "" "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`値の何れかが真であるかどうかを追跡するのに使うことができます。" +"よくある使い方としては型 `String`もしくは `Array String`でログを累算していくというものなどがありますが、 `Writer`モナドはこれよりもっと一般的なものです。\n" +"累算するのに任意のモノイドの値を使うことができ、`Additive Int`モノイドを使って、合計を追跡し続けるのに使ったり、 `Disj Boolean`モノイドを使って途中の `Boolean`値の何れかが真であるかどうかを追跡するのに使うことができます。" #. type: Plain text #: text/chapter11.md:282 @@ -6503,7 +6487,7 @@ msgstr "tell :: forall w a. Monoid w => w -> Writer w Unit\n" msgid "" "The `tell` action appends the provided value to the current accumulated " "result." -msgstr "`tell`アクションは、与えられた値を現在の累積結果に付け加えます。" +msgstr "`tell`アクションは、与えられた値を現在の累算結果に付け加えます。" #. type: Plain text #: text/chapter11.md:292 @@ -6613,9 +6597,7 @@ msgstr "" 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`は累積されたログと結果の両方を返します。" +msgstr "ちょうど `State`モナドの場合と同じように、 `execWriter`が累算されたログだけを返すのに対して、 `runWriter`は累算されたログと結果の両方を返します。" #. type: Plain text #: text/chapter11.md:333 @@ -13212,14 +13194,11 @@ msgstr "現状のライブラリには幾つもの問題があります。" #. type: Bullet: '- ' #: text/chapter14.md:87 #, fuzzy -#| msgid "" -#| "Creating HTML documents is difficult - every new element requires at " -#| "least one record and one data constructor." msgid "" "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: '- ' @@ -14483,17 +14462,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:481 #, fuzzy -#| 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." msgid "" "First, we have to choose a monad in which we can interpret our actions. We " "will use the `Writer String` monad to accumulate an HTML string as our " "result." msgstr "" "まず、アクションを解釈できるモナドを選ばなければなりません。\n" -"`Writer String`モナドを使って、結果のHTML文字列を累積することにします。" +"`Writer String`モナドを使って、結果のHTML文字列を累算することにします。" #. type: Plain text #: text/chapter14.md:483 @@ -14537,9 +14512,7 @@ msgstr "" msgid "" "The definition of `renderElement` is straightforward, using the `tell` " "action from the `Writer` monad to accumulate several small strings:" -msgstr "" -"`renderElement`の定義は直感的で、複数の小さな文字列を累積するために `Writer`" -"モナドの `tell`アクションを使っています。" +msgstr "`renderElement`の定義は直感的で、複数の小さな文字列を累算するために `Writer`モナドの `tell`アクションを使っています。" #. type: Fenced code block (haskell) #: text/chapter14.md:499 @@ -18030,8 +18003,7 @@ msgstr "次の章からは、これらの考えかたに基づいて進めてい #. type: Title # #: text/chapter4.md:1 -#, fuzzy, no-wrap -#| msgid "Recursion, Maps And Folds" +#, no-wrap msgid "Recursion, Maps, And Folds" msgstr "再帰、マップ、畳み込み" @@ -18047,11 +18019,6 @@ msgstr "" #. type: Plain text #: text/chapter4.md:8 -#, fuzzy -#| 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`." msgid "" "We will also cover some standard functions from PureScript's standard " "libraries. We will `map`, `fold`, and some useful special cases, like " @@ -18063,21 +18030,14 @@ msgstr "" #. type: Plain text #: text/chapter4.md:10 -#, fuzzy -#| 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 " -#| "represented by a model of a filesystem." 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 that compute properties of the files " "represented by a model of a filesystem." msgstr "" -"この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用" -"います。この章で学ぶ手法を応用して、擬似的なファイルシステムによって表される" -"ファイルのプロパティを計算する関数を記述します。" +"この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用います。\n" +"この章で学ぶ技術を応用し、ファイルシステムのモデルにより表現されるファイルのプロパティを計算する関数を書きます。" #. type: Plain text #: text/chapter4.md:14 @@ -18173,29 +18133,19 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factorial}}\n" #. type: Plain text #: text/chapter4.md:38 -#, fuzzy -#| 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." msgid "" "Here, we can see how the factorial function is computed by reducing the " "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 -#, fuzzy -#| msgid "" -#| "Here is another common example, which computes the _Fibonacci function_:" msgid "Here is another common example that computes the _Fibonacci function_:" -msgstr "" -"次は、 _フィボナッチ関数_ (Fibonacci function) を計算するという、これまたよく" -"ある例です。" +msgstr "次は、*フィボナッチ関数*を計算するという、これまたよくある例です。" #. type: Fenced code block (haskell) #: text/chapter4.md:41 @@ -18219,10 +18169,11 @@ msgstr "" #. type: Plain text #: text/chapter4.md:48 -#, fuzzy, 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." +#, 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`を使う代わりにパターン照合を使うものでしょう。パターン照合の技法は後の章でお話しします。" +msgstr "" +"> なお上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。\n" +"> パターン照合の技法は後の章でお話しします。\n" #. type: Title ## #: text/chapter4.md:49 @@ -18273,33 +18224,18 @@ msgstr "" #. type: Plain text #: text/chapter4.md:65 -#, fuzzy -#| 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 length that is one more than the length of its tail." 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 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大きいというわけです。" +"この関数では配列が空かどうかで分岐するために`if ... then ... else`式を使っています。\n" +"この`null`関数は空の配列で`true`を返します。\n" +"空の配列の長さはゼロであり、空でない配列の長さは尾鰭の長さより1大きいというわけです。" #. type: Plain text #: text/chapter4.md:67 -#, fuzzy -#| 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`." 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), " @@ -18307,56 +18243,35 @@ msgid "" "`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`に包まれた値を返します。" +"`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返します。\n" +"配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。\n" +"`fromMaybe`関数は既定値と`Maybe`値を取ります。\n" +"後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返します。" #. type: Plain text #: text/chapter4.md:69 -#, fuzzy -#| 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:" msgid "" "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で配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえ" -"ませんが、次の演習を完遂するための手がかりとしては充分でしょう。" +msgstr "JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえませんが、次の演習を完遂するための手掛かりとしては充分でしょう。" #. type: Bullet: ' 1. ' #: text/chapter4.md:74 -#, fuzzy -#| msgid "" -#| "(Easy) Write a recursive function `isEven` which returns `true` if and " -#| "only if its input is an even integer." msgid "" "(Easy) Write a recursive function `isEven` that returns `true` if and only " "if its input is an even integer." -msgstr "" -"(簡単)入力が偶数であるとき、かつそのときに限り`true`に返すような再帰関数を" -"書いてみましょう。" +msgstr "(簡単)入力が偶数であるとき、かつそのときに限り`true`に返す再帰関数`isEven`を書いてみましょう。" #. type: Bullet: ' 2. ' #: text/chapter4.md:74 -#, fuzzy -#| msgid "" -#| "(Medium) Write a recursive function `countEven` which 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." msgid "" "(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 @@ -18366,37 +18281,25 @@ msgstr "マップ" #. type: Plain text #: text/chapter4.md:78 -#, fuzzy -#| 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)." 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)." msgstr "" -"`map`関数は配列に対する再帰関数の1つです。この関数を使うと、配列の各要素に順" -"番に関数を適用することで、配列の要素を変換できます。そのため、配列の*内容*は" -"変更されますが、その*形状*(ここでは「長さ」)は保存されます。" +"`map`関数は配列に対する再帰関数の一例です。\n" +"配列の各要素に順番に関数を適用し、配列の要素を変換するのに使われます。\n" +"そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存されます。" #. type: Plain text #: text/chapter4.md:80 -#, fuzzy -#| msgid "" -#| "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_." msgid "" "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 @@ -18421,11 +18324,6 @@ msgstr "" #. type: Plain text #: text/chapter4.md:92 -#, fuzzy -#| msgid "" -#| "Notice how `map` is used - we provide a function which should be \"mapped " -#| "over\" the array in the first argument, and the array itself in its " -#| "second." msgid "" "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." @@ -18470,10 +18368,9 @@ msgstr "" #. type: Plain text #: text/chapter4.md:105 -#, fuzzy, 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" +#, no-wrap msgid "There is an operator which is equivalent to the `map` function when used with arrays, called `<$>`.\n" -msgstr "配列を扱うときは、`map`関数と等価な`<$>`という演算子が存在します。この演算子は他の二項演算子と同じように中置で使用できます。\n" +msgstr "配列を扱う際は`map`関数と等価な`<$>`という演算子が存在します。\n" #. type: Fenced code block (text) #: text/chapter4.md:106 @@ -18541,14 +18438,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:133 -#, fuzzy, 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" +#, 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 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 @@ -18780,21 +18676,14 @@ msgstr "" #. type: Plain text #: text/chapter4.md:205 -#, fuzzy -#| 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." msgid "" "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 @@ -18873,10 +18762,6 @@ msgstr "" #. type: Plain text #: text/chapter4.md:229 -#, fuzzy -#| msgid "" -#| "We can perform this computation using an array comprehension. We will do " -#| "so in steps, using PSCi as our interactive development environment." msgid "" "We can perform this computation using array comprehension. We will do so in " "steps, using PSCi as our interactive development environment." @@ -19055,10 +18940,11 @@ msgstr "" #. type: Plain text #: text/chapter4.md:292 -#, fuzzy, 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." +#, 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) の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。" +msgstr "" +"> *補足*:`map`と`concatMap`があることで*配列内包表記*を書けるように、もっと一般的な演算子である`map`と`bind`があることで*モナド内包表記*と呼ばれているものが書けます。\n" +"> 本書の後半では*モナド*の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。\n" #. type: Plain text #: text/chapter4.md:294 @@ -19074,54 +18960,35 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factors}}\n" #. type: Plain text #: text/chapter4.md:300 -#, fuzzy -#| msgid "" -#| "The keyword `do` introduces a block of code which uses do notation. The " -#| "block consists of expressions of a few types:" msgid "" "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 -#, fuzzy -#| msgid "" -#| "Expressions which 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." msgid "" "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 -#, fuzzy -#| msgid "" -#| "Expressions which 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]`." msgid "" "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 -#, fuzzy -#| msgid "" -#| "Expressions which give names to expressions, using the `let` keyword." msgid "Expressions that give names to expressions, using the `let` keyword." msgstr "`let`キーワードを使用し、式に名前を与える式。" @@ -19154,17 +19021,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:315 -#, fuzzy -#| 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`:" msgid "" "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 @@ -19274,18 +19136,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:360 -#, fuzzy -#| 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 `false`, then its result is empty." msgid "" "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`と評価された場合は、その結果は空です。" +"つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返すのです。\n" +"もし式が`false`と評価された場合は、その結果は空です。" #. type: Plain text #: text/chapter4.md:362 @@ -19308,26 +19165,16 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 -#, fuzzy -#| msgid "" -#| "(Easy) Write a function `isPrime` which tests if its integer argument is " -#| "prime or not. _Hint_: Use the `factors` function." msgid "" "(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 -#, fuzzy -#| 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." 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 " @@ -19341,13 +19188,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter4.md:369 -#, fuzzy -#| msgid "" -#| "(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 triple_ is an array of numbers `[a, b, c]` such that `a² + " -#| "b² = c²`. _Hint_: Use the `guard` function in an array comprehension." msgid "" "(Medium) Write a function `triples :: Int -> Array (Array Int)`, which takes " "a number `n` and returns all Pythagorean triples whose components (the `a`, " @@ -19355,21 +19195,13 @@ msgid "" "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. ' #: text/chapter4.md:369 -#, fuzzy -#| 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." msgid "" "(Difficult) Write a function `primeFactors` which produces the [prime " "factorization](https://www.mathsisfun.com/prime-factorization.html) of `n`, " @@ -19377,12 +19209,9 @@ msgid "" "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" -"*手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してくださ" -"い。\n" +"(難しい)`factors`関数を使用して、`n`の[素因数分解](https://www.mathsisfun.com/prime-factorization.html)を求める関数`primeFactors`を定義してみましょう。\n" +"`n`の素因数分解とは、積が`n`であるような素数の配列のことです。\n" +"*手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してください。\n" "最初の因数を探し、それから残りの因数を探すのです。" #. type: Title ## @@ -19393,23 +19222,13 @@ msgstr "畳み込み" #. type: Plain text #: text/chapter4.md:373 -#, fuzzy -#| msgid "" -#| "Left and right folds over arrays provide another class of interesting " -#| "functions which can be implemented using recursion." msgid "" "Left and right folds over arrays provide another class of interesting " "functions that can be implemented using recursion." -msgstr "" -"配列における左右の畳み込みは、再帰を用いて実装される別の興味深い一揃いの関数" -"を提供します。" +msgstr "配列における左右の畳み込みは、再帰を用いて実装できる別の興味深い一揃いの関数を提供します。" #. type: Plain text #: text/chapter4.md:375 -#, fuzzy -#| msgid "" -#| "Start by importing the `Data.Foldable` module, and inspecting the types " -#| "of the `foldl` and `foldr` functions using PSCi:" msgid "" "Start by importing the `Data.Foldable` module and inspecting the types of " "the `foldl` and `foldr` functions using PSCi:" @@ -19439,19 +19258,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:387 -#, fuzzy -#| 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:" msgid "" "These types are more general than we are interested in right now. For this " "chapter, we can assume that PSCi has given the following (more specific) " "answer:" msgstr "" "これらの型は、現在興味があるものよりも一般化されています。\n" -"この章の目的に対して、PSCiは以下の(より具体的な)答えをくれていると考えてお" -"きましょう。" +"この章では、PSCiは以下の(より具体的な)答えをくれていると考えておきましょう。" #. type: Fenced code block (text) #: text/chapter4.md:388 @@ -19472,18 +19285,14 @@ msgstr "" #. type: Plain text #: text/chapter4.md:397 #, fuzzy -#| 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\", which will accumulate a result as we traverse the array." msgid "" "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 @@ -19499,9 +19308,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:401 #, fuzzy, 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" 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 "実際にこれらの関数の動きを見てみましょう。`foldl`を使用して数の配列の和を求めてみます。型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。ここでは、次の要素を累積器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累積器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。最初の引数としては、加算演算子を使用できますし、累積器の初期値はゼロになります。\n" +msgstr "" +"実際にこれらの関数の動きを見てみましょう。\n" +"`foldl`を使用して数の配列の和を求めてみます。\n" +"型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。\n" +"ここでは、次の要素を累算器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累算器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。\n" +"最初の引数としては、加算演算子を使用できますし、累算器の初期値はゼロになります。\n" #. type: Fenced code block (text) #: text/chapter4.md:402 @@ -19753,27 +19566,20 @@ msgstr "" #: text/chapter4.md:475 #, no-wrap msgid "Accumulators" -msgstr "累積器" +msgstr "累算器" #. type: Plain text #: text/chapter4.md:478 #, fuzzy -#| 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." msgid "" "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 @@ -19843,34 +19649,23 @@ msgstr "" #. type: Plain text #: text/chapter4.md:498 #, fuzzy -#| 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." 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 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 #, fuzzy -#| msgid "" -#| "Note also that while we might think of the accumulator as \"state\", " -#| "there is no direct mutation going on." msgid "" "Note also that while we might think of the accumulator as a \"state\", there " "is no direct mutation." -msgstr "" -"累積器を「状態」と考えることもできますが、直接には変更されているわけではない" -"ことにも注意してください。" +msgstr "累算器を「状態」と考えることもできますが、直接には変更されているわけではないことにも注意してください。" #. type: Title ## #: text/chapter4.md:501 @@ -19974,9 +19769,8 @@ msgid "" "(Medium) Write a function `fibTailRec` which is the same as `fib` but in " "tail recursive form. _Hint_: Use an accumulator parameter." msgstr "" -"(普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`" -"を書いてください。\n" -"*手掛かり*:累積器引数を使ってください。" +"(普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`を書いてください。\n" +"*手掛かり*:累算器引数を使ってください。" #. type: Bullet: ' 4. ' #: text/chapter4.md:527 @@ -20342,14 +20136,6 @@ msgstr "" #. type: Plain text #: text/chapter4.md:633 #, fuzzy -#| 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." msgid "" "In this chapter, we covered the basics of recursion in PureScript to express " "algorithms concisely. We also introduced user-defined infix operators, " @@ -20358,12 +20144,9 @@ msgid "" "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" -"また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関" -"数、及びこれらの概念を組み合わせた配列内包表記を導入しました。\n" -"最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの" -"重要性、累積器引数を使用して末尾再帰形に関数を変換する方法を示しました。" +"この章では、アルゴリズムを簡潔に表現する手段として、PureScriptでの再帰の基本を説明しました。\n" +"また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関数、及びこれらの概念を組み合わせた配列内包表記を導入しました。\n" +"最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。" #. type: Title # #: text/chapter5.md:1 @@ -22328,9 +22111,7 @@ msgid "" "`bounds` uses the `foldl` function from `Data.Foldable` to traverse the " "array of `Shapes` in a `Picture`, and accumulate the smallest bounding " "rectangle:" -msgstr "" -"`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累積するため、`bounds`に" -"は `Data.Foldable`の `foldl`関数を使用しています。" +msgstr "`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累算するため、`bounds`には `Data.Foldable`の `foldl`関数を使用しています。" #. type: Fenced code block (haskell) #: text/chapter5.md:516 @@ -22357,10 +22138,9 @@ 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 @@ -23231,21 +23011,14 @@ msgstr "ここでも文字列や配列はモノイドの簡単な例になって #. type: Plain text #: text/chapter6.md:229 #, fuzzy -#| 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:" 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 that concatenates an array of " "values in some monoid using a fold. In PSCi:" msgstr "" -"`Monoid`型クラスインスタンスでは、「空」の値から始めて新たな値を合成してい" -"き、その型で*累積*した結果を返すにはどうするかを記述する型クラスです。\n" -"例えば、畳み込みを使って幾つかのモノイドの値の配列を連結する関数を書くことが" -"できます。\n" +"`Monoid`型クラスインスタンスでは、「空」の値から始めて新たな値を合成していき、その型で*累算*した結果を返すにはどうするかを記述する型クラスです。\n" +"例えば、畳み込みを使って幾つかのモノイドの値の配列を連結する関数を書くことができます。\n" "PSCiで試すと次のようになります。" #. type: Fenced code block (haskell) @@ -24178,17 +23951,13 @@ msgstr "" #. type: Plain text #: text/chapter6.md:482 #, fuzzy -#| 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 elements of a stream:" msgid "" "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:483 @@ -27264,9 +27033,7 @@ msgstr "" msgid "" "In general, `traverse` walks over the elements of a data structure, " "performing computations with side-effects and accumulating a result." -msgstr "" -"一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算" -"し、結果を累積します。" +msgstr "一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算し、結果を累算します。" #. type: Plain text #: text/chapter7.md:595 @@ -28703,18 +28470,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:270 #, fuzzy -#| msgid "" -#| "The `foldM safeDivide` function returns `Nothing` if a division by zero " -#| "was attempted at any point. Otherwise it returns the result of repeatedly " -#| "dividing the accumulator, wrapped in the `Just` constructor." msgid "" "The `foldM safeDivide` function returns `Nothing` if a division by zero was " "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`構築子に包んで返します。" +"もし何れかの時点で整数にならない除算が行われようとしたら、`foldM safeDivide`関数は `Nothing`を返します。\n" +"そうでなければ、除算を繰り返した累算の結果を`Just`構築子に包んで返します。" #. type: Title ## #: text/chapter8.md:271 diff --git a/translation/terms.txt b/translation/terms.txt index b39e68fc..9dadae76 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -1,3 +1,4 @@ primitive type: 原始型 type synonym: 型同義語 optional: 省略可能な +accumulator: 累算器。「累積」とされることもあるようです。 From 63e692bee799c23b14979055afc562fdf93aab0f Mon Sep 17 00:00:00 2001 From: gemmaro Date: Sun, 16 Jul 2023 08:58:01 +0900 Subject: [PATCH 08/29] =?UTF-8?q?[=20chore=20]=20suffix=20'=E3=81=AA?= =?UTF-8?q?=E3=81=8A'=20with=20'=E3=80=81'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- text-ja/chapter10.md | 4 +- text-ja/chapter4.md | 773 +++++++++++++++++++++++++++++++++++++++++++ translation/ja.po | 84 ++--- 3 files changed, 798 insertions(+), 63 deletions(-) create mode 100644 text-ja/chapter4.md diff --git a/text-ja/chapter10.md b/text-ja/chapter10.md index 551d350a..81e34ca7 100644 --- a/text-ja/chapter10.md +++ b/text-ja/chapter10.md @@ -1024,7 +1024,7 @@ Map String Int 1. (簡単)より広い種類のマップに関して動作するよう、前のJavaScriptの関数の新しい梱包を書いてください。 シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either JsonDecodeError (Set v)`です。 - なお`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。 + なお、`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。 コンパイラが導いてくれます。 1. (Medium) Rewrite the earlier `quadraticRoots` function as `quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON @@ -1118,7 +1118,7 @@ validateAndSave = do log "Saved" ``` -なおこの段階でコンパイルしようとすると以下のエラーに遭遇します。 +なお、この段階でコンパイルしようとすると以下のエラーに遭遇します。 ```text No type class instance was found for diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md new file mode 100644 index 00000000..bfac734a --- /dev/null +++ b/text-ja/chapter4.md @@ -0,0 +1,773 @@ +# 再帰、マップ、畳み込み + +## この章の目標 + +この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて見ていきましょう。 +再帰は関数型プログラミングの基本的な手法であり、本書全体にわたって使われます。 + +また、PureScriptの標準ライブラリから標準的な関数を幾つか取り扱います。 +`map`や`fold`といった関数だけでなく、`filter`や`concatMap`といった特別な場合において便利なものについても見ていきます。 + +この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用います。 +この章で学ぶ技術を応用し、ファイルシステムのモデルにより表現されるファイルのプロパティを計算する関数を書きます。 + +## プロジェクトの準備 + +この章のソースコードは`src/Data/Path.purs`と`test/Examples.purs`に含まれています。 +`Data.Path`モジュールは仮想ファイルシステムのモデルを含みます。 +このモジュールの内容を変更する必要はありません。 +演習への解答は`Test.MySolutions`モジュールに実装してください。 +それぞれの演習を完了させつつ都度`Test.Main`モジュールにある対応するテストを有効にし、`spago +test`を走らせることで解答を確認してください。 + +このプロジェクトには以下の依存関係があります。 + +- `maybe`: `Maybe`型構築子が定義されています。 +- `arrays`: 配列を扱うための関数が定義されています。 +- `strings`: JavaScriptの文字列を扱うための関数が定義されています。 +- `foldable-traversable`: 配列やその他のデータ構造を畳み込む関数が定義されています。 +- `console`: コンソールへの出力を扱うための関数が定義されています。 + +## 導入 + +再帰は一般のプログラミングでも重要な手法ですが、特に純粋関数型プログラミングでは当たり前のように用いられます。この章で見ていくように、再帰はプログラムの変更可能な状態を減らすために役立つからです。 + +再帰は*分割統治*戦略と密接な関係があります。 +分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分ごとの答えから最終的な答えを組み立てるということです。 + +それでは、PureScriptにおける再帰の簡単な例を幾つか見てみましょう。 + +次に示すのは*階乗関数*のありふれた例です。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:factorial}} +``` + +このように、問題を部分問題へ分割することによって階乗関数の計算方法が見てとれます。 +より小さい数の階乗を計算していくということです。 +ゼロに到達すると、答えは直ちに求まります。 + +次は、*フィボナッチ関数*を計算するという、これまたよくある例です。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:fib}} +``` + +やはり、部分問題の解決策を考えることで全体を解決していることがわかります。 +このとき、`fib (n - 1)`と`fib (n - 2)`という式に対応した、2つの部分問題があります。 +これらの2つの部分問題が解決されていれば、この部分的な答えを加算することで、全体の答えを組み立てることができます。 + +> なお、上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。 +> パターン照合の技法は後の章でお話しします。 + +## 配列上での再帰 + +再帰関数の定義は`Int`型だけに限定されるものではありません。 +本書の後半で*パターン照合*を扱うときに、いろいろなデータ型の上での再帰関数について見ていきますが、ここでは数と配列に限っておきます。 + +入力がゼロでないかどうかについて分岐するのと同じように、配列の場合も、配列が空でないかどうかについて分岐していきます。再帰を使用して配列の長さを計算する次の関数を考えてみます。 + +```haskell +import Prelude + +import Data.Array (null, tail) +import Data.Maybe (fromMaybe) + +{{#include ../exercises/chapter4/test/Examples.purs:length}} +``` + +この関数では配列が空かどうかで分岐するために`if ... then ... else`式を使っています。 +この`null`関数は空の配列で`true`を返します。 +空の配列の長さはゼロであり、空でない配列の長さは尾鰭の長さより1大きいというわけです。 + +`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返します。 +配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。 +`fromMaybe`関数は既定値と`Maybe`値を取ります。 +後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返します。 + +JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえませんが、次の演習を完遂するための手掛かりとしては充分でしょう。 + +## 演習 + + 1. (簡単)入力が偶数であるとき、かつそのときに限り`true`に返す再帰関数`isEven`を書いてみましょう。 + 2. (普通)配列内の偶数の整数を数える再帰関数`countEven`を書いてみましょう。 + *手掛かり*:`head`関数(これも`Data.Array`モジュールから手に入ります)を使うと、空でない配列の最初の要素を見つけられます。 + +## マップ + +`map`関数は配列に対する再帰関数の一例です。 +配列の各要素に順番に関数を適用し、配列の要素を変換するのに使われます。 +そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存されます。 + +本書の後半で*型クラス*の内容を押さえるとき、`map`関数が形状を保存する関数のより一般的な様式の一例であることを見ていきます。 +この関数は*関手*と呼ばれる型構築子のクラスを変換するものです。 + +それでは、PSCiで`map`関数を試してみましょう。 + +```text +$ spago repl + +> import Prelude +> map (\n -> n + 1) [1, 2, 3, 4, 5] +[2, 3, 4, 5, 6] +``` + +`map`がどのように使われているかに注目してください。 +最初の引数には配列上で「写す」関数、第2引数には配列そのものを渡します。 + +## 中置演算子 + +バッククォートで関数名を囲むと、写す関数と配列の間に、`map`関数を書くことができます。 + +```text +> (\n -> n + 1) `map` [1, 2, 3, 4, 5] +[2, 3, 4, 5, 6] +``` + +この構文は _中置関数適用_ と呼ばれ、どんな関数でもこのように中置できます。普通は2引数の関数に対して使うのが最適でしょう。 + +配列を扱う際は`map`関数と等価な`<$>`という演算子が存在します。 + +```text +> (\n -> n + 1) <$> [1, 2, 3, 4, 5] +[2, 3, 4, 5, 6] +``` + +それでは`map`の型を見てみましょう。 + +```text +> :type map +forall a b f. Functor f => (a -> b) -> f a -> f b +``` + +実は`map`の型は、この章で必要とされているものよりも一般的な型になっています。今回の目的では、`map`は次のようなもっと具体的な型であるかのように考えるとよいでしょう。 + +```text +forall a b. (a -> b) -> Array a -> Array b +``` + +この型では、`map`関数に適用するときには`a`と`b`という2つの型を自由に選ぶことができる、ということも示されています。 +`a`は元の配列の要素の型で、`b`は目的の配列の要素の型です。 +もっと言えば、`map`が配列の要素の型を保存する必要があるわけではありません。 +例えば`map`を使用すると数値を文字列に変換できます。 + +```text +> show <$> [1, 2, 3, 4, 5] + +["1","2","3","4","5"] +``` + +中置演算子`<$>`は特別な構文のように見えるかもしれませんが、実はPureScriptの普通の関数の別称です。 +中置構文を使用した単なる*適用*にすぎません。 +実際、括弧でその名前を囲むと、この関数を通常の関数のように使用できます。 +これは、`map`代わりに、括弧で囲まれた`(<$>)`という名前が使えるということです。 + +```text +> (<$>) show [1, 2, 3, 4, 5] +["1","2","3","4","5"] +``` + +中置関数は既存の関数名の別称として定義されます。 +例えば`Data.Array`モジュールでは次のように`range`関数の同義語として中置演算子`(..)`を定義しています。 + +```haskell +infix 8 range as .. +``` + +この演算子は次のように使うことができます。 + +```text +> import Data.Array + +> 1 .. 5 +[1, 2, 3, 4, 5] + +> show <$> (1 .. 5) +["1","2","3","4","5"] +``` + +*補足*:独自の中置演算子は、自然な構文を備える領域特化言語を定義する上で優れた手段になりえます。ただし、乱用すると初心者が読めないコードになることがありますから、新たな演算子の定義には慎重になるのが賢明です。 + +上記の例では、`1 .. 5`という式は括弧で囲まれていましたが、実際にはこれは必要ありません。 +なぜなら、`Data.Array`モジュールは、`<$>`に割り当てられた優先順位より高い優先順位を`..`演算子に割り当てているからです。 +上の例では、`..`の優先順位は、予約語`infix`のあとに書かれた数の`8` と定義されていました。 +ここでは`<$>`の優先順位よりも高い優先順位を`..`に割り当てており、このため括弧を付け加える必要がないということです。 + +```text +> show <$> 1 .. 5 +["1","2","3","4","5"] +``` + +中置演算子に(左または右の)*結合性*を与えたい場合は、代わりに予約語`infixl`と`infixr`を使います。`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。 + +## 配列の絞り込み + +`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供しています。 +この関数は、述語関数に適合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。 + +例えば1から10までの数で、偶数であるような数の配列を計算したいとします。 +これは次のようにできます。 + +```text +> import Data.Array + +> filter (\n -> n `mod` 2 == 0) (1 .. 10) +[2,4,6,8,10] +``` + +## 演習 + + 1. (簡単)`map`関数や`<$>`関数を使用して、 配列に格納された数のそれぞれの平方を計算する関数`squared`を書いてみましょう。 + *手掛かり*:`map`や`<$>`といった関数を使ってください。 + 1. (簡単)`filter`関数を使用して、数の配列から負の数を取り除く関数`keepNonNegative`を書いてみましょう。 + *手掛かり*:`filter`関数を使ってください。 + 1. (普通) + - `filter`の中置同義語`<$?>`を定義してください。 + *補足*:中置同義語はREPLでは定義できないかもしれませんが、ファイルでは定義できます。 + - 関数`keepNonNegativeRewrite`を書いてください。この関数は`filter`を独自の新しい中置演算子`<$?>`で置き換えたところ以外、`keepNonNegative`と同じです。 + - PSCiで独自の演算子の優先度合いと結合性を試してください。 + *補足*:この問題のための単体試験はありません。 + +## 配列の平坦化 + +配列に関する標準的な関数として`Data.Array`で定義されているものには、`concat`関数もあります。`concat`は配列の配列を1つの配列へと平坦化します。 + +```text +> import Data.Array + +> :type concat +forall a. Array (Array a) -> Array a + +> concat [[1, 2, 3], [4, 5], [6]] +[1, 2, 3, 4, 5, 6] +``` + +関連する関数として、`concat`と`map`を組み合わせた`concatMap`と呼ばれる関数もあります。 +`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それに対して`concatMap`は値から値の配列への関数を取ります。 + +実際に動かして見てみましょう。 + +```text +> import Data.Array + +> :type concatMap +forall a b. (a -> Array b) -> Array a -> Array b + +> concatMap (\n -> [n, n * n]) (1 .. 5) +[1,1,2,4,3,9,4,16,5,25] +``` + +ここでは、数をその数とその数の平方の2つの要素からなる配列に写す関数`\n -> [n, n * n]`を引数に`concatMap`を呼び出しています。 +結果は10個の整数の配列です。 +配列は1から5の数とそのそれぞれの数の平方からなります。 + +`concatMap`がどのように結果を連結しているのかに注目してください。渡された関数を元の配列のそれぞれの要素について一度ずつ呼び出し、その関数はそれぞれ配列を生成します。最後にそれらの配列を単一の配列に押し潰したものが結果となります。 + +`map`と`filter`、`concatMap`は、「配列内包表記」(array comprehensions) +と呼ばれる、配列に関するあらゆる関数の基盤を形成します。 + +## 配列内包表記 + +数`n`の2つの因数を見つけたいとしましょう。 +こうするための簡単な方法としては、総当りで調べる方法があります。 +つまり、`1`から`n`の数の全ての組み合わせを生成し、それを乗算してみるわけです。 +もしその積が`n`なら、`n`の因数の組み合わせを見つけたということになります。 + +配列内包表記を使用するとこれを計算できます。 +PSCiを対話式の開発環境として使用し、1つずつこの手順を進めていきましょう。 + +最初の工程では`n`以下の数の組み合わせの配列を生成しますが、これには`concatMap`を使えばよいです。 + +`1 .. n`のそれぞれの数を配列`1 .. n`へとマッピングすることから始めましょう。 + +```text +> pairs n = concatMap (\i -> 1 .. n) (1 .. n) +``` + +この関数をテストしてみましょう。 + +```text +> pairs 3 +[1,2,3,1,2,3,1,2,3] +``` + +これは求めているものとは全然違います。 +単にそれぞれの組み合わせの2つ目の要素を返すのではなく、対全体を保持できるように、内側の`1 .. n`の複製について関数を対応付ける必要があります。 + +```text +> :paste +… pairs' n = +… concatMap (\i -> +… map (\j -> [i, j]) (1 .. n) +… ) (1 .. n) +… ^D + +> pairs' 3 +[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]] +``` + +いい感じになってきました。 +しかし、`[1, 2]`と`[2, 1]`の両方があるように、重複した組み合わせが生成されています。 +`j`を`i`から`n`の範囲に限定することで、2つ目の場合を取り除くことができます。 + +```text +> :paste +… pairs'' n = +… concatMap (\i -> +… map (\j -> [i, j]) (i .. n) +… ) (1 .. n) +… ^D +> pairs'' 3 +[[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]] +``` + +すばらしいです。 +因数の候補の全ての組み合わせを手に入れたので、`filter`を使えば、その積が`n`であるような組み合わせを選び出すことができます。 + +```text +> import Data.Foldable + +> factors n = filter (\pair -> product pair == n) (pairs'' n) + +> factors 10 +[[1,10],[2,5]] +``` + +このコードでは、`foldable-traversable`ライブラリの`Data.Foldable`モジュールにある`product`関数を使っています。 + +うまくいきました。 +因数の組み合わせの正しい集合を重複なく見つけることができました。 + +## do記法 + +しかし、このコードの可読性は大幅に向上できます。`map`や`concatMap`は基本的な関数であり、 _do記法_ (do notation) +と呼ばれる特別な構文の基礎になっています(もっと厳密にいえば、それらの一般化である`map`と`bind`が基礎をなしています)。 + +> *補足*:`map`と`concatMap`があることで*配列内包表記*を書けるように、もっと一般的な演算子である`map`と`bind`があることで*モナド内包表記*と呼ばれているものが書けます。 +> 本書の後半では*モナド*の例をたっぷり見ていくことになりますが、この章では配列のみを考えます。 + +do記法を使うと、先ほどの`factors`関数を次のように書き直すことができます。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:factors}} +``` + +キーワード`do`はdo記法を使うコードのブロックを導入します。 +このブロックは幾つかの種類の式で構成されています。 + +- 配列の要素を名前に束縛する式。 + これは後ろ向きの矢印`<-`で示されており、左側には名前が、右側には配列の型を持つ式があります。 +- 名前に配列の要素を束縛しない式。 + `do`の*結果*はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されています。 +- `let`キーワードを使用し、式に名前を与える式。 + +この新しい記法を使うと、アルゴリズムの構造がわかりやすくなることがあります。 +頭の中で`<-`を「選ぶ」という単語に置き換えるとすると、「1からnの間の要素`i`を選び、それからiからnの間の要素`j`を選び、`[i, j]`を返す」というように読むことができるでしょう。 + +最後の行では、`pure`関数を使っています。この関数はPSCiで評価できますが、型を明示する必要があります。 + +```text +> pure [1, 2] :: Array (Array Int) +[[1, 2]] +``` + +配列の場合、`pure`は単に1要素の配列を作成します。 +`factors`関数を変更して、`pure`の代わりにこの形式も使うようにできます。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:factorsV2}} +``` + +そして、結果は同じになります。 + +## ガード + +`factors`関数を更に改良する方法としては、このフィルタを配列内包表記の内側に移動するというものがあります。 +これは`control`ライブラリにある`Control.Alternative`モジュールの`guard`関数を使用することで可能になります。 + +```haskell +import Control.Alternative (guard) + +{{#include ../exercises/chapter4/test/Examples.purs:factorsV3}} +``` + +`pure`と同じように、どのように動作するかを理解するために、PSCiで`guard`関数を適用して調べてみましょう。 +`guard`関数の型は、ここで必要とされるものよりもっと一般的な型になっています。 + +```text +> import Control.Alternative + +> :type guard +forall m. Alternative m => Boolean -> m Unit +``` + +今回の場合は、PSCiは次の型を報告するものと考えてください。 + +```haskell +Boolean -> Array Unit +``` + +目的からすると、次の計算の結果から配列における`guard`関数について今知りたいことは全てわかります。 + +```text +> import Data.Array + +> length $ guard true +1 + +> length $ guard false +0 +``` + +つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返すのです。 +もし式が`false`と評価された場合は、その結果は空です。 + +ガードが失敗した場合、配列内包表記の現在の分岐は、結果なしで早めに終了されることを意味します。 +これは、`guard`の呼び出しが、途中の配列に対して`filter`を使用するのと同じだということです。 +実践の場面にもよりますが、`filter`の代わりに`guard`を使いたいことは多いでしょう。 +これらが同じ結果になることを確認するために、`factors`の2つの定義を試してみてください。 + +## 演習 + + 1. (簡単)関数`isPrime`を書いてください。 + この関数は整数の引数が素数であるかを調べます。 + *手掛かり*:`factors`関数を使ってください。 + 1. (普通)do記法を使い、2つの配列の*直積集合*を見つけるための関数`cartesianProduct`を書いてみましょう。 + 直積集合とは、要素`a`、`b`の全ての組み合わせの集合のことです。 + ここで`a`は最初の配列の要素、`b`は2つ目の配列の要素です。 + 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より大きい整数について、問題を2つの部分問題に分解してください。 + 最初の因数を探し、それから残りの因数を探すのです。 + +## 畳み込み + +配列における左右の畳み込みは、再帰を用いて実装できる別の興味深い一揃いの関数を提供します。 + +PSCiを使って、`Data.Foldable`モジュールをインポートし、`foldl`と`foldr`関数の型を調べることから始めましょう。 + +```text +> import Data.Foldable + +> :type foldl +forall a b f. Foldable f => (b -> a -> b) -> b -> f a -> b + +> :type foldr +forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b +``` + +これらの型は、現在興味があるものよりも一般化されています。 +この章では、PSCiは以下の(より具体的な)答えをくれていると考えておきましょう。 + +```text +> :type foldl +forall a b. (b -> a -> b) -> b -> Array a -> b + +> :type foldr +forall a b. (a -> b -> b) -> b -> Array a -> b +``` + +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. + +`foldl`関数と`foldr`関数の違いは走査の方向です。 +`foldr`が「右から」配列を畳み込むのに対して、`foldl`は「左から」配列を畳み込みます。 + +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: + +```text +> foldl (+) 0 (1 .. 5) +15 +``` + +この場合では、引数が逆になっていても`(+)`関数は同じ結果を返すので、`foldl`と`foldr`のどちらでも問題ありません。 + +```text +> foldr (+) 0 (1 .. 5) +15 +``` + +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: + +```text +> foldl (\acc n -> acc <> show n) "" [1,2,3,4,5] +"12345" + +> foldr (\n acc -> acc <> show n) "" [1,2,3,4,5] +"54321" +``` + +これは、2つの関数の違いを示しています。左畳み込み式は、以下の関数適用と同等です。 + +```text +((((("" <> show 1) <> show 2) <> show 3) <> show 4) <> show 5) +``` + +Whereas the right fold is equivalent to this: + +```text +((((("" <> show 5) <> show 4) <> show 3) <> show 2) <> show 1) +``` + +## 末尾再帰 + +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. + +It is easy to verify this problem with the following code in PSCi: + +```text +> :paste +… f n = +… if n == 0 +… then 0 +… else 1 + f (n - 1) +… ^D + +> f 10 +10 + +> f 100000 +RangeError: Maximum call stack size exceeded +``` + +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. + +PureScript provides a partial solution to this problem through _tail +recursion optimization_. + +> _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. + +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. + +実際には、PureScriptコンパイラは再帰呼び出しをジャンプに置き換えるのではなく、再帰的な関数全体を _whileループ_ に置き換えます。 + +以下は全ての再帰呼び出しが末尾位置にある再帰関数の例です。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}} +``` + +Notice that the recursive call to `factorialTailRec` is the last thing in +this function – it is in tail position. + +## 累算器 + +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. + +For example, consider again the `length` function presented at the beginning +of the chapter: + +```haskell +length :: forall a. Array a -> Int +length arr = + if null arr + then 0 + else 1 + (length $ fromMaybe [] $ tail arr) +``` + +この実装は末尾再帰ではないので、大きな入力配列に対して実行されると、生成されたJavaScriptはスタックオーバーフローを発生させるでしょう。 +しかし代わりに、結果を蓄積するための2つ目の引数を関数に導入することで、これを末尾再帰に変えることができます。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}} +``` + +In this case, we delegate to the helper function `length'`, which is tail +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. + +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 at 0 and grows by +adding 1 for every element in the input array. + +Note also that while we might think of the accumulator as a "state", there +is no direct mutation. + +## 明示的な再帰より畳み込みを選ぼう + +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. + +例えば`foldr`を使って配列を反転できます。 + +```text +> import Data.Foldable + +> :paste +… reverse :: forall a. Array a -> Array a +… reverse = foldr (\x xs -> xs <> [x]) [] +… ^D + +> reverse [1, 2, 3] +[3,2,1] +``` + +`foldl`を使って`reverse`を書くことは、読者への課題として残しておきます。 + +## 演習 + + 1. (簡単)`foldl`を使って真偽値配列の値が全て真か検査する関数`allTrue`を書いてください。 + 2. (普通。テストなし)関数`foldl (==) false xs`が真を返すような配列`xs`とはどのようなものか説明してください。 + 言い換えると、「関数は`xs`が……を含むときに`true`を返す」という文を完成させることになります。 + 3. (普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`を書いてください。 + *手掛かり*:累算器引数を使ってください。 + 4. (普通)`foldl`を使って`reverse`を書いてみましょう。 + +## 仮想ファイルシステム + +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. + +The `Data.Path` module defines an API for a virtual filesystem as follows: + +- ファイルシステム内のパスを表す型`Path`があります。 +- ルートディレクトリを表すパス`root`があります。 +- `ls`関数はディレクトリ内のファイルを列挙します。 +- `filename`関数は`Path`のファイル名を返します。 +- The `size` function returns the file size for a `Path` representing a + file. +- `isDirectory`関数はファイルかディレクトリかを調べます。 + +型について言うと、次のような型定義があります。 + +```haskell +root :: Path + +ls :: Path -> Array Path + +filename :: Path -> String + +size :: Path -> Maybe Int + +isDirectory :: Path -> Boolean +``` + +PSCiでこのAPIを試してみましょう。 + +```text +$ spago repl + +> import Data.Path + +> root +/ + +> isDirectory root +true + +> ls root +[/bin/,/etc/,/home/] +``` + +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. + +## 全てのファイルの一覧 + +Let's write a function that performs a deep enumeration of all files inside +a directory. This function will have the following type: + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:allFiles_signature}} +``` + +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 +simultaneously. + +最後に、cons演算子`:`を使って現在のファイルも含めます。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:allFiles_implementation}} +``` + +> _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. + +それではPSCiでこの関数を試してみましょう。 + +```text +> import Test.Examples +> import Data.Path + +> allFiles root + +[/,/bin/,/bin/cp,/bin/ls,/bin/mv,/etc/,/etc/hosts, ...] +``` + +すばらしいです。 +do記法で配列内包表記を使ってもこの関数を書くことができるので見ていきましょう。 + +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 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. + +新しいバージョンは次のようになります。 + +```haskell +{{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}} +``` + +Try out the new version in PSCi – you should get the same result. I'll let +you decide which version you find clearer. + +## 演習 + + 1. (簡単)ディレクトリの全てのサブディレクトリの中にある(ディレクトリを除く)全てのファイルを返すような関数`onlyFiles`を書いてみてください。 + 2. (普通)ファイルを名前で検索する関数`whereIs`を書いてください。 + この関数は型`Maybe Path`の値を返すものとします。 + この値が存在するなら、そのファイルがそのディレクトリに含まれているということを表します。 + この関数は次のように振る舞う必要があります。 + + ```text + > whereIs root "ls" + Just (/bin/) + + > whereIs root "cat" + Nothing + ``` + + _Hint_: Try to write this function as an array comprehension using do notation. + 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. + +## まとめ + +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. diff --git a/translation/ja.po b/translation/ja.po index ccae0dfa..6809ce78 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-16 08:51+0900\n" +"PO-Revision-Date: 2023-07-16 08:57+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -3746,11 +3746,9 @@ msgid "" "you'll need to add some type class constraints for `k` and `v`. The compiler " "will guide you." msgstr "" -"(簡単)より広い種類のマップに関して動作するよう、前のJavaScriptの関数の新し" -"い梱包を書いてください。\n" -"シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either " -"JsonDecodeError (Set v)`です。\n" -"なお`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。\n" +"(簡単)より広い種類のマップに関して動作するよう、前のJavaScriptの関数の新しい梱包を書いてください。\n" +"シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either JsonDecodeError (Set v)`です。\n" +"なお、`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。\n" "コンパイラが導いてくれます。" #. type: Bullet: '1. ' @@ -4037,7 +4035,7 @@ msgstr "" 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:983 @@ -4105,13 +4103,6 @@ msgstr "item <- getItem \"person\"\n" #. type: Plain text #: text/chapter10.md:1005 #, fuzzy -#| 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." msgid "" "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 " @@ -4120,10 +4111,8 @@ msgid "" "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`ブロックの中に纏めるのは理に適っています。" @@ -5894,12 +5883,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:107 #, fuzzy -#| 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." msgid "" "Note that these API signatures are presented in a simplified form using the " "`State` type constructor for now. The actual API involves `MonadState`, " @@ -5907,12 +5890,9 @@ msgid "" "don't worry if you see different signatures in your IDE tooltips or on " "Pursuit." msgstr "" -"なおここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式" -"で表されています。\n" -"実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきま" -"す。\n" -"ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないで" -"ください。" +"なお、ここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式で表されています。\n" +"実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきます。\n" +"ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないでください。" #. type: Plain text #: text/chapter11.md:109 @@ -11166,10 +11146,8 @@ 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 @@ -18172,7 +18150,7 @@ msgstr "" #, 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`を使う代わりにパターン照合を使うものでしょう。\n" +"> なお、上の`factorial`と`fib`の例は意図通りに動きますが、よりPureScriptらしい実装では`if`や`then`や`else`を使う代わりにパターン照合を使うものでしょう。\n" "> パターン照合の技法は後の章でお話しします。\n" #. type: Title ## @@ -21037,19 +21015,13 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}}\n" #. type: Plain text #: text/chapter5.md:227 #, fuzzy -#| 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." 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 returns it unchanged, even if it's unsorted." msgstr "" -"このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みま" -"す。なおもし入力の配列が _厳密に_ 2つの要素を含んでいなければ、たとえ整列され" -"ていなかったとしても、この関数は単に元のまま変えずに返しています。" +"このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。\n" +"なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返しています。" #. type: Bullet: '1. ' #: text/chapter5.md:233 @@ -21591,18 +21563,13 @@ msgstr "" #. type: Plain text #: text/chapter5.md:361 #, fuzzy -#| 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 defining ADTs with `data` or type aliases with `type`." 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 " "defining ADTs with `data` or type aliases with `type`." msgstr "" -"なおデータ定義のどこにも構文`forall a`を使っていません。\n" -"`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義する" -"ときは使われません。" +"なお、データ定義のどこにも構文`forall a`を使っていません。\n" +"`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義するときは使われません。" #. type: Plain text #: text/chapter5.md:363 @@ -24591,7 +24558,7 @@ msgstr "" 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:656 @@ -25482,11 +25449,8 @@ 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 @@ -28372,8 +28336,7 @@ msgstr "foldM _ a Nil = pure a\n" #. type: Plain text #: text/chapter8.md:237 msgid "Note that we have to use `pure` to lift `a` into the monad `m`." -msgstr "" -"なお`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。" +msgstr "なお、`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。" #. type: Plain text #: text/chapter8.md:239 @@ -29758,10 +29721,9 @@ msgstr "" #. type: Plain text #: text/chapter8.md:637 #, fuzzy, 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." 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" +"なお、この結果として得られたJavaScriptは最適化の余地があります。\n" "詳細は[この課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。\n" "上記の抜粋はその課題が解決されたら更新されるでしょう。" @@ -30887,7 +30849,7 @@ msgstr "" #. type: Plain text #: text/chapter8.md:963 msgid "Note that `handleValue` can be substituted as:" -msgstr "なお`handleValue`は以下のようにも置き換えられます。" +msgstr "なお、`handleValue`は以下のようにも置き換えられます。" #. type: Fenced code block (hs) #: text/chapter8.md:964 From 3d2088000eda15a33dda26549028178ba3e70883 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Mon, 17 Jul 2023 11:12:24 +0900 Subject: [PATCH 09/29] [ update ] chapter 4 translation --- text-ja/chapter4.md | 157 ++++++++++++++--------------- translation/ja.po | 240 ++++++++++++-------------------------------- 2 files changed, 139 insertions(+), 258 deletions(-) diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md index bfac734a..44bd6eec 100644 --- a/text-ja/chapter4.md +++ b/text-ja/chapter4.md @@ -472,14 +472,21 @@ forall a b. (b -> a -> b) -> b -> Array a -> b forall a b. (a -> b -> b) -> b -> Array a -> b ``` -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. +どちらの場合でも、型`a`は配列の要素の型に対応しています。 +型`b`は「累算器」の型として考えることができます。 +累算器とは配列を走査しつつ結果を累算するものです。 `foldl`関数と`foldr`関数の違いは走査の方向です。 `foldr`が「右から」配列を畳み込むのに対して、`foldl`は「左から」配列を畳み込みます。 -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: +実際にこれらの関数の動きを見てみましょう。 +`foldl`を使用して数の配列の和を求めてみます。 +型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。 +ここでは3つの引数を与える必要があります。 +1つ目は次の要素を累算器に加算する`Int -> Int -> Int`という型の関数です。 +2つ目は累算器の`Int`型の初期値です。 +3つ目は和を求めたい`Int`の配列です。 +最初の引数としては、加算演算子を使用できますし、累算器の初期値はゼロになります。 ```text > foldl (+) 0 (1 .. 5) @@ -493,9 +500,8 @@ Let's see these functions in action. Let's use `foldl` to sum an array of intege 15 ``` -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: +違いを説明するために、畳み込み関数の選択が大事になってくる例も書きましょう。 +加算関数の代わりに、文字列連結を使用して文字列を構築しましょう。 ```text > foldl (\acc n -> acc <> show n) "" [1,2,3,4,5] @@ -511,7 +517,7 @@ string concatenation to build a string: ((((("" <> show 1) <> show 2) <> show 3) <> show 4) <> show 5) ``` -Whereas the right fold is equivalent to this: +それに対し、右畳み込みは以下と等価です。 ```text ((((("" <> show 5) <> show 4) <> show 3) <> show 2) <> show 1) @@ -519,11 +525,10 @@ Whereas the right fold is equivalent to this: ## 末尾再帰 -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. +再帰はアルゴリズムを指定する強力な手法ですが、問題も抱えています。 +JavaScriptで再帰関数を評価するとき、入力が大き過ぎるとスタックオーバーフローでエラーを起こす可能性があるのです。 -It is easy to verify this problem with the following code in PSCi: +PSCiで次のコードを入力すると、この問題を簡単に検証できます。 ```text > :paste @@ -540,21 +545,20 @@ It is easy to verify this problem with the following code in PSCi: RangeError: Maximum call stack size exceeded ``` -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. +これは問題です。 +関数型プログラミングの標準的な手法として再帰を採用しようとするなら、境界がない再帰がありうるときでも扱える方法が必要です。 -PureScript provides a partial solution to this problem through _tail -recursion optimization_. +PureScriptは*末尾再帰最適化*の形でこの問題に対する部分的な解決策を提供しています。 -> _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. +> *補足*:この問題へのより完全な解決策としては、いわゆる*トランポリン*を使用するライブラリで実装できますが、それはこの章で扱う範囲を超えています。 +> 興味のある読者は[`free`](https://pursuit.purescript.org/packages/purescript-free)や[`tailrec`](https://pursuit.purescript.org/packages/purescript-tailrec)パッケージのドキュメントをあたると良いでしょう。 -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. +末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 +*末尾位置*にある関数の再帰的な呼び出しは*ジャンプ*に置き換えられます。 +このジャンプではスタックフレームが確保されません。 +関数が戻るより前の最後の呼び出しであるとき、呼び出しが*末尾位置*にあるといいます。 +なぜ先の例でスタックオーバーフローが見られたのかはこれが理由です。 +`f`の再帰呼び出しが末尾位置*でなかったからです。 実際には、PureScriptコンパイラは再帰呼び出しをジャンプに置き換えるのではなく、再帰的な関数全体を _whileループ_ に置き換えます。 @@ -564,18 +568,16 @@ position. {{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}} ``` -Notice that the recursive call to `factorialTailRec` is the last thing in -this function – it is in tail position. +`factorialTailRec`への再帰呼び出しがこの関数の最後にある点に注目してください。 +つまり末尾位置にあるのです。 ## 累算器 -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. +末尾再帰ではない関数を末尾再帰関数に変える一般的な方法は、*累算器引数*を使用することです。 +累算器引数は関数に追加される余剰の引数で、返り値を*累算*するものです。 +これは結果を累算するために返り値を使うのとは対照的です。 -For example, consider again the `length` function presented at the beginning -of the chapter: +例えば章の初めに示した`length`関数を再考しましょう。 ```haskell length :: forall a. Array a -> Int @@ -592,29 +594,23 @@ length arr = {{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}} ``` -In this case, we delegate to the helper function `length'`, which is tail -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. +ここでは補助関数`length'`に委譲しています。 +この関数は末尾再帰です。 +その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。 +つまり、生成されるコードは*whileループ*となり、大きな入力でもスタックが溢れません。 -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 at 0 and grows by -adding 1 for every element in the input array. +`lengthTailRec`の実装を理解する上では、補助関数`length'`が基本的に累算器引数を使って追加の状態を保持していることに注目してください。 +追加の状態とは、部分的な結果です。 +0から始まり、入力の配列中の全ての各要素について1ずつ足されて大きくなっていきます。 -Note also that while we might think of the accumulator as a "state", there -is no direct mutation. +なお、累算器を「状態」と考えることもできますが、直接には変更されていません。 ## 明示的な再帰より畳み込みを選ぼう -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. +末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けられるので、全ての関数をこの形で書こうとする誘惑にかられます。 +しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書くことができることを忘れがちです。 +`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、コードの単純さという利点があります。 +これらの部品はよく知られており、だからこそ明示的な再帰よりもアルゴリズムの*意図*がより良く伝わるのです。 例えば`foldr`を使って配列を反転できます。 @@ -643,18 +639,16 @@ much better than explicit recursion. ## 仮想ファイルシステム -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. +この節ではこれまで学んだことを応用してファイルシステムのモデルを扱う関数を書きます。 +事前に定義されたAPIを扱う上でマップ、畳み込み、及びフィルタを使用します。 -The `Data.Path` module defines an API for a virtual filesystem as follows: +`Data.Path`モジュールでは、次のように仮想ファイルシステムのAPIが定義されています。 - ファイルシステム内のパスを表す型`Path`があります。 - ルートディレクトリを表すパス`root`があります。 - `ls`関数はディレクトリ内のファイルを列挙します。 - `filename`関数は`Path`のファイル名を返します。 -- The `size` function returns the file size for a `Path` representing a - file. +- `size`関数はファイルを表す`Path`のファイルの大きさを返します。 - `isDirectory`関数はファイルかディレクトリかを調べます。 型について言うと、次のような型定義があります。 @@ -688,24 +682,23 @@ true [/bin/,/etc/,/home/] ``` -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. +`Test.Examples`モジュールでは`Data.Path` APIを使用する関数を定義しています。 +`Data.Path`モジュールを変更したり定義を理解したりする必要はありません。 +全て`Test.Examples`モジュールだけで作業します。 ## 全てのファイルの一覧 -Let's write a function that performs a deep enumeration of all files inside -a directory. This function will have the following type: +それでは、ディレクトリの中身を含めた全てのファイルを深く列挙する関数を書いてみましょう。 +この関数は以下のような型を持つでしょう。 ```haskell {{#include ../exercises/chapter4/test/Examples.purs:allFiles_signature}} ``` -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 -simultaneously. +再帰を使ってこの関数を定義できます。 +`ls`を使うとディレクトリ直下の子が列挙されます。 +それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返ります。 +`concatMap`を使うと、`allFiles`を適用して平坦化するまでを一度にできます。 最後に、cons演算子`:`を使って現在のファイルも含めます。 @@ -713,7 +706,8 @@ simultaneously. {{#include ../exercises/chapter4/test/Examples.purs:allFiles_implementation}} ``` -> _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. +> *補足*:実はcons演算子`:`は、不変な配列に対して効率性が悪いので、一般的には推奨されません。 +> 連結リストやシーケンスなどの他のデータ構造を使用すると、効率性を向上させられます。 それではPSCiでこの関数を試してみましょう。 @@ -729,11 +723,11 @@ simultaneously. すばらしいです。 do記法で配列内包表記を使ってもこの関数を書くことができるので見ていきましょう。 -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 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. +逆向きの矢印は配列から要素を選択するのに相当することを思い出してください。 +最初の工程は引数の直接の子から要素を選択することです。 +それからそのファイルに対して再帰関数を呼び出します。 +do記法を使用しているので`concatMap`が暗黙に呼び出されています。 +この関数は再帰的な結果を全て連結します。 新しいバージョンは次のようになります。 @@ -741,8 +735,9 @@ concatenates all of the recursive results. {{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}} ``` -Try out the new version in PSCi – you should get the same result. I'll let -you decide which version you find clearer. +PSCiで新しいコードを試してみてください。 +同じ結果が返ってくるはずです。 +どちらのほうがわかりやすいかの選定はお任せします。 ## 演習 @@ -760,14 +755,12 @@ you decide which version you find clearer. Nothing ``` - _Hint_: Try to write this function as an array comprehension using do notation. - 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. + *手掛かり*:この関数をdo記法を使った配列内包表記で書いてみましょう。 + 3. (難しい)`Path`中の最大のファイルと最小のファイルを1つずつ含む配列を返す関数`largestSmallest`を書いてください。 + *補足*:空配列や1要素の配列を返すことで、`Path`にそれぞれゼロか1個のファイルがある場合についても考慮してください。 ## まとめ -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. +この章ではアルゴリズムを簡潔に表現するためにPureScriptでの再帰の基本を押さえました。 +また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関数、及びこれらの概念を組み合わせた配列内包表記を導入しました。 +最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。 diff --git a/translation/ja.po b/translation/ja.po index 6809ce78..5f41862c 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-16 08:57+0900\n" +"PO-Revision-Date: 2023-07-17 11:12+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -19262,13 +19262,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:397 -#, fuzzy msgid "" "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" +"どちらの場合でも、型`a`は配列の要素の型に対応しています。\n" "型`b`は「累算器」の型として考えることができます。\n" "累算器とは配列を走査しつつ結果を累算するものです。" @@ -19285,13 +19284,16 @@ msgstr "" #. type: Plain text #: text/chapter4.md:401 -#, fuzzy, no-wrap +#, 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 use the addition operator, and the initial value of the accumulator will be zero:\n" msgstr "" "実際にこれらの関数の動きを見てみましょう。\n" "`foldl`を使用して数の配列の和を求めてみます。\n" "型`a`は`Int`になり、結果の型`b`も`Int`として選択できます。\n" -"ここでは、次の要素を累算器に加算する`Int -> Int -> Int`という型の関数、`Int`型の累算器の初期値、和を求めたい`Int`の配列という、3つの引数を提供する必要があります。\n" +"ここでは3つの引数を与える必要があります。\n" +"1つ目は次の要素を累算器に加算する`Int -> Int -> Int`という型の関数です。\n" +"2つ目は累算器の`Int`型の初期値です。\n" +"3つ目は和を求めたい`Int`の配列です。\n" "最初の引数としては、加算演算子を使用できますし、累算器の初期値はゼロになります。\n" #. type: Fenced code block (text) @@ -19325,19 +19327,13 @@ msgstr "" #. type: Plain text #: text/chapter4.md:415 -#, fuzzy -#| 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:" msgid "" "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 @@ -19372,10 +19368,8 @@ msgstr "(((((\"\" <> show 1) <> show 2) <> show 3) <> show 4) <> show 5)\n" #. type: Plain text #: text/chapter4.md:431 -#, fuzzy -#| msgid "whereas the right fold is equivalent to this:" msgid "Whereas the right fold is equivalent to this:" -msgstr "それに対し、右畳み込みは以下に相当します。" +msgstr "それに対し、右畳み込みは以下と等価です。" #. type: Fenced code block (text) #: text/chapter4.md:432 @@ -19391,24 +19385,16 @@ msgstr "末尾再帰" #. type: Plain text #: text/chapter4.md:439 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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 -#, fuzzy -#| 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で次のコードを入力すると、この問題を簡単に検証できます。" @@ -19444,51 +19430,31 @@ msgstr "" #. type: Plain text #: text/chapter4.md:458 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| msgid "" -#| "PureScript provides a partial solution to this problem in the form of " -#| "_tail recursion optimization_." msgid "" "PureScript provides a partial solution to this problem through _tail " "recursion optimization_." -msgstr "" -"PureScriptは _末尾再帰最適化_ (tail recursion optimization) の形でこの問題に" -"対する部分的な解決策を提供しています。" +msgstr "PureScriptは*末尾再帰最適化*の形でこの問題に対する部分的な解決策を提供しています。" #. type: Plain text #: text/chapter4.md:462 -#, fuzzy, 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." +#, 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 -#, fuzzy -#| 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." msgid "" "The key observation that enables tail recursion optimization: a recursive " "call in _tail position_ to a function can be replaced with a _jump_, which " @@ -19497,12 +19463,12 @@ msgid "" "overflow in the example – the recursive call to `f` was _not_ in tail " "position." msgstr "" -"末尾再帰最適化を可能にする上で鍵となる観点は以下となります。 _末尾位置_ " -"(tail position) にある関数の再帰的な呼び出しは、スタックフレームが確保されな" -"い _ジャンプ_ に置き換えることができます。関数が戻るより前の最後の呼び出しで" -"あるとき、呼び出しが _末尾位置_ にあるといいます。なぜこの例でスタックオー" -"バーフローが見られたのかはこれが理由です。この`f`の再帰呼び出しは、末尾位置 _" -"ではない_ からです。" +"末尾再帰最適化を可能にする上で鍵となる観点は以下となります。\n" +"*末尾位置*にある関数の再帰的な呼び出しは*ジャンプ*に置き換えられます。\n" +"このジャンプではスタックフレームが確保されません。\n" +"関数が戻るより前の最後の呼び出しであるとき、呼び出しが*末尾位置*にあるといいます。\n" +"なぜ先の例でスタックオーバーフローが見られたのかはこれが理由です。\n" +"`f`の再帰呼び出しが末尾位置*でなかったからです。" #. type: Plain text #: text/chapter4.md:466 @@ -19529,16 +19495,12 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:factorialTailRec}}\n #. type: Plain text #: text/chapter4.md:474 -#, fuzzy -#| msgid "" -#| "Notice that the recursive call to `factorialTailRec` is the last thing " -#| "that happens in this function - it is in tail position." msgid "" "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 @@ -19548,23 +19510,18 @@ msgstr "累算器" #. type: Plain text #: text/chapter4.md:478 -#, fuzzy msgid "" "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 "" -"末尾再帰ではない関数を末尾再帰関数に変える一般的な方法としては、*累算器引数*を使用する方法があります。\n" -"累算器引数は関数に追加される余剰の引数で返り値を*累算*するものです。\n" -"これは結果を累算するために返り値を使うのとは対称的です。" +"末尾再帰ではない関数を末尾再帰関数に変える一般的な方法は、*累算器引数*を使用することです。\n" +"累算器引数は関数に追加される余剰の引数で、返り値を*累算*するものです。\n" +"これは結果を累算するために返り値を使うのとは対照的です。" #. type: Plain text #: text/chapter4.md:480 -#, fuzzy -#| msgid "" -#| "For example, consider again the `length` function presented in the " -#| "beginning of the chapter:" msgid "" "For example, consider again the `length` function presented at the beginning " "of the chapter:" @@ -19607,43 +19564,35 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:lengthTailRec}}\n" #. type: Plain text #: text/chapter4.md:496 -#, fuzzy -#| 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." msgid "" "In this case, we delegate to the helper function `length'`, which is tail " "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'`に委譲しています。`length'`" -"は末尾再帰です。その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。こ" -"れは、生成されたコードが _whileループ_ となり、大きな入力でもスタックが溢れな" -"いことを意味します。" +"ここでは補助関数`length'`に委譲しています。\n" +"この関数は末尾再帰です。\n" +"その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。\n" +"つまり、生成されるコードは*whileループ*となり、大きな入力でもスタックが溢れません。" #. type: Plain text #: text/chapter4.md:498 -#, fuzzy 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 at 0 and grows by " "adding 1 for every element in the input array." msgstr "" -"`lengthTailRec`の実装を理解するために補助関数`length'`に着目しましょう。\n" -"この関数は必然的に累算器引数を使って、部分的な結果である追加の状態を保持しています。\n" -"0から始まり、入力の配列中の全ての要素それぞれについて1ずつ足されて大きくなっていきます。" +"`lengthTailRec`の実装を理解する上では、補助関数`length'`が基本的に累算器引数を使って追加の状態を保持していることに注目してください。\n" +"追加の状態とは、部分的な結果です。\n" +"0から始まり、入力の配列中の全ての各要素について1ずつ足されて大きくなっていきます。" #. type: Plain text #: text/chapter4.md:500 -#, fuzzy msgid "" "Note also that while we might think of the accumulator as a \"state\", there " "is no direct mutation." -msgstr "累算器を「状態」と考えることもできますが、直接には変更されているわけではないことにも注意してください。" +msgstr "なお、累算器を「状態」と考えることもできますが、直接には変更されていません。" #. type: Title ## #: text/chapter4.md:501 @@ -19653,17 +19602,6 @@ msgstr "明示的な再帰より畳み込みを選ぼう" #. type: Plain text #: text/chapter4.md:504 -#, fuzzy -#| 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." msgid "" "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 " @@ -19674,14 +19612,10 @@ msgid "" "are well-understood, and as such, communicate the _intent_ of the algorithm " "much better than explicit recursion." msgstr "" -"末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けることがで" -"きるので、全ての関数をこの形で書こうとする誘惑にかられます。\n" -"しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書く" -"ことができることを忘れがちです。\n" -"`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、" -"コードの単純さという利点があります。\n" -"これらの部品はよく知られており、明示的な再帰よりもアルゴリズムの*意図*をより" -"はっきりとさせるのです。" +"末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けられるので、全ての関数をこの形で書こうとする誘惑にかられます。\n" +"しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書くことができることを忘れがちです。\n" +"`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、コードの単純さという利点があります。\n" +"これらの部品はよく知られており、だからこそ明示的な再帰よりもアルゴリズムの*意図*がより良く伝わるのです。" #. type: Plain text #: text/chapter4.md:506 @@ -19763,27 +19697,16 @@ msgstr "仮想ファイルシステム" #. type: Plain text #: text/chapter4.md:531 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| 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 "" @@ -19812,13 +19735,9 @@ msgstr "`filename`関数は`Path`のファイル名を返します。" #. type: Bullet: '- ' #: text/chapter4.md:540 -#, fuzzy -#| 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 "`size`関数は`Path`が示すファイルの大きさを返します。" +msgstr "`size`関数はファイルを表す`Path`のファイルの大きさを返します。" #. type: Bullet: '- ' #: text/chapter4.md:540 @@ -19892,17 +19811,12 @@ msgstr "" #. type: Plain text #: text/chapter4.md:573 -#, fuzzy -#| msgid "" -#| "The `Test.Examples` module defines functions which 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." msgid "" "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`モジュールだけで作業します。" @@ -19914,16 +19828,12 @@ msgstr "全てのファイルの一覧" #. type: Plain text #: text/chapter4.md:577 -#, fuzzy -#| msgid "" -#| "Let's write a function which performs a deep enumeration of all files " -#| "inside a directory. This function will have the following type:" msgid "" "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 @@ -19933,13 +19843,6 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_signature}} #. type: Plain text #: text/chapter4.md:583 -#, fuzzy -#| 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." 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 " @@ -19947,10 +19850,10 @@ msgid "" "`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 @@ -19965,12 +19868,11 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_implementat #. type: Plain text #: text/chapter4.md:591 -#, fuzzy, 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." +#, 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 @@ -20007,13 +19909,6 @@ msgstr "" #. type: Plain text #: text/chapter4.md:606 -#, fuzzy -#| 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." 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 " @@ -20023,9 +19918,9 @@ msgid "" msgstr "" "逆向きの矢印は配列から要素を選択するのに相当することを思い出してください。\n" "最初の工程は引数の直接の子から要素を選択することです。\n" -"それから、単にそのファイルに対してこの再帰関数を呼びします。\n" -"do記法を使用しているので、再帰的な結果を全て連結する`concatMap`が暗黙に呼び出" -"されています。" +"それからそのファイルに対して再帰関数を呼び出します。\n" +"do記法を使用しているので`concatMap`が暗黙に呼び出されています。\n" +"この関数は再帰的な結果を全て連結します。" #. type: Plain text #: text/chapter4.md:608 @@ -20040,16 +19935,13 @@ msgstr "{{#include ../exercises/chapter4/test/Examples.purs:allFiles_2}}\n" #. type: Plain text #: text/chapter4.md:614 -#, fuzzy -#| msgid "" -#| "Try out the new version in PSCi - you should get the same result. I'll " -#| "let you decide which version you find clearer." msgid "" "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 @@ -20099,21 +19991,17 @@ msgstr "" #. type: Plain text #: text/chapter4.md:630 -#, fuzzy, 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" +#, 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 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 -#, fuzzy msgid "" "In this chapter, we covered the basics of recursion in PureScript to express " "algorithms concisely. We also introduced user-defined infix operators, " @@ -20122,7 +20010,7 @@ msgid "" "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" "最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。" From a902a70124d6e04e2fcea5d944d0b9cd30bf2b8e Mon Sep 17 00:00:00 2001 From: gemmaro Date: Tue, 18 Jul 2023 08:41:25 +0900 Subject: [PATCH 10/29] [ update ] chapter 5 translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ change ] '適合' -> '照合' * [ change ] 'メッセージ' -> '文言' --- text-ja/chapter10.md | 4 +- text-ja/chapter3.md | 2 +- text-ja/chapter4.md | 4 +- text-ja/chapter5.md | 677 +++++++++++++++++++++++++++++++++++++++ translation/ja.po | 713 ++++++++++-------------------------------- translation/terms.txt | 2 + 6 files changed, 847 insertions(+), 555 deletions(-) create mode 100644 text-ja/chapter5.md diff --git a/text-ja/chapter10.md b/text-ja/chapter10.md index 81e34ca7..bf5f0fc0 100644 --- a/text-ja/chapter10.md +++ b/text-ja/chapter10.md @@ -1620,8 +1620,8 @@ export const log = function (s) { }; ``` -実行時の -`log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返します。内側の関数はコンソールにメッセージを書き込むという副作用を実行します。 +実行時の `log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返します。 +内側の関数はコンソールに文言を書き込むという副作用を実行します。 `Effect a`型の式は、通常のJavaScriptのメソッドのようにJavaScriptから呼び出すことができます。例えば、この `main`関数は何らかの型`a`について`Effect a`という型でなければならないので、次のように実行できます。 diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md index 12269aca..1a7e1dd7 100644 --- a/text-ja/chapter3.md +++ b/text-ja/chapter3.md @@ -212,7 +212,7 @@ add x y z = x + y + z ``` -後者では、PureScriptコンパイラはそれぞれの行ごとに1つ、つまり*2つ*の宣言であると構文解析します。 +後者では、PureScriptコンパイラはそれぞれの行毎に1つ、つまり*2つ*の宣言であると構文解析します。 一般に、同じブロック内で定義された宣言は同じ深さで字下げする必要があります。 例えばPSCiでlet文の宣言は同じ深さで字下げしなければなりません。 diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md index 44bd6eec..6a96a7a2 100644 --- a/text-ja/chapter4.md +++ b/text-ja/chapter4.md @@ -33,7 +33,7 @@ test`を走らせることで解答を確認してください。 再帰は一般のプログラミングでも重要な手法ですが、特に純粋関数型プログラミングでは当たり前のように用いられます。この章で見ていくように、再帰はプログラムの変更可能な状態を減らすために役立つからです。 再帰は*分割統治*戦略と密接な関係があります。 -分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分ごとの答えから最終的な答えを組み立てるということです。 +分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分毎の答えから最終的な答えを組み立てるということです。 それでは、PureScriptにおける再帰の簡単な例を幾つか見てみましょう。 @@ -203,7 +203,7 @@ infix 8 range as .. ## 配列の絞り込み `Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供しています。 -この関数は、述語関数に適合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。 +この関数は、述語関数に照合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。 例えば1から10までの数で、偶数であるような数の配列を計算したいとします。 これは次のようにできます。 diff --git a/text-ja/chapter5.md b/text-ja/chapter5.md new file mode 100644 index 00000000..2661bdb9 --- /dev/null +++ b/text-ja/chapter5.md @@ -0,0 +1,677 @@ +# パターン照合 + +## この章の目標 + +この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。 +また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱います。 + +パターン照合は関数型プログラミングにおける一般的な手法であり、開発者が簡潔に関数を書けるようになります。 +関数の実装を複数の場合に分解することにより、水面下の複雑なアイディアが表現されるのです。 + +代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等の水準の表現力を可能にしています。 +パターン照合とも密接に関連しています。 + +この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラフィックスを記述し操作するためのライブラリを書くことです。 + +## プロジェクトの準備 + +この章のソースコードはファイル `src/Data/Picture.purs`で定義されています。 + +`Data.Picture`モジュールは簡単な図形を表すデータ型`Shape`やその図形の集合である型`Picture`を定義します。 +また、これらの型を扱うための関数もあります。 + +このモジュールでは、データ構造の畳込みを行う関数を提供する `Data.Foldable`モジュールもインポートします。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:module_picture}} +``` + +`Data.Picture`モジュールは`Number`モジュールもインポートしますが、こちらは`as`キーワードを使います。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:picture_import_as}} +``` + +こうすると型や関数をモジュール内で使用できるようになりますが、 +`Number.max`のように*修飾名*を使ったときに限定されます。 +重複したインポートを避けたり、どのモジュールからインポートされたのかを明らかにするのに役立ちます。 + +> *補足*:元のモジュールと同じモジュール名を修飾名に使用する必要はありません。 +> `import Math as M`などのより短い名前にできますし、かなりよく見掛けます。 + +## 単純なパターン照合 + +例を見ることから始めましょう。 +パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになります。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcd}} +``` + +このアルゴリズムはユークリッドの互除法と呼ばれています。 +その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が見つかるでしょう。 +パターン照合の利点の1つは、コードを場合分けして定義でき、数学関数の仕様に似た単純で宣言型なコードを定義できることです。 + +パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作します。 +この定義の各行は*選択肢*や*場合*と呼ばれています。 +等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ以上のパターンで構成されています。 +場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなければならない条件を表現しています。 +それぞれの場合は上からこの順番に試されていき、最初にパターンが入力に照合した場合が返り値を決定します。 + +例えば`gcd`関数は次の手順で評価されます。 + +- まず最初の場合が試されます。 + 第2引数がゼロの場合、関数は `n`(最初の引数)を返します。 +- そうでなければ、2番目の場合が試されます。 + 最初の引数がゼロの場合、関数は `m`(第2引数)を返します。 +- それ以外の場合、関数は最後の行の式を評価して返します。 + +なお、パターンでは値を名前に束縛できます。 +この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛しています。 +様々な種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力の引数から名前を選ぶ様々な方法に対応することがわかるでしょう。 + +## 単純なパターン + +上記のコード例では、2種類のパターンを示しました。 + +- `Int`型の値が正確に一致する場合にのみ照合する、整数直値パターン +- 引数を名前に束縛する、変数パターン + +単純なパターンには他にも種類があります。 + +- `Number`、`String`、`Char`、そして`Boolean`といった直値 +- どんな引数とも照合するが名前に束縛はしない、アンダースコア (`_`) で表されるワイルドカードパターン + +これらの単純なパターンを使用する実演として、もう2つの例が以下です。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:fromString}} + +{{#include ../exercises/chapter5/src/ChapterExamples.purs:toString}} +``` + +PSCiでこれらの関数を試してみてください。 + +## ガード + +ユークリッドの互除法の例では、`m > n`のときと`m <= n`のときの2つの選択肢の間を切り替えるために`if .. then .. else`式を使いました。 +こういうときには*ガード*を使うという他の選択肢もあります。 + +ガードとは、パターンにより課された制約に加えて満たされなくてはいけない真偽値の式です。 +ガードを使用してユークリッドのアルゴリズムを書き直すと、次のようになります。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcdV2}} +``` + +この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を課しています。 +最後の行でのガードは式`otherwise`を使っています。 +これはキーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。 + +```text +> :type otherwise +Boolean + +> otherwise +true +``` + +この例が示すように、ガードは等号の左側に現れ、パイプ文字 (`|`) でパターンのリストと区切られています。 + +## 演習 + +1. (簡単)パターン照合を使用して、階乗関数`factorial`を書いてみましょう。 + *手掛かり*:入力がゼロのときとゼロでないときの、2つの特殊な場合を考えてみてください。 + *補足*:これは前の章の例の反復ですが、ここでは自力で書き直せるかやってみてください。 +1. (普通)\\( (1 + x) ^ n \\)を多項式展開した式にある\\( x ^ k + \\)の項の係数を求める関数`binomial`を書いてください。 + これは`n`要素の集合から`k`要素の部分集合を選ぶ方法の数と同じです。 + 数式\\( n! / k! (n - k)! \\)を使ってください。 + ここで \\( ! \\) は前に書いた階乗関数です。 + *手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。 + 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、もっと使用例を追加してみてください。 +1. (普通)[_パスカルの法則_](https://en.wikipedia.org/wiki/Pascal%27s_rule)を使って前の演習と同じ2項係数を計算する関数`pascal`を書いてください。 + +## 配列パターン + +*配列直値パターン*は、固定長の配列に対して照合する方法を提供します。 +例えば空の配列であるか判定する関数`isEmpty`を書きたいとします。 +最初の選択肢に空の配列パターン (`[]`) を用いるとこれを実現できます。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}} +``` + +次の関数では、長さ5の配列と照合し、配列の5つの要素をそれぞれ違った方法で束縛しています。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:takeFive}} +``` + +最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にのみ照合します。 +その場合、関数は第3要素と第4要素の積を返します。 +それ以外の場合は、関数は0を返します。 +例えばPSCiで試してみると次のようになります。 + +```text +> :paste +… takeFive [0, 1, a, b, _] = a * b +… takeFive _ = 0 +… ^D + +> takeFive [0, 1, 2, 3, 4] +6 + +> takeFive [1, 2, 3, 4, 5] +0 + +> takeFive [] +0 +``` + +配列の直値パターンでは、固定長の配列と一致させることはできます。 +しかしPureScriptは不特定の長さの配列を照合させる手段は全く提供して*いません*。 +そのような類の方法で不変な配列を分解すると、実行速度が低下する可能性があるためです。 +このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めします。 +その他の操作について、より優れた漸近性能を提供するデータ構造も存在します。 + +## レコードパターンと行多相 + +*レコードパターン*は(ご想像の通り)レコードに照合します。 + +レコードパターンはレコード直値にほぼ見た目が似ていますが、コロンの右に値を置くのではなく、それぞれのフィールドで束縛子を指定します。 + +例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレコードに照合し、これらのフィールドの値はそれぞれ `x`と +`y`という名前に束縛されます。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:showPerson}} +``` + +レコードパターンはPureScriptの型システムの興味深い機能である*行多相*の良い例となっています。 +もし上の`showPerson`を型シグネチャなしで定義していたとすると、この型はどのように推論されるのでしょうか。 +面白いことに、推論される型は上で与えた型とは同じではありません。 + +```text +> showPerson { first: x, last: y } = y <> ", " <> x + +> :type showPerson +forall r. { first :: String, last :: String | r } -> String +``` + +この型変数 `r`は何でしょうか。 +PSCiで`showPerson`を使ってみると、面白いことがわかります。 + +```text +> showPerson { first: "Phil", last: "Freeman" } +"Freeman, Phil" + +> showPerson { first: "Phil", last: "Freeman", location: "Los Angeles" } +"Freeman, Phil" +``` + +レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま動作するのです。 +レコードに少なくとも型が`String`であるようなフィールド`first`と`last`が含まれていれば、関数適用は正しく型付けされます。 +しかし、フィールドが*不足*していると、`showPerson`の呼び出しは*不正*となります。 + +```text +> showPerson { first: "Phil" } + +Type of expression lacks required label "last" +``` + +`showPerson`の新しい型シグネチャを読むと、「`String`な`first`と`last`フィールド _と他のフィールドを何でも_ +持つあらゆるレコードを取り、`String`を返す」となります。なお、この挙動は元の`showPerson`のものとは異なります。行変数`r`がなければ`showPerson`は +_厳密に_ `first`と`last`フィールドしかないレコードのみを受け付けます。 + +なお、次のように書くこともできます。 + +```haskell +> showPerson p = p.last <> ", " <> p.first +``` + +そしてPSCiは同じ型を推論することでしょう。 + +## レコード同名利用 + +`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と`y`という名前の値に束縛していたのでした。 +別の方法として、フィールド名自体を再利用してこのような類のパターン照合を次のように単純化できます。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:showPersonV2}} +``` + +ここでは、プロパティの名前のみを指定し、名前に導入したい値を指定する必要はありません。これは _レコード同名利用_ (record pun) +と呼ばれます。 + +レコード同名利用はレコードの*構築*にも使用できます。 +例えば、スコープに `first`と `last`という名前の値があれば、`{ first, last }`を使って人物レコードを作ることができます。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:unknownPerson}} +``` + +こうすると、状況によってはコードの可読性が向上します。 + +## 入れ子になったパターン + +配列パターンとレコードパターンはどちらも小さなパターンを組み合わせることで大きなパターンを構築しています。 +これまでのほとんどの例では配列パターンとレコードパターンの内部で単純なパターンを使用していました。 +しかし特筆すべきこととして、パターンは自由に*入れ子*にできます。 +これにより潜在的に複雑なデータ型についての条件を使って関数を定義できます。 + +例えばこのコードは2つのレコードパターンを組み合わせています。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:livesInLA}} +``` + +## 名前付きパターン + +入れ子のパターンを使う場合、パターンには*名前を付け*てスコープに名前を追加で持ち込むことができます。 +任意のパターンに名前を付けるには、 `@`記号を使います。 + +例えば次の関数は2要素配列を整列するもので、2つの要素に名前を付けていますが、配列自身にも名前を付けています。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}} +``` + +このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。 +なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返します。 + +## 演習 + +1. (簡単)レコードパターンを使って、2つの `Person`レコードが同じ都市にいるか調べる関数 `sameCity`を定義してみましょう。 +1. (普通)行多相を考慮すると、 `sameCity`関数の最も一般的な型は何でしょうか。 + 先ほど定義した`livesInLA`関数についてはどうでしょうか。 + *補足*:この演習にテストはありません。 +1. (普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数`fromSingleton`を書いてみましょう。 + 1要素だけを持つ配列でない場合、関数は与えられた既定値を返します。 + この関数は`forall a. a -> Array a -> a`という型を持ちます。 + +## Case式 + +パターンが現れるのは最上位にある関数宣言だけではありません。 +`case`式を使う計算中の途中の値に対してパターン照合を使えます。 +case式には無名関数に似た便利さがあります。 +関数に名前を与えることがいつも望ましいわけではないように、パターンを使いたいためだけに関数に名前をつけるようなことを避けられるようになります。 + +例を示しましょう。 +次の関数は、配列の「最長ゼロ末尾」(和がゼロであるような、最も長い配列の末尾)を計算します。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:lzsImport}} + +{{#include ../exercises/chapter5/src/ChapterExamples.purs:lzs}} +``` + +以下は一例です。 + +```text +> lzs [1, 2, 3, 4] +[] + +> lzs [1, -1, -2, 3] +[-1, -2, 3] +``` + +この関数は場合毎の分析によって動作します。 +もし配列が空なら、唯一の選択肢は空の配列を返すことです。 +配列が空でない場合は、更に2つの場合に分けるためにまず`case`式を使用します。 +配列の合計がゼロであれば、配列全体を返します。 +そうでなければ、配列の残りに対して再帰します。 + +## パターン照合の失敗と部分関数 + +case式のパターンを順番に照合していって、どの選択肢の場合も入力が照合しなかった時はどうなるのでしょう。 +この場合、*パターン照合失敗*によって、case式は実行時に失敗します。 + +簡単な例でこの動作を見てみましょう。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:unsafePartialImport}} + +{{#include ../exercises/chapter5/src/ChapterExamples.purs:partialFunction}} +``` + +この関数は単一の場合しか含んでいません。 +そしてその場合は単一の入力である`true`にのみ照合します。 +このファイルをコンパイルしてPSCiでそれ以外の値を与えて試すと実行時エラーが発生します。 + +```text +> partialFunction false + +Failed pattern match +``` + +どんな入力の組み合わせに対しても値を返すような関数は*全関数*と呼ばれ、そうでない関数は*部分的*であると呼ばれます。 + +一般的には、可能な限り全関数として定義したほうが良いと考えられています。 +もし関数が何らかの妥当な入力の集合について結果を返さないことがわかっているなら、大抵は失敗であることを示すことができる値を返すほうがよいでしょう。 +例えば何らかの`a`についての型`Maybe a`で、妥当な結果を返せないときは`Nothing`を使います。 +この方法なら、型安全な方法で値の有無を示すことができます。 + +PureScriptコンパイラは、パターン照合が不完全であるために関数が全関数ではないことが検出されると、エラーを出します。 +`unsafePartial`関数を使うとこうしたエラーを抑制できます(ただしその部分関数が安全だと言い切れるなら)。 +もし上記の`unsafePartial`関数の呼び出しを取り除くと、コンパイラは次のエラーを出します。 + +```text +A case expression could not be determined to cover all inputs. +The following additional cases are required to cover all inputs: + + false +``` + +これは値`false`が、定義されたどのパターンとも一致しないことを示しています。 +一般にこれらの警告には、複数の不一致な場合が含まれることがあります。 + +上記の型シグネチャも省略した場合は、次のようになります。 + +```haskell +partialFunction true = true +``` + +このとき、PSCiは興味深い型を推論します。 + +```text +> :type partialFunction + +Partial => Boolean -> Boolean +``` + +本書では以降、`=>`記号が絡む(*型クラス*に関連する)型をもっと見ていきます。 +しかし現時点では、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。 + +コンパイラは、*冗長*な場合を検出したとき(つまり、その場合より前の方に定義された場合にのみ一致するとき)などにも警告を出します。 + +```haskell +redundantCase :: Boolean -> Boolean +redundantCase true = true +redundantCase false = false +redundantCase false = false +``` + +このとき、最後の場合は冗長であると正しく検出されます。 + +```text +A case expression contains unreachable cases: + + false +``` + +> *補足*:PSCiは警告を表示しません。 +> そのため、この例を再現するには、この関数をファイルとして保存し、`spago build`を使ってコンパイルします。 + +## 代数的データ型 + +この節では _代数的データ型_ (algebraic data type, _ADT_) +と呼ばれる、PureScriptの型システムの機能を導入します。この機能はパターン照合と地続きの関係があります。 + +しかしまずは切り口となる例について考えていきます。この例では単純なベクターグラフィックスライブラリの実装というこの章の課題を解決する基礎を与えます。 + +直線、矩形、円、テキストなどの単純な図形の種類を表現する型を定義したいとします。 +オブジェクト指向言語では、恐らくインターフェースもしくは抽象クラス +`Shape`を定義し、使いたいそれぞれの図形について具体的なサブクラスを定義するでしょう。 + +しかし、この方針は大きな欠点を1つ抱えています。 +`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に把握し、`Shape`インターフェースに定義する必要があるのです。 +モジュール性を壊さずに新しい操作を追加することが難しくなります。 + +もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決する型安全な方法を提供します。 +モジュール性のある方法で `Shape`に新たな操作を定義しつつ、型安全性を維持できます。 + +代数的データ型としてどのように`Shape`が表現されるかを次に示します。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:Shape}} + +{{#include ../exercises/chapter5/src/Data/Picture.purs:Point}} +``` + +この宣言では`Shape`をそれぞれの構築子の直和として定義しており、各構築子では含まれるデータを指定します。 +`Shape`は、中央 `Point`と半径(数値)を持つ `Circle`か、`Rectangle`、 `Line`、 `Text`の何れかです。 +他に`Shape`型の値を構築する方法はありません。 + +代数的データ型 (algebraic data type; ADT) +の定義はキーワード`data`から始まり、それに新しい型の名前と任意個の型引数が続きます。 +その型の構築子(これを*データ構築子*と言います)は等号の後に定義され、パイプ文字 (`|`) で区切られます。 +ADTの構築子が持つデータは原始型に限りません。 +構築子にはレコード、配列、また他のADTさえも含められます。 + +それではPureScriptの標準ライブラリから別の例を見てみましょう。 +省略可能な値を定義するのに使われる `Maybe`型を本書の冒頭で扱いました。 +`maybe`パッケージでは `Maybe`を次のように定義しています。 + +```haskell +data Maybe a = Nothing | Just a +``` + +この例では型引数 `a`の使用方法を示しています。パイプ文字を「または」と読むことにすると、この定義は「`Maybe a`型の値は、無い +(`Nothing`) か、ただの (`Just`) 型 `a`の値だ」とほぼ英語のように読むことができます。 + +なお、データ定義のどこにも構文`forall a`を使っていません。 +`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義するときは使われません。 + +データ構築子は再帰的なデータ構造を定義するためにも使用できます。更に例を挙げると、要素が型 +`a`の単方向連結リストのデータ型の定義はこのようになります。 + +```haskell +data List a = Nil | Cons a (List a) +``` + +この例は `lists`パッケージから持ってきました。 +ここで `Nil`構築子は空のリストを表しており、`Cons`は先頭となる要素と尾鰭から空でないリストを作成するために使われます。 +`Cons`の2つ目のフィールドでデータ型 `List a`を使用しており、再帰的なデータ型になっていることに注目してください。 + +## ADTの使用 + +代数的データ型の構築子を使用して値を構築するのはとても簡単です。 +対応する構築子に含まれるデータに応じた引数を用意し、その構築子を単に関数のように適用するだけです。 + +例えば、上で定義した `Line`構築子は2つの `Point`を必要としていますので、`Line`構築子を使って `Shape`を構築するには、型 +`Point`の2つの引数を与えなければなりません。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:exampleLine}} +``` + +さて、代数的データ型で値を構築することは簡単ですが、これをどうやって使ったらよいのでしょうか。 +ここで代数的データ型とパターン照合との重要な接点が見えてきます。 +代数的データ型の値を消費する唯一の方法は構築子に照合するパターンを使うことです。 + +例を見てみましょう。 +`Shape`を `String`に変換したいとします。 +`Shape`を構築するのにどの構築子が使用されたかを調べるには、パターン照合を使用しなければなりません。 +これには次のようにします。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:showShape}} + +{{#include ../exercises/chapter5/src/Data/Picture.purs:showPoint}} +``` + +各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できます。 +`showShape`の最初の場合を考えてみましょう。 +もし `Shape`が `Circle`構築子に照合した場合、2つの変数パターン `c`と +`r`を使って`Circle`の引数(中心と半径)がスコープに導入されます。 +その他の場合も同様です。 + +## 演習 + +1. (簡単)`Circle`(型は`Shape`)を構築する関数`circleAtOrigin`を書いてください。 + 中心は原点にあり、半径は`10.0`です。 +1. (普通)原点を中心として`Shape`の大きさを`2.0`倍に拡大する関数`doubleScaleAndCenter`を書いてみましょう。 +1. (普通)`Shape`からテキストを抽出する関数`shapeText`を書いてください。 + この関数は`Maybe + String`を返しますが、もし入力が`Text`を使用して構築されたのでなければ、返り値には`Nothing`構築子を使ってください。 + +## Newtype + +代数的データ型の特殊な場合として、 _newtype_ と呼ばれるものがあります。newtypeはキーワード `data`の代わりにキーワード +`newtype`を使用して導入します。 + +newtype宣言では*過不足なく1つだけの*構築子を定義しなければならず、その構築子は*過不足なく1つだけの*引数を取る必要があります。 +つまり、newtype宣言は既存の型に新しい名前を与えるものなのです。 +実際、newtypeの値は、元の型と同じ実行時表現を持ってるので、実行時性能のオーバーヘッドがありません。 +しかし、これらは型システムの観点から区別されます。 +型安全性に追加の層を与えるのです。 + +例として、ボルト、アンペア、オームのような単位を表現するために、`Number`の型レベルの別名を定義したくなる場合があるかもしれません。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:electricalUnits}} +``` + +それからこれらの型を使う関数と値を定義します。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:calculateCurrent}} +``` + +これによりつまらないミスを防ぐことができます。例えば電源 _なし_ に _2つ_ の電球により生み出される電流を計算しようとするなどです。 + +```haskell +current :: Amp +current = calculateCurrent lightbulb lightbulb +{- +TypesDoNotUnify: + current = calculateCurrent lightbulb lightbulb + ^^^^^^^^^ + Could not match type + Ohm + with type + Volt +-} +``` + +もし`newtype`なしに単なる`Number`を使っていたら、コンパイラはこのミスを捕捉できません。 + +```haskell +-- これもコンパイルできますが、型安全ではありません。 +calculateCurrent :: Number -> Number -> Number +calculateCurrent v r = v / r + +battery :: Number +battery = 1.5 + +lightbulb :: Number +lightbulb = 500.0 + +current :: Number +current = calculateCurrent lightbulb lightbulb -- 捕捉されないミス +``` + +なお、newtypeは単一の構築子しかとれず、構築子は単一の値でなくてはなりませんが、newtypeは任意の数の型変数を取ることが*できます*。 +例えば以下のnewtypeは妥当な定義です(`err`と`a`は型変数で、`CouldError`構築子は型`Either err +a`の*単一*の値を期待します)。 + +```Haskell +newtype CouldError err a = CouldError (Either err a) +``` + +また、newtypeの構築子はよくnewtype自身と同じ名前を持つことがあります。 +ただこれは必須ではありません。 +例えば別個の名前であっても正しいものです。 + +```haskell +{{#include ../exercises/chapter5/src/ChapterExamples.purs:Coulomb}} +``` + +この場合`Coulomb`は(引数ゼロの)*型構築子*で、`MakeCoulomb`は*データ構築子*です。 +これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名前には一意性があります。 +これは全てのADTについて言えることです。 +なお、型構築子とデータ構築子には異なる名前を付けられますが、実際には同じ名前を共有するのが普通です。 +前述の`Amp`と`Volt`の場合がこれです。 + +newtypeの別の応用は、実行時表現を変えることなく、既存の型に異なる _挙動_ を加えることです。その利用例については次章で _型クラス_ +をお話しするときに押さえます。 + +## 演習 + +1. (簡単)`Watt`を`Number`の`newtype`として定義してください。それからこの新しい`Watt`型と前述の`Amp`と`Volt`の定義を使って`calculateWattage`関数を定義してください。 + +```haskell +calculateWattage :: Amp -> Volt -> Watt +``` + +`Watt`中のワット数は与えられた`Amp`中の電流と与えられた`Volt`の電圧の積で計算できます。 + +## ベクターグラフィックスライブラリ + +これまで定義してきたデータ型を使って、ベクターグラフィックスを扱う簡単なライブラリを作成していきましょう。 + +`Picture`という型同義語を定義しておきます。 +これはただの`Shape`の配列です。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:Picture}} +``` + +デバッグしていると `Picture`を `String`として表示できるようにしたくなることもあるでしょう。これはパターン照合を使用して定義された +`showPicture`関数でできます。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:showPicture}} +``` + +試してみましょう。 +モジュールを `spago build`でコンパイルし、 `spago repl`でPSCiを開きます。 + +```text +$ spago build +$ spago repl + +> import Data.Picture + +> showPicture [ Line { x: 0.0, y: 0.0 } { x: 1.0, y: 1.0 } ] + +["Line [start: (0.0, 0.0), end: (1.0, 1.0)]"] +``` + +## 外接矩形の算出 + +このモジュールのコード例には、 `Picture`の最小外接矩形を計算する関数 `bounds`が含まれています。 + +`Bounds`型は外接矩形を定義します。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:Bounds}} +``` + +`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累算するため、`bounds`には `Data.Foldable`の +`foldl`関数を使用しています。 + +```haskell +{{#include ../exercises/chapter5/src/Data/Picture.purs:bounds}} +``` + +基底の場合では、空の +`Picture`の最小外接矩形を求める必要がありますが、`emptyBounds`で定義される空の外接矩形がその条件を満たしています。 + +累算関数`combine`は`where`ブロックで定義されています。 +`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の +`Shape`を引数にとり、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。 +`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。 + +## 演習 + +1. (普通)ベクターグラフィックライブラリを拡張し、`Shape`の面積を計算する新しい操作 `area`を追加してください。 + この演習の目的上は、線分やテキストの面積は0であるものとしてください。 +1. (難しい)`Shape`型を新しいデータ構築子 `Clipped`で拡張してください。 + `Clipped`は他の `Picture`を矩形に切り抜きます。 + 切り抜かれた図形の境界を計算できるよう、`shapeBounds`関数を拡張してください。 + なお、これにより`Shape`は再帰的なデータ型になります。 + *手掛かり* :コンパイラは必要に応じて他の関数を拡張するのに付き添ってくれるでしょう。 + +## まとめ + +この章では、関数型プログラミングから基本的ながら強力なテクニックであるパターン照合を扱いました。複雑なデータ構造の一部分と照合するために、簡単なパターンの使い方だけではなく、配列パターンやレコードパターンを使った深さのあるデータ構造の一部分との照合方法を見てきました。 + +また、この章ではパターン照合に密接に関連する代数的データ型も紹介しました。 +代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上で、モジュール性のある方法が齎されるのでした。 + +最後に*行多相*を扱いました。 +これは強力な抽象化をする型であり、これにより多くの既存のJavaScript関数に型を与えられます。 + +本書では今後も代数的データ型とパターン照合をいろんなところで使用するので、今のうちにこれらに習熟しておくと後で実を結ぶことでしょう。これ以外にも独自の代数的データ型を作成し、パターン照合を使用してそれらの型を使う関数を書いてみてください。 diff --git a/translation/ja.po b/translation/ja.po index 5f41862c..b68c4a44 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-17 11:12+0900\n" +"PO-Revision-Date: 2023-07-30 13:22+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -5488,8 +5488,8 @@ msgid "" "argument, returning a function of no arguments. The inner function performs " "the side-effect of writing a message to the console." msgstr "" -"実行時の `log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返しま" -"す。内側の関数はコンソールにメッセージを書き込むという副作用を実行します。" +"実行時の `log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返します。\n" +"内側の関数はコンソールに文言を書き込むという副作用を実行します。" #. type: Plain text #: text/chapter10.md:1369 @@ -7214,15 +7214,10 @@ msgstr "" #. type: Plain text #: text/chapter11.md:492 #, fuzzy -#| msgid "" -#| "Note that only those log messages which were written before the error was " -#| "thrown actually get appended to the log." msgid "" "Note that only those log messages that were written before the error was " "thrown get appended to the log." -msgstr "" -"実際に追加されるログは、エラーが投げられる前に書かれたログメッセージだけであ" -"ることにも注目してください。" +msgstr "実際に追加されるログは、エラーが投げられる前に書かれたログ文言だけであることにも注目してください。" #. type: Title ## #: text/chapter11.md:493 @@ -7423,14 +7418,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:543 #, fuzzy -#| 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`." msgid "" "This is because of how the side-effects provided by the `ExceptT` monad " "transformer interact with the side-effects provided by the `WriterT` monad " @@ -7440,13 +7427,9 @@ msgid "" "the first error, as we saw earlier when we transformed `Writer` with " "`ExceptT`." msgstr "" -"これは、 `ExceptT`モナド変換子が提供する副作用が、 `WriterT`モナド変換子が提" -"供する副作用と干渉するためです。\n" -"これはモナド変換子スタックが構成されている順序を変更することで解決できま" -"す。\n" -"スタックの最上部に `ExceptT`変換子を移動すると、先ほど `Writer`を `ExceptT`に" -"変換したときと同じように、最初のエラーまでに書かれた全てのメッセージが含まれ" -"るようになります。" +"これは、 `ExceptT`モナド変換子が提供する副作用が、 `WriterT`モナド変換子が提供する副作用と干渉するためです。\n" +"これはモナド変換子スタックが構成されている順序を変更することで解決できます。\n" +"スタックの最上部に `ExceptT`変換子を移動すると、先ほど `Writer`を `ExceptT`に変換したときと同じように、最初のエラーまでに書かれた全ての文言が含まれるようになります。" #. type: Plain text #: text/chapter11.md:545 @@ -7511,9 +7494,8 @@ msgstr "" #. type: Plain text #: text/chapter11.md:558 #, fuzzy, no-wrap -#| msgid " which matches a string as a prefix of the current state, or fails with an error message.\n" msgid " which matches a string as a prefix of the current state or fails with an error message.\n" -msgstr " これは現在の状態が接頭辞に適合するか、もしくはエラーメッセージとともに失敗します。\n" +msgstr " これは現在の状態が接頭辞に照合するか、もしくはエラー文言とともに失敗します。\n" #. type: Plain text #: text/chapter11.md:560 @@ -7919,7 +7901,7 @@ msgstr "guard :: forall m. Alternative m => Boolean -> m Unit\n" 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:664 @@ -7972,10 +7954,7 @@ 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 "" -"これにより、まずもし最初の文字が大文字なら複数の大文字に適合し、さもなくばも" -"し最初の文字が小文字なら複数の小文字に適合する、という構文解析器を定義できま" -"す。" +msgstr "これにより、まずもし最初の文字が大文字なら複数の大文字に照合し、さもなくばもし最初の文字が小文字なら複数の小文字に照合する、という構文解析器を定義できます。" #. type: Fenced code block (text) #: text/chapter11.md:680 @@ -7986,8 +7965,7 @@ msgstr "> upperOrLower = some upper <|> some lower\n" #. type: Plain text #: text/chapter11.md:685 msgid "This parser will match characters until the case changes:" -msgstr "" -"この構文解析器は、大文字と小文字が切り替わるまで、文字に適合し続けます。" +msgstr "この構文解析器は、大文字と小文字が切り替わるまで、文字に照合し続けます。" #. type: Fenced code block (text) #: text/chapter11.md:686 @@ -8474,15 +8452,10 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}}\n" #. type: Plain text #: text/chapter11.md:811 #, fuzzy -#| msgid "" -#| "In this case, we can use `put` to update the game state, and `tell` to " -#| "add a message to the log:" msgid "" "In this case, we can use `put` to update the game state and `tell` to add a " "message to the log:" -msgstr "" -"この場合、 `put`を使ってゲームの状態を更新し、 `tell`を使ってログにメッセージ" -"を追加できます。" +msgstr "この場合、 `put`を使ってゲームの状態を更新し、 `tell`を使ってログに文言を追加できます。" #. type: Fenced code block (haskell) #: text/chapter11.md:812 @@ -8590,16 +8563,12 @@ msgstr "" #. type: Plain text #: text/chapter11.md:835 #, fuzzy -#| 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." msgid "" "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:837 @@ -8873,12 +8842,9 @@ 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" -"最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新" -"し、`prompt`アクションを使ってプロンプトを再び表示しています。" +"純粋な計算であるゲームロジックを実行するには、画面に全てのログ文言を出力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。\n" +"`for_`アクションが(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。\n" +"最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`アクションを使ってプロンプトを再び表示しています。" #. type: Plain text #: text/chapter11.md:909 @@ -8918,18 +8884,15 @@ msgid "" "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" -"このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用して" -"います。" +"(難しい)`RWS`モナドの ` Writer`コンポーネントは、エラー文言とお知らせ文言の2つの種類の文言のために使われています。\n" +"このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用しています。" #. type: Plain text #: text/chapter11.md:920 #, fuzzy, 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" +" エラー文言を扱うのに `ExceptT`モナド変換子を使うようにし、お知らせ文言を扱うのに`RWS`を使うようにするよう、コードをリファクタリングしてください。\n" " *補足*:この演習にはテストはありません。\n" #. type: Title ## @@ -9004,10 +8967,7 @@ msgid "" "module provides several other options." msgstr "" "最初の引数は`optparse`ライブラリを設定するために使用されます。\n" -"今回の場合、アプリケーションが引数なしで走らされたときは、(「missing " -"argument」エラーを表示する代わりに)`OP.prefs OP.showHelpOnEmpty`を使って使用" -"方法のメッセージを表示するように設定していますが、`Options.Applicative." -"Builder`モジュールには他にも幾つかの選択肢を提供しています。" +"今回の場合、アプリケーションが引数なしで走らされたときは、(「missing argument」エラーを表示する代わりに)`OP.prefs OP.showHelpOnEmpty`を使って使用方法の文言を表示するように設定していますが、`Options.Applicative.Builder`モジュールには他にも幾つかの選択肢を提供しています。" #. type: Plain text #: text/chapter11.md:940 @@ -9029,12 +8989,11 @@ msgstr "" #. type: Plain text #: text/chapter11.md:948 #, fuzzy, 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:950 @@ -9296,10 +9255,8 @@ msgid "" "appropriate error message." msgstr "" "*補足*:この`unsafePartial`の呼び出しは必須です。\n" -"これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと" -"照合するためです。\n" -"ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子" -"と照合させ、適切なエラーメッセージを提供したほうがよいでしょう。" +"これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと照合するためです。\n" +"ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子と照合させ、適切なエラー文言を提供したほうがよいでしょう。" #. type: Plain text #: text/chapter12.md:33 @@ -11654,22 +11611,20 @@ msgstr "" msgid "" "As we can see, this error message is not very helpful, but it can be " "improved with a little work." -msgstr "" -"見ての通りこのエラーメッセージではあまり役に立ちませんが、少し工夫するだけで" -"改良できます。" +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) @@ -11695,9 +11650,7 @@ msgstr "" msgid "" "This time, if we modify the code to introduce a bug, we see our improved " "error message after the first failed test case:" -msgstr "" -"このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗" -"したときに改良されたエラーメッセージが表示されます。" +msgstr "このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗したときに改良されたエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter13.md:80 @@ -11751,9 +11704,7 @@ msgstr "" msgid "" "(Easy) Add an appropriate error message to the remaining property for " "`merge`." -msgstr "" -"(簡単)`merge`の残りの性質に対して、適切なエラーメッセージを追加してくださ" -"い。" +msgstr "(簡単)`merge`の残りの性質に対して、適切なエラー文言を追加してください。" #. type: Title ## #: text/chapter13.md:95 @@ -11783,9 +11734,7 @@ msgstr "mergePoly :: forall a. Ord a => Array a -> Array a -> Array a\n" msgid "" "If we modify our original test to use `mergePoly` in place of `merge`, we " "see the following error message:" -msgstr "" -"`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエ" -"ラーメッセージが表示されます。" +msgstr "`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter13.md:105 @@ -11808,21 +11757,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:115 #, fuzzy -#| 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 " -#| "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`:" 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 " "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" +"このような場合、型註釈を使ってコンパイラが特定の型を推論するように強制できます。\n" "例えば`Array Int`などです。" #. type: Fenced code block (haskell) @@ -11916,10 +11858,8 @@ msgid "" "appropriate error message. Your property should use a helper function to fix " "any polymorphic type arguments to either `Int` or `Boolean`." msgstr "" -"(普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエ" -"ラーメッセージを含めてQuickCheckの性質を書いてください。\n" -"その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定し" -"なければいけません。" +"(普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエラー文言を含めてQuickCheckの性質を書いてください。\n" +"その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定しなければいけません。" #. type: Title ## #: text/chapter13.md:142 @@ -12874,15 +12814,10 @@ msgstr "`spago test`を使ってQuickCheckのテストを自動化する方法 #. type: Bullet: '- ' #: text/chapter13.md:408 #, fuzzy -#| msgid "" -#| "We saw how to write properties as functions, and how to use the `` " -#| "operator to improve error messages." msgid "" "We saw how to write properties as functions and how to use the `` " "operator to improve error messages." -msgstr "" -"性質を関数として書く方法とエラーメッセージを改良する ``演算子の使い方を説" -"明しました。" +msgstr "性質を関数として書く方法とエラー文言を改良する ``演算子の使い方を説明しました。" #. type: Bullet: '- ' #: text/chapter13.md:408 @@ -16303,9 +16238,7 @@ msgstr "" msgid "" "In the second case, the PureScript compiler will try to parse _two_ " "declarations, one for each line." -msgstr "" -"後者では、PureScriptコンパイラはそれぞれの行ごとに1つ、つまり*2つ*の宣言であ" -"ると構文解析します。" +msgstr "後者では、PureScriptコンパイラはそれぞれの行毎に1つ、つまり*2つ*の宣言であると構文解析します。" #. type: Plain text #: text/chapter3.md:195 @@ -18089,9 +18022,7 @@ msgid "" "partial solutions." msgstr "" "再帰は*分割統治*戦略と密接な関係があります。\n" -"分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部" -"分に分割してそれぞれの部分について問題を解き、部分ごとの答えから最終的な答え" -"を組み立てるということです。" +"分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分毎の答えから最終的な答えを組み立てるということです。" #. type: Plain text #: text/chapter4.md:30 @@ -18536,10 +18467,8 @@ msgid "" "array from an existing array, keeping only those elements which match a " "predicate function." msgstr "" -"`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供" -"しています。\n" -"この関数は、述語関数に適合する要素のみを残し、既存の配列から新しい配列を作成" -"する機能を提供します。" +"`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供しています。\n" +"この関数は、述語関数に照合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。" #. type: Plain text #: text/chapter4.md:173 @@ -20022,64 +19951,40 @@ msgstr "パターン照合" #. type: Plain text #: text/chapter5.md:6 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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つの新しい概念を導入します。" -"また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱" -"います。" +"この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。\n" +"また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱います。" #. type: Plain text #: text/chapter5.md:8 -#, fuzzy -#| 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." 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." msgstr "" -"パターン照合は関数型プログラミングにおける一般的な手法で、複数の場合に実装を" -"分解することにより、開発者は水面下では複雑な動作をする関数を簡潔に書くことが" -"できます。" +"パターン照合は関数型プログラミングにおける一般的な手法であり、開発者が簡潔に関数を書けるようになります。\n" +"関数の実装を複数の場合に分解することにより、水面下の複雑なアイディアが表現されるのです。" #. type: Plain text #: text/chapter5.md:10 -#, fuzzy -#| 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." msgid "" "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の型システムの機能であり、型のある言語において同等" -"の水準の表現力を可能にしています。パターン照合とも密接に関連しています。" +"代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等の水準の表現力を可能にしています。\n" +"パターン照合とも密接に関連しています。" #. type: Plain text #: text/chapter5.md:12 -#, fuzzy -#| 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." msgid "" "The chapter's goal will be to write a library to describe and manipulate " "simple vector graphics using algebraic types and pattern matching." -msgstr "" -"この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラ" -"フィックスを描画し操作するためのライブラリを書くことです。" +msgstr "この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラフィックスを記述し操作するためのライブラリを書くことです。" #. type: Plain text #: text/chapter5.md:16 @@ -20091,18 +19996,13 @@ msgstr "" #. type: Plain text #: text/chapter5.md:18 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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 @@ -20136,30 +20036,23 @@ msgstr "{{#include ../exercises/chapter5/src/Data/Picture.purs:picture_import_as #. type: Plain text #: text/chapter5.md:32 -#, fuzzy -#| 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." 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 clarify which modules certain things are " "imported from." msgstr "" -"こうすると型や関数をモジュール内で使用できるようになりますが、`Number.max`の" -"ように*修飾名*を使ったときに限定されます。重複したインポートを避けたり、どの" -"モジュールからインポートされたのかを明らかにするのに役立ちます。" +"こうすると型や関数をモジュール内で使用できるようになりますが、\n" +"`Number.max`のように*修飾名*を使ったときに限定されます。\n" +"重複したインポートを避けたり、どのモジュールからインポートされたのかを明らかにするのに役立ちます。" #. type: Plain text #: text/chapter5.md:34 -#, fuzzy, 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." +#, 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 @@ -20169,17 +20062,12 @@ msgstr "単純なパターン照合" #. type: Plain text #: text/chapter5.md:38 -#, fuzzy -#| msgid "" -#| "Let's begin by looking at an example. Here is a function which computes " -#| "the greatest common divisor of two integers using pattern matching:" msgid "" "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" -"パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになりま" -"す。" +"例を見ることから始めましょう。\n" +"パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになります。" #. type: Fenced code block (haskell) #: text/chapter5.md:39 @@ -20189,14 +20077,6 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcd}}\n" #. type: Plain text #: text/chapter5.md:44 -#, fuzzy -#| 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." msgid "" "This algorithm is called the Euclidean Algorithm. If you search for its " "definition online, you will likely find a set of mathematical equations that " @@ -20205,23 +20085,11 @@ msgid "" "like a mathematical function specification." msgstr "" "このアルゴリズムはユークリッドの互除法と呼ばれています。\n" -"その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が" -"見つかるでしょう。\n" -"パターン照合の利点の1つは、上記のようにコードを場合分けして定義でき、数学関数" -"の定義と似たような簡潔で宣言型なコードを書くことができることです。" +"その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が見つかるでしょう。\n" +"パターン照合の利点の1つは、コードを場合分けして定義でき、数学関数の仕様に似た単純で宣言型なコードを定義できることです。" #. type: Plain text #: text/chapter5.md:46 -#, fuzzy -#| 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 " -#| "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 " -#| "match their inputs determines the return value." msgid "" "A function written using pattern matching works by pairing sets of " "conditions with their results. Each line is called an _alternative_ or a " @@ -20232,15 +20100,11 @@ msgid "" "returned. Each case is tried in order, and the first case whose patterns " "match their inputs determines the return value." msgstr "" -"パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作しま" -"す。\n" +"パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作します。\n" "この定義の各行は*選択肢*や*場合*と呼ばれています。\n" -"等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ" -"以上のパターンで構成されています。\n" -"場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなけれ" -"ばならない条件を表現しています。\n" -"それぞれの場合は上からこの順番に試されていき、最初に入力に適合した場合が返り" -"値を決定します。" +"等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ以上のパターンで構成されています。\n" +"場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなければならない条件を表現しています。\n" +"それぞれの場合は上からこの順番に試されていき、最初にパターンが入力に照合した場合が返り値を決定します。" #. type: Plain text #: text/chapter5.md:48 @@ -20274,7 +20138,6 @@ msgstr "それ以外の場合、関数は最後の行の式を評価して返し #. type: Plain text #: text/chapter5.md:54 -#, fuzzy msgid "" "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 " @@ -20301,7 +20164,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 @@ -20315,32 +20178,21 @@ msgstr "単純なパターンには他にも種類があります。" #. type: Bullet: '- ' #: text/chapter5.md:66 -#, fuzzy -#| 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 -#, fuzzy -#| msgid "" -#| "Wildcard patterns, indicated with an underscore (`_`), which match any " -#| "argument, and which do not bind any names." msgid "" "Wildcard patterns, indicated with an underscore (`_`), match any argument " "and do not bind any names." -msgstr "" -"どんな引数とも適合するが名前に束縛はしない、アンダースコア (`_`) で表されるワ" -"イルドカードパターン" +msgstr "どんな引数とも照合するが名前に束縛はしない、アンダースコア (`_`) で表されるワイルドカードパターン" #. type: Plain text #: text/chapter5.md:68 -#, fuzzy -#| 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 "ここではこれらの単純なパターンを使用して、もう2つ例を示します。" +msgstr "これらの単純なパターンを使用する実演として、もう2つの例が以下です。" #. type: Fenced code block (haskell) #: text/chapter5.md:69 @@ -20361,25 +20213,21 @@ msgstr "PSCiでこれらの関数を試してみてください。" #. type: Plain text #: text/chapter5.md:80 -#, fuzzy, 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" +#, 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" +msgstr "" +"ユークリッドの互除法の例では、`m > n`のときと`m <= n`のときの2つの選択肢の間を切り替えるために`if .. then .. else`式を使いました。\n" +"こういうときには*ガード*を使うという他の選択肢もあります。\n" #. type: Plain text #: text/chapter5.md:82 -#, fuzzy -#| 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 rewritten to use a guard:" msgid "" "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 @@ -20389,21 +20237,15 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:gcdV2}}\n" #. type: Plain text #: text/chapter5.md:88 -#, fuzzy -#| 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`:" 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`:" msgstr "" -"この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいと" -"いう条件を付け加えています。最後の行でのガードは式`otherwise`を使っており、" -"キーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。" +"この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を課しています。\n" +"最後の行でのガードは式`otherwise`を使っています。\n" +"これはキーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。" #. type: Fenced code block (text) #: text/chapter5.md:89 @@ -20423,10 +20265,6 @@ msgstr "" #. type: Plain text #: text/chapter5.md:98 -#, fuzzy -#| msgid "" -#| "As this example demonstrates, guards appear on the left of the equals " -#| "symbol, separated from the list of patterns by a pipe character (`|`)." msgid "" "This example demonstrates that guards appear on the left of the equals " "symbol, separated from the list of patterns by a pipe character (`|`)." @@ -20504,16 +20342,10 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}}\n" #. type: Plain text #: text/chapter5.md:114 -#, fuzzy -#| msgid "" -#| "Here is another function which matches arrays of length five, binding " -#| "each of its five elements in a different way:" msgid "" "Here is another function that matches arrays of length five, binding each of " "its five elements differently:" -msgstr "" -"次の関数では、長さ5の配列と適合し、配列の5つの要素をそれぞれ違った方法で束縛" -"しています。" +msgstr "次の関数では、長さ5の配列と照合し、配列の5つの要素をそれぞれ違った方法で束縛しています。" #. type: Fenced code block (haskell) #: text/chapter5.md:115 @@ -20523,20 +20355,13 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:takeFive}}\n" #. type: Plain text #: text/chapter5.md:120 -#, fuzzy -#| 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:" 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:" msgstr "" -"最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にの" -"み適合します。\n" +"最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にのみ照合します。\n" "その場合、関数は第3要素と第4要素の積を返します。\n" "それ以外の場合は、関数は0を返します。\n" "例えばPSCiで試してみると次のようになります。" @@ -20575,15 +20400,6 @@ msgstr "" #. type: Plain text #: text/chapter5.md:138 -#, fuzzy -#| msgid "" -#| "Array literal patterns allow us to match arrays of a fixed length, but " -#| "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 structures exist which provide improved asymptotic " -#| "performance for different operations." msgid "" "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 " @@ -20593,12 +20409,10 @@ msgid "" "structures exist which provide improved asymptotic performance for different " "operations." msgstr "" -"配列の直値パターンでは、固定長の配列と一致させることはできますが、PureScript" -"は不特定の長さの配列を照合させる手段を提供していません。\n" -"そのような方法で不変な配列を分解すると、実行速度が低下する可能性があるためで" -"す。\n" -"このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めし" -"ます。\n" +"配列の直値パターンでは、固定長の配列と一致させることはできます。\n" +"しかしPureScriptは不特定の長さの配列を照合させる手段は全く提供して*いません*。\n" +"そのような類の方法で不変な配列を分解すると、実行速度が低下する可能性があるためです。\n" +"このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めします。\n" "その他の操作について、より優れた漸近性能を提供するデータ構造も存在します。" #. type: Title ## @@ -20609,8 +20423,6 @@ msgstr "レコードパターンと行多相" #. type: Plain text #: text/chapter5.md:142 -#, fuzzy -#| msgid "_Record patterns_ are used to match - you guessed it - records." msgid "_Record patterns_ are used to match – you guessed it – records." msgstr "*レコードパターン*は(ご想像の通り)レコードに照合します。" @@ -20625,19 +20437,11 @@ msgstr "" #. type: Plain text #: text/chapter5.md:146 -#, fuzzy -#| 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` " -#| "respectively:" 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`, " "respectively:" -msgstr "" -"例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレ" -"コードに照合し、これらのフィールドの値はそれぞれ `x`と `y`という名前に束縛さ" -"れます。" +msgstr "例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレコードに照合し、これらのフィールドの値はそれぞれ `x`と `y`という名前に束縛されます。" #. type: Fenced code block (haskell) #: text/chapter5.md:147 @@ -20700,23 +20504,15 @@ msgstr "" #. type: Plain text #: text/chapter5.md:171 -#, fuzzy -#| 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:" msgid "" "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`の呼び出しは _不正_ となります。" +"レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま動作するのです。\n" +"レコードに少なくとも型が`String`であるようなフィールド`first`と`last`が含まれていれば、関数適用は正しく型付けされます。\n" +"しかし、フィールドが*不足*していると、`showPerson`の呼び出しは*不正*となります。" #. type: Fenced code block (text) #: text/chapter5.md:172 @@ -20760,10 +20556,8 @@ msgstr "> showPerson p = p.last <> \", \" <> p.first\n" #. type: Plain text #: text/chapter5.md:187 -#, fuzzy -#| msgid "and PSCi would have inferred the same type." msgid "And PSCi would have inferred the same type." -msgstr "この場合も、 PSCiは先ほどと同じ型を推論するでしょう。" +msgstr "そしてPSCiは同じ型を推論することでしょう。" #. type: Title ## #: text/chapter5.md:188 @@ -20773,21 +20567,14 @@ msgstr "レコード同名利用" #. type: Plain text #: text/chapter5.md:191 -#, fuzzy -#| 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:" 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 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 @@ -20823,10 +20610,8 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:unknownPerson} #. type: Plain text #: text/chapter5.md:205 -#, fuzzy -#| msgid "This may improve readability of code in some circumstances." msgid "This may improve the readability of code in some circumstances." -msgstr "こうすると、状況によってはコードの可読性向上に役立ちます。" +msgstr "こうすると、状況によってはコードの可読性が向上します。" #. type: Title ## #: text/chapter5.md:206 @@ -20836,14 +20621,6 @@ msgstr "入れ子になったパターン" #. type: Plain text #: text/chapter5.md:209 -#, fuzzy -#| 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." 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 " @@ -20851,12 +20628,10 @@ msgid "" "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 @@ -20902,14 +20677,13 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:sortPair}}\n" #. type: Plain text #: text/chapter5.md:227 -#, fuzzy 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 returns it unchanged, even if it's unsorted." msgstr "" "このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。\n" -"なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返しています。" +"なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返します。" #. type: Bullet: '1. ' #: text/chapter5.md:233 @@ -20922,11 +20696,6 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:233 -#, fuzzy -#| msgid "" -#| "(Medium) What is the most general type of the `sameCity` function, taking " -#| "into account row polymorphism? What about the `livesInLA` function " -#| "defined above? _Note_: There is no test for this exercise." msgid "" "(Medium) What is the most general type of the `sameCity` function, " "considering row polymorphism? What about the `livesInLA` function defined " @@ -20938,22 +20707,15 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:233 -#, fuzzy -#| 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 function should have type `forall a. a -> Array a -> a`" msgid "" "(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`という型を" -"持っています。" +"(普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数`fromSingleton`を書いてみましょう。\n" +"1要素だけを持つ配列でない場合、関数は与えられた既定値を返します。\n" +"この関数は`forall a. a -> Array a -> a`という型を持ちます。" #. type: Title ## #: text/chapter5.md:234 @@ -20963,14 +20725,6 @@ msgstr "Case式" #. type: Plain text #: text/chapter5.md:237 -#, fuzzy -#| 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, 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." 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 " @@ -20979,18 +20733,13 @@ msgid "" "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 -#, fuzzy -#| msgid "" -#| "Here is an example. This function computes \"longest zero suffix\" of an " -#| "array (the longest suffix which sums to zero):" msgid "" "Here is an example. This function computes the \"longest zero suffix\" of an " "array (the longest suffix which sums to zero):" @@ -21029,23 +20778,17 @@ msgstr "" #. type: Plain text #: text/chapter5.md:257 -#, fuzzy -#| 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." 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 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 @@ -21055,19 +20798,12 @@ msgstr "パターン照合の失敗と部分関数" #. type: Plain text #: text/chapter5.md:261 -#, fuzzy -#| 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_." msgid "" "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 @@ -21089,19 +20825,14 @@ msgstr "" #. type: Plain text #: text/chapter5.md:271 -#, fuzzy -#| 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 " -#| "argument, we will see an error at runtime:" 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 " "argument, we will see an error at runtime:" msgstr "" -"この関数は単一の場合しか含んでおらず、単一の入力である`true`にのみ照合しま" -"す。このファイルをコンパイルしてPSCiでそれ以外の値を与えてテストすると、実行" -"時エラーが発生します。" +"この関数は単一の場合しか含んでいません。\n" +"そしてその場合は単一の入力である`true`にのみ照合します。\n" +"このファイルをコンパイルしてPSCiでそれ以外の値を与えて試すと実行時エラーが発生します。" #. type: Fenced code block (text) #: text/chapter5.md:272 @@ -21117,16 +20848,10 @@ msgstr "" #. type: Plain text #: text/chapter5.md:279 -#, fuzzy -#| msgid "" -#| "Functions which return a value for any combination of inputs are called " -#| "_total_ functions, and functions which do not are called _partial_." msgid "" "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) であると呼ばれます。" +msgstr "どんな入力の組み合わせに対しても値を返すような関数は*全関数*と呼ばれ、そうでない関数は*部分的*であると呼ばれます。" #. type: Plain text #: text/chapter5.md:281 @@ -21147,14 +20872,6 @@ msgstr "" #. type: Plain text #: text/chapter5.md:283 -#, fuzzy -#| 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 " -#| "`unsafePartial` function above, then the compiler would generate the " -#| "following error:" 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 " @@ -21163,12 +20880,9 @@ msgid "" "`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 @@ -21223,25 +20937,19 @@ msgstr "" #. type: Plain text #: text/chapter5.md:308 -#, fuzzy, 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" +#, no-wrap 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 "本書ではのちに`=>`記号を含むいろいろな型を見ることになります(これらは*型クラス*に関連しています)。しかし、今のところは、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。\n" +msgstr "" +"本書では以降、`=>`記号が絡む(*型クラス*に関連する)型をもっと見ていきます。\n" +"しかし現時点では、PureScriptは型システムを使って部分関数を把握していることと、安全な場合に型検証器に明示する必要があることを確認すれば充分です。\n" #. type: Plain text #: text/chapter5.md:310 -#, fuzzy -#| 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):" 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 " "a prior case would have matched):" -msgstr "" -"コンパイラは、定義されたパターンが _冗長_ であることを検出した場合(前の方に" -"定義されたパターンのみに一致する場合)でも警告を生成します。" +msgstr "コンパイラは、*冗長*な場合を検出したとき(つまり、その場合より前の方に定義された場合にのみ一致するとき)などにも警告を出します。" #. type: Fenced code block (haskell) #: text/chapter5.md:311 @@ -21276,10 +20984,11 @@ msgstr "" #. type: Plain text #: text/chapter5.md:327 -#, fuzzy, 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`." +#, 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`を使ってコンパイルします。" +msgstr "" +"> *補足*:PSCiは警告を表示しません。\n" +"> そのため、この例を再現するには、この関数をファイルとして保存し、`spago build`を使ってコンパイルします。\n" #. type: Title ## #: text/chapter5.md:328 @@ -21323,12 +21032,6 @@ msgstr "" #. type: Plain text #: text/chapter5.md:337 -#, fuzzy -#| 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." 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 " @@ -21336,26 +21039,18 @@ msgid "" "to add new operations without breaking modularity." msgstr "" "しかし、この方針は大きな欠点を1つ抱えています。\n" -"`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に" -"把握し、`Shape`インターフェースに定義する必要があるのです。\n" -"このため、モジュール性を壊さずに新しい操作を追加することが難しくなります。" +"`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に把握し、`Shape`インターフェースに定義する必要があるのです。\n" +"モジュール性を壊さずに新しい操作を追加することが難しくなります。" #. type: Plain text #: text/chapter5.md:339 -#, fuzzy -#| 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." msgid "" "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 @@ -21376,13 +21071,6 @@ msgstr "" #. type: Plain text #: text/chapter5.md:349 -#, fuzzy -#| 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 `Rectangle`, or a `Line`, or `Text`. There are no other " -#| "ways to construct a value of type `Shape`." msgid "" "This declaration defines `Shape` as a sum of different constructors, and for " "each constructor identifies the included data. A `Shape` is either a " @@ -21396,16 +21084,9 @@ msgstr "" "`Line`、 `Text`の何れかです。\n" "他に`Shape`型の値を構築する方法はありません。" +# 頭字語のADTの意味が分かるような註釈は必要です。 #. type: Plain text #: text/chapter5.md:351 -#, fuzzy -#| 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 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." 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." @@ -21414,11 +21095,10 @@ msgid "" "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 @@ -21450,7 +21130,6 @@ msgstr "" #. type: Plain text #: text/chapter5.md:361 -#, fuzzy 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 " @@ -21572,19 +21251,13 @@ msgid "" "into scope using two variable patterns, `c` and `r`. The other cases are " "similar." msgstr "" -"各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できま" -"す。\n" +"各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できます。\n" "`showShape`の最初の場合を考えてみましょう。\n" -"もし `Shape`が `Circle`構築子に適合した場合、2つの変数パターン `c`と `r`を" -"使って`Circle`の引数(中心と半径)がスコープに導入されます。その他の場合も同" -"様です。" +"もし `Shape`が `Circle`構築子に照合した場合、2つの変数パターン `c`と `r`を使って`Circle`の引数(中心と半径)がスコープに導入されます。\n" +"その他の場合も同様です。" #. type: Bullet: '1. ' #: text/chapter5.md:397 -#, fuzzy -#| msgid "" -#| "(Easy) Write a function `circleAtOrigin` which constructs a `Circle` (of " -#| "type `Shape`) centered at the origin with radius `10.0`." msgid "" "(Easy) Write a function `circleAtOrigin` which constructs a `Circle` (of " "type `Shape`) centered at the origin with a radius `10.0`." @@ -21595,16 +21268,10 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter5.md:397 -#, fuzzy -#| msgid "" -#| "(Medium) Write a function `doubleScaleAndCenter` which scales the size of " -#| "a `Shape` by a factor of `2.0` and centers it at the origin." msgid "" "(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`" -"を書いてみましょう。" +msgstr "(普通)原点を中心として`Shape`の大きさを`2.0`倍に拡大する関数`doubleScaleAndCenter`を書いてみましょう。" #. type: Bullet: '1. ' #: text/chapter5.md:397 @@ -21775,18 +21442,14 @@ msgstr "newtype CouldError err a = CouldError (Either err a)\n" #. type: Plain text #: text/chapter5.md:456 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 @@ -21796,15 +21459,6 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:Coulomb}}\n" #. type: Plain text #: text/chapter5.md:462 -#, fuzzy -#| msgid "" -#| "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." msgid "" "In this case, `Coulomb` is the _type constructor_ (of zero arguments), and " "`MakeCoulomb` is the _data constructor_. These constructors live in " @@ -21814,11 +21468,11 @@ msgid "" "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 @@ -21874,12 +21528,10 @@ msgstr "" #. type: Plain text #: text/chapter5.md:480 -#, fuzzy -#| 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 @@ -22039,28 +21691,23 @@ msgstr "" #. type: Plain text #: text/chapter5.md:534 -#, fuzzy 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 " "types with new operations." msgstr "" -"また、この章ではパターン照合に密接に関連する代数的データ型を紹介しました。\n" -"代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上でモジュール性のある方法が齎されることを見てきました。" +"また、この章ではパターン照合に密接に関連する代数的データ型も紹介しました。\n" +"代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上で、モジュール性のある方法が齎されるのでした。" #. type: Plain text #: text/chapter5.md:536 -#, fuzzy -#| msgid "" -#| "Finally, we covered _row polymorphism_, a powerful type of abstraction " -#| "which allows many idiomatic JavaScript functions to be given a type." msgid "" "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 @@ -22397,9 +22044,7 @@ msgstr "" msgid "" "If we try to show a value of type `Data.Either`, we get an interesting error " "message:" -msgstr "" -"型 `Data.Either`の値を表示しようとすると、興味深いエラーメッセージが表示され" -"ます。" +msgstr "型 `Data.Either`の値を表示しようとすると、興味深いエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter6.md:97 @@ -22426,18 +22071,13 @@ msgstr "" #. type: Plain text #: text/chapter6.md:109 #, fuzzy -#| 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." msgid "" "The problem here is not that there is no `Show` instance for the type we " "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`と表示されているのがそれです。" +"ここでの問題は `show`しようとしている型に対する `Show`インスタンスが存在しないということではなく、PSCiがこの型を推論できなかったということです。\n" +"このエラー文言で*未知の型*`a`と表示されているのがそれです。" #. type: Plain text #: text/chapter6.md:111 @@ -22469,7 +22109,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 @@ -23879,7 +23519,7 @@ msgstr "genericTail xs = map _.tail (uncons xs)\n" #. type: Plain text #: text/chapter6.md:505 msgid "This gives a somewhat confusing error message:" -msgstr "これはやや複雑なエラーメッセージを出力します。" +msgstr "これはやや複雑なエラー文言を出力します。" #. type: Fenced code block (text) #: text/chapter6.md:506 @@ -25877,9 +25517,7 @@ msgstr "" msgid "" "Now we can lift over `Either String`, providing an appropriate error message " "for each parameter:" -msgstr "" -"これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー" -"メッセージを提供できるようになります。" +msgstr "これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー文言を提供できるようになります。" #. type: Fenced code block (text) #: text/chapter7.md:282 @@ -25928,15 +25566,10 @@ msgstr "" #. type: Plain text #: text/chapter7.md:307 #, fuzzy -#| msgid "" -#| "Now our function takes three optional arguments using `Maybe`, and " -#| "returns either a `String` error message or a `String` result." msgid "" "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`の結果のどちらかを返します。" +msgstr "これでこの関数は`Maybe`の3つの省略可能な引数を取り、`String`のエラー文言か`String`の結果のどちらかを返します。" #. type: Plain text #: text/chapter7.md:309 @@ -25968,20 +25601,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:322 #, fuzzy -#| 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:" 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:" msgstr "" -"このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省" -"略されたフィールドのうち最初のものに対応するエラーメッセージが表示されま" -"す。\n" -"しかし、もし複数の入力が省略されているとき、最初のエラーしか見ることができま" -"せん。" +"このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラー文言が表示されます。\n" +"しかし、もし複数の入力が省略されているとき、最初のエラーしか見ることができません。" #. type: Fenced code block (text) #: text/chapter7.md:323 @@ -28753,15 +28379,6 @@ msgstr "配列やリストで表現される多値関数" #. type: Plain text #: text/chapter8.md:380 #, fuzzy -#| 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 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 is implemented at runtime." 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 " @@ -28773,14 +28390,10 @@ msgid "" "is implemented at runtime." msgstr "" "これらの区別はわかりにくいので注意してください。\n" -"エラーメッセージは例外の形でJavaScriptの式の副作用となることがあります。\n" -"その意味では例外はネイティブな副作用を表していて、 `Effect`を使用して表現でき" -"ます。\n" -"しかし、 `Either`を使用して実装されたエラーメッセージはJavaScriptランタイムの" -"副作用ではなく、 `Effect`を使うスタイルでエラーメッセージを実装するのは適切で" -"はありません。\n" -"そのため、ネイティブなのは作用自体というより、実行時にどのように実装されてい" -"るかです。" +"エラー文言は例外の形でJavaScriptの式の副作用となることがあります。\n" +"その意味では例外はネイティブな副作用を表していて、 `Effect`を使用して表現できます。\n" +"しかし、 `Either`を使用して実装されたエラー文言はJavaScript実行器の副作用ではなく、 `Effect`を使うスタイルでエラー文言を実装するのは適切ではありません。\n" +"そのため、ネイティブなのは作用自体というより、実行時にどのように実装されているかです。" #. type: Title ## #: text/chapter8.md:381 diff --git a/translation/terms.txt b/translation/terms.txt index 9dadae76..71c2c7dd 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -2,3 +2,5 @@ primitive type: 原始型 type synonym: 型同義語 optional: 省略可能な accumulator: 累算器。「累積」とされることもあるようです。 +pattern match: パターン照合 +JavaScript runtime: 実行器 From 0a387febb230b93bd0b5752311cc4f7bfb716682 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Sun, 30 Jul 2023 13:32:18 +0900 Subject: [PATCH 11/29] [ update ] chapter 6 translation * [ add ] term entry 'hash code' --- text-ja/chapter5.md | 8 +- text-ja/chapter9.md | 2 +- translation/ja.po | 627 ++++++++++-------------------------------- translation/terms.txt | 3 +- 4 files changed, 156 insertions(+), 484 deletions(-) diff --git a/text-ja/chapter5.md b/text-ja/chapter5.md index 2661bdb9..bcae3047 100644 --- a/text-ja/chapter5.md +++ b/text-ja/chapter5.md @@ -20,7 +20,7 @@ `Data.Picture`モジュールは簡単な図形を表すデータ型`Shape`やその図形の集合である型`Picture`を定義します。 また、これらの型を扱うための関数もあります。 -このモジュールでは、データ構造の畳込みを行う関数を提供する `Data.Foldable`モジュールもインポートします。 +このモジュールでは、データ構造を畳込む関数を提供する`Data.Foldable`モジュールもインポートします。 ```haskell {{#include ../exercises/chapter5/src/Data/Picture.purs:module_picture}} @@ -106,7 +106,7 @@ PSCiでこれらの関数を試してみてください。 この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を課しています。 最後の行でのガードは式`otherwise`を使っています。 -これはキーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。 +これはキーワードのようにも見えますが、実際はただの`Prelude`にある普通の束縛です。 ```text > :type otherwise @@ -129,7 +129,7 @@ true 数式\\( n! / k! (n - k)! \\)を使ってください。 ここで \\( ! \\) は前に書いた階乗関数です。 *手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。 - 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、もっと使用例を追加してみてください。 + 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、コーナーケースを更に追加してみてください。 1. (普通)[_パスカルの法則_](https://en.wikipedia.org/wiki/Pascal%27s_rule)を使って前の演習と同じ2項係数を計算する関数`pascal`を書いてください。 ## 配列パターン @@ -290,7 +290,7 @@ _厳密に_ `first`と`last`フィールドしかないレコードのみを受 1要素だけを持つ配列でない場合、関数は与えられた既定値を返します。 この関数は`forall a. a -> Array a -> a`という型を持ちます。 -## Case式 +## case式 パターンが現れるのは最上位にある関数宣言だけではありません。 `case`式を使う計算中の途中の値に対してパターン照合を使えます。 diff --git a/text-ja/chapter9.md b/text-ja/chapter9.md index 3eff1186..5fc817fd 100644 --- a/text-ja/chapter9.md +++ b/text-ja/chapter9.md @@ -294,5 +294,5 @@ $ cat c/a/a.txt In this chapter, we covered asynchronous effects and learned how to: - `aff`ライブラリを使って`Aff`モナド中で非同期コードを走らせる。 -- `affjax`ライブラリを使って非同期にHTTPリクエストを行う。 +- `affjax`ライブラリを使って非同期にHTTPリクエストする。 - `parallel`ライブラリを使って並列に非同期コードを走らせる。 diff --git a/translation/ja.po b/translation/ja.po index b68c4a44..aa854970 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-07-30 13:22+0900\n" +"PO-Revision-Date: 2023-08-04 12:11+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -1641,8 +1641,7 @@ 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 @@ -20009,9 +20008,7 @@ msgstr "" msgid "" "The module imports the `Data.Foldable` module, which provides functions for " "folding data structures:" -msgstr "" -"このモジュールでは、データ構造の畳込みを行う関数を提供する `Data.Foldable`モ" -"ジュールもインポートします。" +msgstr "このモジュールでは、データ構造を畳込む関数を提供する`Data.Foldable`モジュールもインポートします。" #. type: Fenced code block (haskell) #: text/chapter5.md:21 @@ -20245,7 +20242,7 @@ msgid "" msgstr "" "この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいという条件を課しています。\n" "最後の行でのガードは式`otherwise`を使っています。\n" -"これはキーワードのようにも見えますが、実際はただの`Prelude`にある通常の束縛です。" +"これはキーワードのようにも見えますが、実際はただの`Prelude`にある普通の束縛です。" #. type: Fenced code block (text) #: text/chapter5.md:89 @@ -20297,14 +20294,12 @@ msgid "" "cases. If it takes a long time to complete or crashes with an error about " "the call stack, try adding more corner cases." msgstr "" -"(普通)\\\\( (1 + x) ^ n \\\\)を多項式展開した式にある\\\\( x ^ k \\\\)の項" -"の係数を求める関数`binomial`を書いてください。\n" +"(普通)\\\\( (1 + x) ^ n \\\\)を多項式展開した式にある\\\\( x ^ k \\\\)の項の係数を求める関数`binomial`を書いてください。\n" "これは`n`要素の集合から`k`要素の部分集合を選ぶ方法の数と同じです。\n" "数式\\\\( n! / k! (n - k)! \\\\)を使ってください。\n" "ここで \\\\( ! \\\\) は前に書いた階乗関数です。\n" "*手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。\n" -"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、もっと使" -"用例を追加してみてください。" +"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、コーナーケースを更に追加してみてください。" #. type: Bullet: '1. ' #: text/chapter5.md:104 @@ -20721,7 +20716,7 @@ msgstr "" #: text/chapter5.md:234 #, no-wrap msgid "Case Expressions" -msgstr "Case式" +msgstr "case式" #. type: Plain text #: text/chapter5.md:237 @@ -21730,34 +21725,23 @@ msgstr "型クラス" #. type: Plain text #: text/chapter6.md:6 -#, fuzzy -#| msgid "" -#| "This chapter will introduce a powerful form of abstraction which is " -#| "enabled by PureScript's type system - type classes." msgid "" "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 -#, fuzzy -#| 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 complex data structures without having to think directly about " -#| "the structure of the data itself." msgid "" "This motivating example for this chapter will be a library for hashing data " "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 @@ -21813,8 +21797,6 @@ msgstr "`either`: 非交和を表す `Either`データ型が定義されてい #. type: Bullet: '- ' #: text/chapter6.md:24 -#, fuzzy -#| msgid "`strings`, which defines functions which operate on strings." msgid "`strings`, which defines functions that operate on strings." msgstr "`strings`: 文字列を操作する関数が定義されています。" @@ -21912,22 +21894,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:51 -#, fuzzy -#| msgid "" -#| "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_." msgid "" "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`という名前の型クラスのインスタンスを宣言します。 " -"PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインス" -"タンスに名前をつけます。このとき、 _`Boolean`型は `Show`型クラスに属している" -"_ といいます。" +"このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。\n" +"PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインスタンスに名前を付けられます。\n" +"このとき、`Boolean`型は*`Show`型クラスに属している*といいます。" #. type: Plain text #: text/chapter6.md:53 @@ -21995,13 +21970,6 @@ msgstr "" #. type: Plain text #: text/chapter6.md:82 -#, fuzzy -#| 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`." 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 " @@ -22009,11 +21977,10 @@ msgid "" "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 @@ -22070,27 +22037,20 @@ msgstr "" #. type: Plain text #: text/chapter6.md:109 -#, fuzzy msgid "" "The problem here is not that there is no `Show` instance for the type we " "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がこの型を推論できなかったということです。\n" -"このエラー文言で*未知の型*`a`と表示されているのがそれです。" +"これは推論された型で*未知の型*`a`とされていることが示しています。" #. type: Plain text #: text/chapter6.md:111 -#, fuzzy -#| msgid "" -#| "We can annotate the expression with a type, using the `::` operator, so " -#| "that PSCi can choose the correct type class instance:" msgid "" "We can annotate the expression with a type using the `::` operator, so that " "PSCi can choose the correct type class instance:" -msgstr "" -"`::`演算子を使って式に対して型注釈を加えると、PSCiが正しい型クラスインスタン" -"スを選ぶことができるようになります。" +msgstr "`::`演算子を使って式に註釈を付け、、PSCiが正しい型クラスインスタンスを選べるようにできます。" #. type: Fenced code block (text) #: text/chapter6.md:112 @@ -22205,16 +22165,13 @@ msgstr "Eq" #. type: Plain text #: text/chapter6.md:145 -#, fuzzy -#| msgid "" -#| "The `Eq` type class defines the `eq` function, which tests two values for " -#| "equality. The `==` operator is actually just an alias for `eq`." msgid "" "The `Eq` type class defines the `eq` function, which tests two values for " "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 @@ -22228,16 +22185,12 @@ msgstr "" #. type: Plain text #: text/chapter6.md:152 -#, fuzzy -#| 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." msgid "" "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 @@ -22268,10 +22221,12 @@ msgstr "Ord" #. type: Plain text #: text/chapter6.md:166 -#, fuzzy, 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" +#, no-wrap 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`型クラスは順序付け可能な型に対して2つの値を比較する `compare`関数を定義します。比較演算子 `<`、 `>`と、その仲間の厳密な大小比較ではない`<=`、 `>=`も、`compare`を使って定義されます。\n" +msgstr "" +"`Ord`型クラスは`compare`関数を定義します。\n" +"この関数は2つの値を比較するのに使えるもので、その値の型は順序付けに対応したものです。\n" +"比較演算子`<`、`>`と厳密な大小比較ではない`<=`、`>=`は`compare`を用いて定義されます。\n" #. type: Plain text #: text/chapter6.md:168 @@ -22298,36 +22253,27 @@ msgstr "" #. type: Plain text #: text/chapter6.md:177 -#, fuzzy -#| msgid "" -#| "The `compare` function compares two values, and returns an `Ordering`, " -#| "which has three alternatives:" msgid "" "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 -#, fuzzy -#| msgid "`LT` - if the first argument is less than the second." msgid "`LT` – if the first argument is less than the second." -msgstr "`LT`- 最初の引数が2番目の値より小さいとき" +msgstr "`LT`- 最初の引数が2番目の値より小さいとき。" #. type: Bullet: '- ' #: text/chapter6.md:181 -#, fuzzy -#| msgid "`EQ` - if the first argument is equal to the second." msgid "`EQ` – if the first argument is equal to the second." -msgstr "`EQ`- 最初の引数が2番目の値と等しい(または比較できない)とき" +msgstr "`EQ`- 最初の引数が2番目の値と等しいとき。" #. type: Bullet: '- ' #: text/chapter6.md:181 -#, fuzzy -#| msgid "`GT` - if the first argument is greater than the second." msgid "`GT` – if the first argument is greater than the second." -msgstr "`GT`- 最初の引数が2番目の値より大きいとき" +msgstr "`GT`- 最初の引数が2番目の値より大きいとき。" #. type: Plain text #: text/chapter6.md:183 @@ -22358,29 +22304,22 @@ msgstr "Field" #. type: Plain text #: text/chapter6.md:195 -#, fuzzy -#| msgid "" -#| "The `Field` type class identifies those types which support numeric " -#| "operators such as addition, subtraction, multiplication and division. It " -#| "is provided to abstract over those operators, so that they can be reused " -#| "where appropriate." msgid "" "The `Field` type class identifies those types which support numeric " "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 -#, fuzzy, 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." +#, 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 @@ -22390,15 +22329,6 @@ msgstr "class EuclideanRing a <= Field a\n" #. type: Plain text #: text/chapter6.md:203 -#, fuzzy -#| 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 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`." msgid "" "The `Field` type class is composed from several more general _superclasses_. " "This allows us to talk abstractly about types that support some but not all " @@ -22407,14 +22337,10 @@ msgid "" "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" -"そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタン" -"スですが、`Ring`や`Field`のインスタンスではありません。" +"`Field`型クラスは、幾つかのより抽象的な*上位クラス*が組み合わさってできています。\n" +"このため、`Field`の操作の全てを提供しているわけではないが、その一部を提供する型について抽象的に説明できます。\n" +"例えば、自然数の型は加算及び乗算については閉じていますが、減算については必ずしも閉じていません。\n" +"そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタンスですが、`Ring`や`Field`のインスタンスではありません。" #. type: Plain text #: text/chapter6.md:205 @@ -22461,17 +22387,12 @@ msgstr "" #. type: Plain text #: text/chapter6.md:216 -#, fuzzy -#| msgid "" -#| "Strings form a semigroup under regular string concatenation, and so do " -#| "arrays. Several other standard instances are provided by the `prelude` " -#| "package." msgid "" "Strings form a semigroup under regular string concatenation, and so do " "arrays. The `prelude` package provides several other standard instances." msgstr "" -"文字列は普通の文字列連結について半群をなし、同様に配列も半群をなします。その" -"他の標準的なインスタンスの幾つかは、 `prelude`パッケージで提供されています。" +"文字列は普通の文字列連結について半群をなし、配列も同様です。\n" +"その他の標準的なインスタンスは`prelude`パッケージで提供されています。" #. type: Plain text #: text/chapter6.md:218 @@ -22505,16 +22426,15 @@ msgstr "ここでも文字列や配列はモノイドの簡単な例になって #. type: Plain text #: text/chapter6.md:229 -#, fuzzy 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 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 @@ -22600,34 +22520,24 @@ msgstr "" #. type: Plain text #: text/chapter6.md:260 -#, fuzzy -#| 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." 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 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 -#, fuzzy, 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" +#, 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 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 @@ -22650,60 +22560,36 @@ msgstr "" #. type: Plain text #: text/chapter6.md:273 -#, fuzzy -#| 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 in an array of integers, we see that the results of " -#| "`show`ing each integer have been concatenated into a single `String`." 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 " "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 -#, fuzzy -#| msgid "" -#| "But arrays are not the only types which 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_." msgid "" "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 -#, fuzzy, no-wrap -#| msgid "Functor, and Type Class Laws" +#, no-wrap msgid "Functor and Type Class Laws" msgstr "関手と型クラス則" #. type: Plain text #: text/chapter6.md:279 -#, fuzzy -#| msgid "" -#| "The Prelude also defines a collection of type classes which enable a " -#| "functional style of programming with side-effects in PureScript: " -#| "`Functor`, `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:" msgid "" "The Prelude also defines a collection of type classes that enable a " "functional style of programming with side-effects in PureScript: `Functor`, " @@ -22711,10 +22597,10 @@ msgid "" "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 @@ -22814,12 +22700,13 @@ msgstr "" #. type: Plain text #: text/chapter6.md:312 -#, fuzzy 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 as mapping the " "composition of the two functions over the structure." -msgstr "第2の法則は _合成律_ (composition law) です。構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。" +msgstr "" +"第2の法則は*合成律*です。\n" +"構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。" #. type: Plain text #: text/chapter6.md:314 @@ -22969,20 +22856,14 @@ msgstr "型クラス制約" #. type: Plain text #: text/chapter6.md:348 -#, fuzzy -#| 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 equal, by using equality defined using an `Eq` type class instance." msgid "" "Types of functions can be constrained by using type classes. Here is an " "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 @@ -23104,10 +22985,12 @@ msgstr "" #. type: Plain text #: text/chapter6.md:388 -#, fuzzy, 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" +#, 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.\n" -msgstr "ここで、この関数には`Int -> Int`または`Number -> Number`と注釈を付けることが考えられますが、最も一般的な型が`Semiring`で動作するため、PSCiでは`Int`と `Number`の両方で関数を実行させることができます。\n" +msgstr "" +"ここで、この関数に`Int -> Int`または`Number -> Number`と註釈を付けることはできます。\n" +"しかし、PSCiでは最も一般的な型が`Semiring`で動作することが示されています。\n" +"こうすると`Int`と`Number`の両方で関数を使えます。\n" #. type: Title ## #: text/chapter6.md:389 @@ -23152,12 +23035,9 @@ msgstr "" #. type: Plain text #: text/chapter6.md:401 -#, fuzzy, 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" +#, no-wrap 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" +msgstr "型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置くことになります。\n" #. type: Fenced code block (haskell) #: text/chapter6.md:402 @@ -23208,12 +23088,11 @@ msgstr "" #. type: Plain text #: text/chapter6.md:420 -#, fuzzy, 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" +#, no-wrap 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:422 @@ -23231,10 +23110,6 @@ msgstr "(普通)`NonEmpty`に`Functor`インスタンスを書いてくだ #. type: Bullet: '1. ' #: text/chapter6.md:426 -#, fuzzy -#| 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:" msgid "" "(Medium) Given any type `a` with an instance of `Ord`, we can add a new " "\"infinite\" value that is greater than any other value:" @@ -23256,8 +23131,7 @@ msgstr "" #. type: Plain text #: text/chapter6.md:432 -#, fuzzy, no-wrap -#| msgid " Write an `Ord` instance for `Extended a` which reuses the `Ord` instance for `a`.\n" +#, no-wrap msgid " Write an `Ord` instance for `Extended a` that reuses the `Ord` instance for `a`.\n" msgstr " `a`への`Ord`インスタンスを再利用して、`Extended a`に`Ord`インスタンスを書いてください。\n" @@ -23272,19 +23146,11 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter6.md:436 -#, fuzzy -#| 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 includes an extra element at the front:" 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 that " "includes an extra element at the front:" -msgstr "" -"(難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持って" -"いる)ような型構築子 `f`が与えられたとき、追加の要素を先頭に含めるような新た" -"なコンテナ型を作ることができます。" +msgstr "(難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持っている)ような型構築子 `f`が与えられたとき、追加の要素を先頭に含める新たなコンテナ型を作れます。" #. type: Plain text #: text/chapter6.md:440 @@ -23323,10 +23189,6 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter6.md:449 -#, fuzzy -#| msgid "" -#| "(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function " -#| "which removes duplicate `Shape`s from an array using the `nubEq` function." msgid "" "(Medium) Write a `dedupShapes :: Array Shape -> Array Shape` function that " "removes duplicate `Shape`s from an array using the `nubEq` function." @@ -23345,26 +23207,19 @@ msgstr "" #. type: Title ## #: text/chapter6.md:452 -#, fuzzy, no-wrap -#| msgid "Multi Parameter Type Classes" +#, no-wrap msgid "Multi-Parameter Type Classes" msgstr "多変数型クラス" #. type: Plain text #: text/chapter6.md:455 -#, fuzzy -#| 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 " -#| "parameterized by _zero or more_ type arguments." 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 a type class can be " "parameterized by _zero or more_ type arguments." msgstr "" -"型クラスは必ずしも1つの型だけを型変数としてとるわけではありません。型変数が1" -"つだけなのが最も一般的ですが、実際には型クラスは*ゼロ個以上の*型変数を持つこ" -"とができます。" +"型クラスが引数として1つの型だけを取れるのかというと、そうではありません。\n" +"その場合がほとんどですが、型クラスは*ゼロ個以上の*型変数を持てます。" #. type: Plain text #: text/chapter6.md:457 @@ -23407,11 +23262,6 @@ msgstr "" #. type: Plain text #: text/chapter6.md:476 -#, fuzzy -#| msgid "" -#| "The `Stream` module defines a class `Stream` which identifies types which " -#| "look like streams of elements, where elements can be pulled from the " -#| "front of the stream using the `uncons` function." msgid "" "The `Stream` module defines a class `Stream` which identifies types that " "look like streams of elements, where elements can be pulled from the front " @@ -23445,7 +23295,6 @@ msgstr "" #. type: Plain text #: text/chapter6.md:482 -#, fuzzy msgid "" "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 " @@ -23493,22 +23342,14 @@ msgstr "関数従属性" #. type: Plain text #: text/chapter6.md:499 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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`関数をストリームに" -"書くことを考えてみましょう。" +"多変数型クラスは非常に便利ですが、紛らわしい型や型推論の問題にも繋がります。\n" +"単純な例として、上記で与えられた`Stream`クラスを使い、ストリームに対して汎用的な`tail`関数を書くことを考えてみましょう。" #. type: Fenced code block (haskell) #: text/chapter6.md:500 @@ -23589,20 +23430,13 @@ msgstr "" #. type: Plain text #: text/chapter6.md:531 -#, fuzzy -#| 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:" msgid "" "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:532 @@ -23647,16 +23481,10 @@ msgstr "" #. type: Plain text #: text/chapter6.md:550 -#, fuzzy -#| msgid "" -#| "Functional dependencies can be quite useful when using multi-parameter " -#| "type classes to design certain APIs." msgid "" "Functional dependencies can be useful when designing certain APIs using " "multi-parameter type classes." -msgstr "" -"多種の型のクラスを使用して何らかのAPIを設計する場合、関数従属性は非常に有用で" -"す。" +msgstr "多変数の型クラスを使用して何らかのAPIを設計する場合、関数従属性が便利なことがあります。" #. type: Title ## #: text/chapter6.md:551 @@ -23666,29 +23494,16 @@ msgstr "型変数のない型クラス" #. type: Plain text #: text/chapter6.md:554 -#, fuzzy -#| 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." msgid "" "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:556 -#, fuzzy -#| 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:" msgid "" "An important example is the `Partial` class we saw earlier when discussing " "partial functions. Take, for example, the functions `head` and `tail` " @@ -23696,10 +23511,10 @@ msgid "" "array without wrapping them in a `Maybe`, so they can fail if the array is " "empty:" msgstr "" -"重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあり" -"ます。`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょ" -"う。この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。なので配列" -"が空のときに失敗する可能性があります。" +"重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあります。\n" +"`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。\n" +"この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。\n" +"そのため配列が空のときに失敗する可能性があります。" #. type: Fenced code block (haskell) #: text/chapter6.md:557 @@ -23830,15 +23645,6 @@ msgstr "" #. type: Plain text #: text/chapter6.md:603 -#, fuzzy -#| 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 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." 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 " @@ -23849,26 +23655,13 @@ msgid "" "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:605 -#, fuzzy -#| 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 superclass relationship between `Eq` and " -#| "`Ord`." msgid "" "In general, it makes sense to define a superclass relationship when the laws " "for the subclass mention the superclass members. For example, for any pair " @@ -23878,62 +23671,40 @@ msgid "" "evaluates to `EQ`. This relationship on the level of laws justifies the " "superclass relationship between `Eq` and `Ord`." msgstr "" -"一般に、下位クラスの法則が上位クラスのメンバに言及しているとき、上位クラス関" -"係を定義するのは筋が通っています。\n" -"例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インス" -"タンスの下で同値であるなら、`compare`関数は `EQ`を返すはずだと見做すのは理に" -"適っています。\n" -"言い換えれば、`a == b`が真であるのはちょうど`compare a b`が`EQ`に評価されると" -"きなのです。\n" -"法則のレベルでのこの関係は`Eq`と`Ord`の間の上位クラス関係の正当性を示します。" +"一般に、下位クラスの法則が上位クラスの構成要素に言及しているとき、上位クラス関係を定義するのは筋が通っています。\n" +"例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インスタンスの下で同値であるなら、`compare`関数は`EQ`を返すはずだと推定するのは理に適っています。\n" +"言い換えれば、`a == b`が真であるのは`compare a b`が厳密に`EQ`に評価されるときなのです。\n" +"法則のレベルでのこの関係は、`Eq`と`Ord`の間の上位クラス関係の正当性を示します。" #. type: Plain text #: text/chapter6.md:607 -#, fuzzy -#| 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." msgid "" "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:611 -#, fuzzy -#| 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 function in PSCi using `unsafePartial`. _Hint_: Use the " -#| "`maximum` function from `Data.Foldable`." msgid "" "(Medium) Define a partial function `unsafeMaximum :: Partial => Array Int -> " "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`関数を" -"使います。" +"(普通)部分関数`unsafeMaximum :: Partial => Array Int -> Int`を定義してください。\n" +"この関数は空でない整数の配列の最大値を求めます。\n" +"`unsafePartial`を使ってPSCiで関数を試してください。\n" +"*手掛かり*:`Data.Foldable`の`maximum`関数を使います。" #. type: Bullet: '1. ' #: text/chapter6.md:613 -#, fuzzy -#| msgid "" -#| "(Medium) The `Action` class is a multi-parameter type class which defines " -#| "an action of one type on another:" msgid "" "(Medium) The `Action` class is a multi-parameter type class that defines an " "action of one type on another:" -msgstr "" -"(普通)次の `Action`クラスは、ある型の別の型での動作 (action) を定義する、多" -"変数型クラスです。" +msgstr "(普通)次の `Action`クラスは、ある型の別の型での動作を定義する、多変数型クラスです。" #. type: Plain text #: text/chapter6.md:617 @@ -23949,10 +23720,11 @@ msgstr "" #. type: Plain text #: text/chapter6.md:619 -#, fuzzy, 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" +#, no-wrap 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 " *動作*はモノイドな値を使って他の型の値を変更する方法を決めるやり方を記述する関数です。`Action`型クラスには2つの法則があります。\n" +msgstr "" +" *動作*とは、他の型の値を変更する方法を決めるために使われるモノイドな値を記述する関数です。\n" +" `Action`型クラスには2つの法則があります。\n" #. type: Bullet: ' - ' #: text/chapter6.md:622 @@ -24007,8 +23779,7 @@ msgstr "" #. type: Plain text #: text/chapter6.md:636 -#, fuzzy, no-wrap -#| msgid " Write an instance which implements this action:\n" +#, no-wrap msgid " Write an instance that implements this action:\n" msgstr " この動作を実装するインスタンスを書いてください。\n" @@ -24032,34 +23803,22 @@ msgstr "" msgid " Remember, your instance must satisfy the laws listed above.\n" msgstr " インスタンスが上で挙げた法則を見たさなくてはならないことを思い出してください。\n" +# FIXME: PureScriptではなくPurescriptになっています。 #. type: Bullet: '1. ' #: text/chapter6.md:645 -#, fuzzy -#| 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." msgid "" "(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" +"PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える必要があるでしょう。\n" "*補足*:テストでは4つの実装を押さえています。" #. type: Bullet: '1. ' #: text/chapter6.md:647 -#, fuzzy -#| msgid "" -#| "(Medium) Write an `Action` instance which repeats an input string some " -#| "number of times:" msgid "" "(Medium) Write an `Action` instance that repeats an input string some number " "of times:" @@ -24162,10 +23921,9 @@ msgstr "" #. type: Plain text #: text/chapter6.md:674 -#, fuzzy, no-wrap -#| msgid "Note that this library is for demonstration purposes only, and is not intended to provide a robust hashing mechanism." +#, no-wrap msgid "> Note that this library is for demonstration purposes only and is not intended to provide a robust hashing mechanism.\n" -msgstr "なお、このライブラリの説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は目的としていません。" +msgstr "> なお、このライブラリは説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は意図していません。\n" #. type: Plain text #: text/chapter6.md:676 @@ -24174,16 +23932,12 @@ msgstr "ハッシュ関数に期待される性質とはどのようなもので #. type: Bullet: '- ' #: text/chapter6.md:679 -#, fuzzy -#| msgid "" -#| "A hash function should be deterministic, and map equal values to equal " -#| "hash codes." msgid "" "A hash function should be deterministic and map equal values to equal hash " "codes." msgstr "" "ハッシュ関数は決定的でなくてはなりません。\n" -"つまり、同じ値には同じハッシュ値を対応させなければなりません。" +"つまり、同じ値は同じハッシュコードに写さなければなりません。" #. type: Bullet: '- ' #: text/chapter6.md:679 @@ -24196,22 +23950,15 @@ msgstr "" #. type: Plain text #: text/chapter6.md:681 -#, fuzzy -#| 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 " -#| "certainly would not be enforceable by PureScript's type system. However, " -#| "this should provide the intuition for the following type class:" 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 " "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:682 @@ -24256,21 +24003,14 @@ msgstr "" #. type: Plain text #: text/chapter6.md:699 -#, fuzzy -#| msgid "" -#| "Let's write a function which 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:" msgid "" "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) @@ -24281,13 +24021,6 @@ msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashEqual}}\n" #. type: Plain text #: text/chapter6.md:705 -#, fuzzy -#| 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." 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 " @@ -24302,12 +24035,6 @@ msgstr "" #. type: Plain text #: text/chapter6.md:707 -#, fuzzy -#| 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:" 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 " @@ -24315,8 +24042,8 @@ msgid "" msgstr "" "原始型の `Hashable`インスタンスを幾つか書いてみましょう。\n" "まずは整数のインスタンスです。\n" -"`HashCode`は実際には単なる梱包された整数なので、これは簡単です。\n" -"`hashCode`補助関数を使うことができます。" +"`HashCode`は実際には単なる梱包された整数なので、単純です。\n" +"`hashCode`補助関数を使えます。" #. type: Fenced code block (haskell) #: text/chapter6.md:708 @@ -24390,13 +24117,6 @@ msgstr "{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashString}}\n" #. type: Plain text #: text/chapter6.md:737 -#, fuzzy -#| 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 `Eq` but not equal identically." 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 " @@ -24404,25 +24124,13 @@ msgid "" "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`の意味では同じ値でも厳密に" -"は同じではない、というような型の値は存在しないので簡単です。" +"これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証明するにはどうしたらいいでしょうか。\n" +"同じ値が等しいハッシュコードを持っていることを確認する必要があります。\n" +"`Int`、`Char`、`String`、`Boolean`のような場合は単純です。\n" +"`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しないからです。" #. type: Plain text #: text/chapter6.md:739 -#, fuzzy -#| 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 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 must satisfy the law. Therefore, the two arrays " -#| "have equal hashes, and so the `Hashable (Array a)` obeys the type class " -#| "law as well." 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 " @@ -24434,15 +24142,11 @@ msgid "" "the `Hashable (Array a)` obeys the type class law as well." msgstr "" "もっと面白い型についてはどうでしょうか。\n" -"この場合、配列の長さに関する帰納を使うと、型クラスの法則を証明できます。\n" +"`Array`インスタンスの型クラスの法則を証明するにあたっては、配列の長さに関する帰納を使えます。\n" "長さゼロの唯一の配列は `[]`です。\n" -"配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じ" -"で配列の残りの部分が等しいとき、またその時に限り等しくなります。\n" -"この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし " -"`Hashable a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を" -"もつことがわかります。\n" -"したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型ク" -"ラス法則を満たしています。" +"配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じで配列の残りの部分が等しいとき、またその時に限り等しくなります。\n" +"この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし `Hashable a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を持つことがわかります。\n" +"したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型クラス法則に従います。" #. type: Plain text #: text/chapter6.md:741 @@ -24465,13 +24169,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter6.md:747 -#, fuzzy -#| msgid "" -#| "(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." msgid "" "(Medium) Write a function `arrayHasDuplicates`, which tests if an array has " "any duplicate elements based on both hash and value equality. First, check " @@ -24479,12 +24176,10 @@ msgid "" "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" -"まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対" -"が見付かったら`==`で値の同値性を確認してください。\n" -"*手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるで" -"しょう。" +"(普通)関数`arrayHasDuplicates`を書いてください。\n" +"この関数はハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうかを調べます。\n" +"まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対が見付かったら`==`で値の同値性を確認してください。\n" +"*手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるでしょう。" #. type: Bullet: ' 1. ' #: text/chapter6.md:747 @@ -24530,35 +24225,19 @@ msgstr "" #. type: Plain text #: text/chapter6.md:760 -#, fuzzy -#| 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, and defined our own library based on a type class for " -#| "computing hash codes." msgid "" "In this chapter, we've been introduced to _type classes_, a type-oriented " "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:761 -#, fuzzy -#| 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." msgid "" "This chapter also introduced type class laws, a technique for proving " "properties about code that uses type classes for abstraction. Type class " @@ -24567,10 +24246,9 @@ msgid "" "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" +"型クラス法則は*等式推論*と呼ばれるより大きな分野の一部です。\n" +"そちらではプログラミング言語の性質と型システムがプログラムを論理的に追究するために使われています。\n" "これは重要な考え方で、本書では今後あらゆる箇所で立ち返る話題となるでしょう。" #. type: Title ## @@ -25852,7 +25530,7 @@ msgid "" msgstr "" "(難しい)型`combineMaybe : forall a f. (Applicative f) => Maybe (f a) -> f (Maybe a)`\n" "を持つ関数`combineMaybe`を書いてください。\n" -"この関数は副作用をもつ省略可能な計算をとり、省略可能な結果をもつ副作用のある計算を返します。" +"この関数は副作用を持つ省略可能な計算をとり、省略可能な結果を持つ副作用のある計算を返します。" #. type: Plain text #: text/chapter7.md:390 @@ -28037,21 +27715,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:292 #, fuzzy -#| 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:" 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 that encoded their user profile:" msgstr "" -"しかし、モナドはアプリカティブ関手でできること以上を行うことができ、重要な違" -"いはdo記法の構文で強調されています。\n" -"利用者情報をエンコードしたXML文書から利用者の都市を検索する、`userCity`の例に" -"ついてもう一度考えてみましょう。" +"しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法の構文で強調されています。\n" +"利用者情報をエンコードしたXML文書から利用者の都市を検索する、`userCity`の例についてもう一度考えてみましょう。" #. type: Plain text #: text/chapter8.md:303 @@ -31435,7 +31106,7 @@ msgstr "`aff`ライブラリを使って`Aff`モナド中で非同期コード #. type: Bullet: '- ' #: text/chapter9.md:244 msgid "Make HTTP requests asynchronously with the `affjax` library." -msgstr "`affjax`ライブラリを使って非同期にHTTPリクエストを行う。" +msgstr "`affjax`ライブラリを使って非同期にHTTPリクエストする。" #. type: Bullet: '- ' #: text/chapter9.md:244 diff --git a/translation/terms.txt b/translation/terms.txt index 71c2c7dd..6519c1b1 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -1,6 +1,7 @@ primitive type: 原始型 type synonym: 型同義語 optional: 省略可能な -accumulator: 累算器。「累積」とされることもあるようです。 +accumulator: 累算器。一般には「累積」とされることもあるようです。 pattern match: パターン照合 JavaScript runtime: 実行器 +hash code: ハッシュコード。「ハッシュ値」とされていました。 From 29065c1e5acbf8f245c97467da85d7a05f06597f Mon Sep 17 00:00:00 2001 From: gemmaro Date: Sun, 6 Aug 2023 14:44:06 +0900 Subject: [PATCH 12/29] [ update ] chapter 7 translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ change ] 'コンテキスト' -> '文脈' * [ change ] 'アクション' -> '動作' * [ change ] 'canvas' -> 'キャンバス' * [ change, wip ] 'それぞれ' -> '各' * [ change ] 'ストローク' -> '線描き' --- translation/ja.po | 1463 ++++++++++------------------------------- translation/terms.txt | 3 + 2 files changed, 340 insertions(+), 1126 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index aa854970..921b5afa 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-04 12:11+0900\n" +"PO-Revision-Date: 2023-08-06 23:23+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -164,10 +164,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" -"テストの最新の状態については[#79](https://github.com/purescript-contrib/" -"purescript-book/issues/79)を見てください。" +"各章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確かめることができます。\n" +"テストの最新の状態については[#79](https://github.com/purescript-contrib/purescript-book/issues/79)を見てください。" #. type: Title ## #: README.md:13 @@ -218,7 +216,7 @@ msgid "" "be introduced. Here are some examples of problems that will be solved in " "this book:" msgstr "" -"それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。\n" +"各章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。\n" "以下は本書で解いていく課題の幾つかの例です。" #. type: Bullet: '- ' @@ -854,7 +852,7 @@ msgid "" "is strongly recommended that you attempt the exercises in each chapter to " "fully understand the material." msgstr "" -"各章には演習が含まれており、それぞれ難易度も示されています。\n" +"各章には演習が含まれており、難易度も示されています。\n" "内容を完全に理解するために、各章の演習に取り組むことを強くお勧めします。" #. type: Plain text @@ -1691,12 +1689,6 @@ msgstr "カリー化されていない関数についての補足" #. type: Plain text #: text/chapter10.md:181 #, fuzzy -#| msgid "" -#| "PureScript's curried functions has 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 " -#| "code, it is sometimes necessary to define uncurried JavaScript functions " -#| "which accept multiple arguments." msgid "" "PureScript's curried functions have certain advantages. It allows us to " "partially apply functions, and to give type class instances for function " @@ -1704,10 +1696,10 @@ msgid "" "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 @@ -4205,9 +4197,7 @@ msgstr "" 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`を使って前置し、エラー文言" -"の質を向上させます。" +msgstr "仕上げとして、各`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向上させます。" #. type: Fenced code block (hs) #: text/chapter10.md:1042 @@ -4228,12 +4218,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1051 #, fuzzy -#| 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." msgid "" "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 " @@ -4242,22 +4226,13 @@ msgid "" "triggered. See if you can trigger each of them." msgstr "" "最初のエラーのみがこのアプリの通常の操作内で起こります。\n" -"他のエラーはWebブラウザの開発ツールを開いてローカルストレージ中に保存された" -"「person」文字列を編集し、そのページを参照することで引き起こせます。\n" -"どのようにJSON文字列を変更したかが、どのエラーの引き金になるかを決定しま" -"す。\n" -"それぞれのエラーを引き起こせるかどうかやってみてください。" +"他のエラーはWebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。\n" +"どのようにJSON文字列を変更したかが、どのエラーの引き金になるかを決定します。\n" +"各エラーを引き起こせるかどうかやってみてください。" #. type: Plain text #: text/chapter10.md:1053 #, fuzzy -#| 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." msgid "" "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 " @@ -4266,13 +4241,10 @@ msgid "" "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`は`window.alert`が定義された環境でのみ使うことができま" -"す。\n" +"次に`alert`動作を実装していきます。\n" +"この動作は`Effect.Console`モジュールの`log`動作によく似ています。\n" +"唯一の相違点は`alert`動作が`window.alert`メソッドを使うことで、対して`log`動作は`console.log`メソッドを使っています。\n" +"そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができます。\n" "例えばWebブラウザなどです。" #. type: Fenced code block (hs) @@ -4819,12 +4791,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1176 #, fuzzy -#| 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." msgid "" "We've already seen that PureScript's records evaluate to JavaScript objects. " "As for functions and arrays, we can reason about the runtime representation " @@ -4832,11 +4798,9 @@ msgid "" "labels. Of course, the fields of a record are not required to be of the same " "type." msgstr "" -"PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てき" -"ました。\n" -"ちょうど関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれ" -"ば、レコードのフィールドのデータの実行時の表現についても推論できます。\n" -"もちろん、レコードのそれぞれのフィールドは、同じ型である必要はありません。" +"PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てきました。\n" +"ちょうど関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールドのデータの実行時の表現についても推論できます。\n" +"勿論、レコードの各フィールドは、同じ型である必要はありません。" #. type: Title ### #: text/chapter10.md:1177 @@ -4847,21 +4811,14 @@ msgstr "ADTの表現" #. type: Plain text #: text/chapter10.md:1180 #, fuzzy -#| 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 " -#| "based on those prototypes." 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 that create new JavaScript objects " "based on those prototypes." msgstr "" -"PureScriptコンパイラは、代数的データ型の全ての構築子についてそれぞれを関数と" -"して定義し、新たなJavaScriptオブジェクト型を作成します。\n" -"これらの構築子は雛形に基づいて新しいJavaScriptオブジェクトを作成する関数に対" -"応しています。" +"代数的データ型の全ての構築子について、PureScriptコンパイラは関数を定義することで新たなJavaScriptオブジェクト型を作成します。\n" +"これらの構築子は雛形に基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。" #. type: Plain text #: text/chapter10.md:1182 @@ -4917,10 +4874,9 @@ msgid "" "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:1207 @@ -5896,11 +5852,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:109 #, fuzzy -#| 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 array, with a call to `modify` for each array element:" 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 " @@ -5908,10 +5859,8 @@ msgid "" "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:110 @@ -5955,20 +5904,14 @@ msgstr "" #. type: Plain text #: text/chapter11.md:128 #, fuzzy -#| 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`." msgid "" "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:130 @@ -6156,9 +6099,7 @@ 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`アクションは変更され" -"た設定で計算するために使います。" +msgstr "`ask`動作は現在の設定を読み取るために使い、`local`動作は変更された設定で計算するために使います。" #. type: Plain text #: text/chapter11.md:186 @@ -6216,9 +6157,7 @@ msgstr "" 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`オブジェクトを変更し、" -"ユーザーの権限を昇格させることもできます。" +msgstr "`local`動作を使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユーザーの権限を昇格させることもできます。" #. type: Fenced code block (haskell) #: text/chapter11.md:205 @@ -6466,7 +6405,7 @@ msgstr "tell :: forall w a. Monoid w => w -> Writer w Unit\n" msgid "" "The `tell` action appends the provided value to the current accumulated " "result." -msgstr "`tell`アクションは、与えられた値を現在の累算結果に付け加えます。" +msgstr "`tell`動作は与えられた値を現在の累算結果に付け加えます。" #. type: Plain text #: text/chapter11.md:292 @@ -6653,7 +6592,7 @@ msgstr " 数列が `1`に到達するまでに何回のコラッツ関数の #: 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:357 @@ -6664,19 +6603,13 @@ msgstr "モナド変換子" #. type: Plain text #: text/chapter11.md:360 #, fuzzy -#| msgid "" -#| "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." msgid "" "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." msgstr "" -"上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*" -"の例となっています。\n" -"対応するモナド変換子はそれぞれ `StateT`、 `ReaderT`、 `WriterT`と呼ばれていま" -"す。" +"上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*の例となっています。\n" +"対応する各モナド変換子は`StateT`、`ReaderT`、`WriterT`と呼ばれています。" #. type: Plain text #: text/chapter11.md:362 @@ -6708,19 +6641,13 @@ msgstr "" #. type: Plain text #: text/chapter11.md:364 #, fuzzy -#| 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." msgid "" "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:366 @@ -6857,13 +6784,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:403 #, fuzzy -#| 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:" msgid "" "We can use the actions of the outer `StateT String` monad (`get`, `put`, and " "`modify`) directly, but to use the effects of the wrapped monad (`Either " @@ -6871,12 +6791,8 @@ msgid "" "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 (Either String)`モナドの動作(`get`、`put`、`modify`)は直接使えますが、梱包されている内側のモナド (`Either String`) の作用を使うためには、これらの関数をモナド変換子まで「持ち上げ」なくてはいけません。\n" +"`Control.MonadTrans`モジュールでは、モナド変換子であるような型構築子を捉える`MonadTrans`型クラスを次のように定義しています。" #. type: Fenced code block (haskell) #: text/chapter11.md:404 @@ -6891,15 +6807,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:410 #, fuzzy -#| 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 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`." 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 " @@ -6910,13 +6817,9 @@ msgid "" "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`を一緒に使うことができることを意味します。" +"このクラスは、基礎となる任意のモナド `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`を一緒に使うことができることを意味します。" #. type: Plain text #: text/chapter11.md:412 @@ -7028,13 +6931,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:446 #, fuzzy -#| 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." 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` " @@ -7042,11 +6938,10 @@ msgid "" "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:447 @@ -7092,13 +6987,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:462 #, fuzzy -#| 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`." msgid "" "The `MonadError` class captures those monads that support throwing and " "catching errors of some type `e`, and an instance is provided for the " @@ -7106,12 +6994,9 @@ msgid "" "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:464 @@ -7157,9 +7042,8 @@ msgid "" "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:472 @@ -7550,9 +7434,7 @@ msgstr "型クラスが助けに来たぞっ" 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`モナドのアクションには" -"次のような型が与えられていました。" +msgstr "本章の最初で扱った `State`モナドを見てみると、 `State`モナドの動作には次のような型が与えられていました。" #. type: Fenced code block (haskell) #: text/chapter11.md:575 @@ -7635,31 +7517,19 @@ msgstr "" #. type: Plain text #: text/chapter11.md:594 #, fuzzy -#| 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." 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 that " "support their operations." msgstr "" -"当然ですが、これまで扱ってきた `ReaderT`、 `WriterT`、 `ExceptT`変換子につい" -"ても、同じことが成り立っています。`transformers`では主な変換子それぞれについ" -"ての型クラスが定義されています。これによりそれらの操作に対応するモナドの上に" -"抽象化できるのです。" +"当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが成り立っています。\n" +"`transformers`では主な変換子について各々型クラスが定義されています。\n" +"これによりそれらの操作に対応するモナドの上に抽象化できるのです。" #. type: Plain text #: text/chapter11.md:596 #, fuzzy -#| 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 defined on the monad stack itself:" 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` " @@ -7667,11 +7537,9 @@ msgid "" "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" +"上の`split`関数の場合、構築されたこのモナドスタックは各型クラス`MonadState`、`MonadWriter`、`MonadError`のインスタンスです。\n" "これはつまり、`lift`は全く呼び出す必要がないのです。\n" -"まるでモナドスタック自体に定義されていたかのように、アクション `get`、" -"`put`、 `tell`、 `throwError`をそのまま使用できます。" +"まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、`tell`、`throwError`をそのまま使用できます。" #. type: Fenced code block (haskell) #: text/chapter11.md:597 @@ -8300,9 +8168,7 @@ msgstr "" msgid "" "We will see how the `Map` and `Set` structures are used as we write the " "actions for our game." -msgstr "" -"ゲームのアクションを書く上で`Map`と `Set`構造をどのように使っていくのかを見て" -"いきます。" +msgstr "ゲームの動作を書く上で`Map`と`Set`構造をどのように使っていくのかを見ていきます。" #. type: Plain text #: text/chapter11.md:773 @@ -8328,13 +8194,6 @@ msgstr "ゲームロジックの実装" #. type: Plain text #: text/chapter11.md:781 #, fuzzy -#| 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." msgid "" "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 " @@ -8342,12 +8201,8 @@ msgid "" "`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" -"このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モ" -"ナドはコンソールにテキストを出力するような観測可能な副作用へと結果を変換する" -"ために使っています。" +"今回は`Reader`モナドと`Writer`モナドと`State`モナドの動作を再利用し、`Game`モナドで定義されている単純な動作を組み合わせてゲームを構築していきます。\n" +"このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドはコンソールにテキストを出力するような観測可能な副作用へと結果を変換するために使っています。" #. type: Plain text #: text/chapter11.md:783 @@ -8356,9 +8211,9 @@ msgid "" "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:784 @@ -8369,21 +8224,14 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:has}}\n" #. type: Plain text #: text/chapter11.md:789 #, fuzzy -#| 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 in `Data.Set` to test whether the specified `GameItem` appears in " -#| "the `Set` of inventory items." 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 " "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:791 @@ -8393,10 +8241,9 @@ msgid "" "`MonadWriter` and `MonadState` type classes. First of all, it reads the " "current game state:" msgstr "" -"他にも `pickUp`アクションがあります。\n" -"現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加" -"します。\n" -"これには`MonadWriter`と `MonadState`型クラスのアクションを使っています。\n" +"他にも`pickUp`動作があります。\n" +"現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加します。\n" +"これには`MonadWriter`と`MonadState`型クラスの動作を使っています。\n" "一番最初に現在のゲームの状態を読み取ります。" #. type: Fenced code block (haskell) @@ -8543,21 +8390,14 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:debug}}\n" #. type: Plain text #: text/chapter11.md:833 #, fuzzy -#| 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 same do notation block." 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 " "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:835 @@ -8566,24 +8406,17 @@ msgid "" "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:837 #, fuzzy -#| msgid "" -#| "The remainder of the `Game` module defines a set of similar actions, each " -#| "using only the actions defined by the `MonadState`, `MonadReader` and " -#| "`MonadWriter` type classes." msgid "" "The remainder of the `Game` module defines a set of similar actions, each " "using only the actions defined by the `MonadState`, `MonadReader`, and " "`MonadWriter` type classes." -msgstr "" -"`Game.purs`モジュールの残りの部分では、`MonadState`型クラスと`MonadReader`型" -"クラスと`MonadWriter`型クラスでそれぞれ定義されたアクションだけを使い、同様の" -"アクションが定義されています。" +msgstr "`Game.purs`モジュールの残りの部分では、`MonadState`型クラスと`MonadReader`型クラスと`MonadWriter`型クラスでそれぞれ定義された動作だけを使い、同様の動作が定義されています。" #. type: Title ## #: text/chapter11.md:838 @@ -8661,21 +8494,14 @@ msgstr "" #. type: Plain text #: text/chapter11.md:859 #, fuzzy -#| msgid "" -#| "`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 " -#| "the final state." msgid "" "`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 " "the final state." msgstr "" -"`runRWS`は `runReader`、 `runWriter`、 `runState`を組み合わせたように見えま" -"す。\n" -"これは、引数として大域的な設定及び初期状態をとり、ログ、結果、最的な終状態を" -"含むデータ構造を返します。" +"`runRWS`は `runReader`、 `runWriter`、 `runState`を組み合わせたように見えます。\n" +"これは、引数として大域的な設定及び初期状態を取り、ログ、結果、最的な終状態を含むデータ構造を返します。" #. type: Plain text #: text/chapter11.md:861 @@ -8706,17 +8532,13 @@ msgstr "" #. type: Plain text #: text/chapter11.md:869 #, fuzzy -#| msgid "" -#| "The `node-readline` package provides the `LineHandler` type, which " -#| "represents actions in the `Effect` monad which handle user input from the " -#| "terminal. Here is the corresponding API:" msgid "" "The `node-readline` package provides the `LineHandler` type, which " "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) @@ -8826,10 +8648,8 @@ msgid "" "run the `game` action (in the `RWS` monad), passing the game environment and " "current game state." msgstr "" -"このアクションが最初に行うことは、 `Data.String`モジュールの `split`関数を使" -"用して、ユーザーの入力を単語に分割することです。\n" -"それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`" -"モナドで)`game`アクションを実行しています。" +"この動作が最初に行うことは、`Data.String`モジュールの `split`関数を使用して、ユーザーの入力を単語に分割することです。\n" +"それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`モナドで)`game`動作を実行しています。" #. type: Plain text #: text/chapter11.md:907 @@ -8842,8 +8662,8 @@ msgid "" "prompt is displayed again using the `prompt` action." msgstr "" "純粋な計算であるゲームロジックを実行するには、画面に全てのログ文言を出力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。\n" -"`for_`アクションが(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。\n" -"最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`アクションを使ってプロンプトを再び表示しています。" +"`for_`動作が(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。\n" +"最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`動作を使ってプロンプトを再び表示しています。" #. type: Plain text #: text/chapter11.md:909 @@ -9081,13 +8901,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:970 #, fuzzy -#| 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." msgid "" "We have seen how monad transformers allow us to write safe code in an " "imperative style, where the type system tracks effects. In addition, type " @@ -9096,14 +8909,11 @@ msgid "" "and `MonadPlus` to build useful monads by combining standard monad " "transformers." msgstr "" -"モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見" -"てきました。\n" +"モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見てきました。\n" "このスタイルでは型システムによって作用が追跡されています。\n" -"また、型クラスはモナドが提供するアクションへと抽象化する強力な方法を提供しま" -"す。\n" +"また、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供します。\n" "このモナドのお陰でコードの再利用が可能になりました。\n" -"標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のよ" -"うな標準的な抽象化を使用して、役に立つモナドを構築できました。" +"標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のような標準的な抽象化を使用して、役に立つモナドを構築できました。" #. type: Plain text #: text/chapter11.md:971 @@ -9159,11 +8969,8 @@ 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 @@ -9202,28 +9009,19 @@ msgid "" "with the Canvas API." msgstr "" "`Example/Rectangle.purs`ファイルには簡単な導入例が含まれています。\n" -"この例ではcanvasの中心に青い四角形を1つ描画します。\n" -"このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas APIを扱うた" -"めの`Effect`モナドのアクションを含む`Graphics.Canvas`モジュールをインポートし" -"ます。" +"この例ではキャンバスの中心に青い四角形を1つ描画します。\n" +"このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas APIを扱うための`Effect`モナドの動作を含む`Graphics.Canvas`モジュールをインポートします。" #. type: Plain text #: text/chapter12.md:23 #, fuzzy -#| msgid "" -#| "The `main` action starts, like in the other modules, by using the " -#| "`getCanvasElementById` action to get a reference to the canvas object, " -#| "and the `getContext2D` action to access the 2D rendering context for the " -#| "canvas:" msgid "" "The `main` action starts, like in the other modules, by using the " "`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`動作を使ってキャンバスオブジェクトへの参照を取得します。\n" +"また、`getContext2D`動作を使ってキャンバスの2D描画文脈を参照します。" #. type: Plain text #: text/chapter12.md:25 @@ -9262,7 +9060,7 @@ msgstr "" 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 @@ -9291,17 +9089,11 @@ msgstr "" #. type: Plain text #: text/chapter12.md:43 #, fuzzy -#| msgid "" -#| "The graphics context `ctx` manages the state of the canvas, and provides " -#| "methods to render primitive shapes, set styles and colors, and apply " -#| "transformations." msgid "" "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の状態を管理し、原始的な図形を描画した" -"り、スタイルや色を設定したり、座標変換を適用するためのメソッドを提供します。" +msgstr "グラフィックス文脈`ctx`はキャンバスの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用するためのメソッドを提供します。" #. type: Plain text #: text/chapter12.md:45 @@ -9310,10 +9102,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" -"より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がよ" -"り簡単です。" +"話を進めると、`setFillStyle`動作を使うことで塗り潰しスタイルを濃い青に設定できます。\n" +"より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がより簡単です。" #. type: Fenced code block (haskell) #: text/chapter12.md:46 @@ -9327,9 +9117,8 @@ 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 @@ -9337,7 +9126,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) @@ -9349,22 +9138,15 @@ msgstr "fillPath :: forall a. Context2D -> Effect a -> Effect a\n" #. type: Plain text #: text/chapter12.md:59 #, fuzzy -#| msgid "" -#| "`fillPath` takes a graphics context and another action which 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 rectangle:" msgid "" "`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 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 @@ -9392,9 +9174,7 @@ msgstr "$ spago bundle-app --main Example.Rectangle --to dist/Main.js\n" 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の中央に青" -"い四角形が描画されていることを確認してみましょう。" +msgstr "それでは `html/index.html`ファイルを開き、このコードによってキャンバスの中央に青い四角形が描画されていることを確認してみましょう。" #. type: Title ## #: text/chapter12.md:72 @@ -9520,22 +9300,16 @@ msgstr "" #. type: Plain text #: text/chapter12.md:106 #, fuzzy -#| 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 of the canvas:" 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 " "of the canvas:" msgstr "" -"例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰しま" -"す。\n" +"例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰します。\n" "弧は1回転のうち2/3ラジアン分あります。\n" "単位円が上下逆様になっている点に注意してください。\n" -"これはy軸がcanvasの下向きに伸びるためです。" +"これはy軸がキャンバスの下向きに伸びるためです。" #. type: Fenced code block (haskell) #: text/chapter12.md:107 @@ -9702,21 +9476,16 @@ 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 #, fuzzy -#| msgid "" -#| "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " -#| "each of the examples so far." msgid "" "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " "each example so far." -msgstr "" -"(簡単)これまでの例のそれぞれについて、 `strokePath`関数や`setStrokeStyle`関" -"数を使ってみましょう。" +msgstr "(簡単)これまでの各例について、`strokePath`関数や`setStrokeStyle`関数を使ってみましょう。" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 @@ -9805,12 +9574,11 @@ msgstr "" #. type: Plain text #: text/chapter12.md:179 #, fuzzy, 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 @@ -9827,34 +9595,23 @@ msgstr "無作為に円を描く" #. type: Plain text #: text/chapter12.md:185 #, fuzzy -#| 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." msgid "" "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`ファイルには2種類の異なる副作用が混在した`Effect`モナドを使う例が含まれています。\n" +"1つは乱数生成で、もう1つはキャンバスの操作です。\n" "この例では無作為に生成された円をキャンバスに100個描画します。" #. type: Plain text #: text/chapter12.md:187 #, fuzzy -#| msgid "" -#| "The `main` action obtains a reference to the graphics context as before, " -#| "and then sets the stroke and fill styles:" msgid "" "The `main` action obtains a reference to the graphics context as before and " "then sets the stroke and fill styles:" -msgstr "" -"`main`アクションではこれまでのようにグラフィックスコンテキストへの参照を取得" -"し、ストロークと塗り潰しスタイルを設定します。" +msgstr "`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗り潰しスタイルを設定します。" #. type: Fenced code block (haskell) #: text/chapter12.md:188 @@ -9867,9 +9624,7 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:style}}\n" msgid "" "Next, the code uses the `for_` function to loop over the integers between " "`0` and `100`:" -msgstr "" -"次のコードでは `for_`アクションを使って `0`から `100`までの整数について反復し" -"ています。" +msgstr "次のコードでは`for_`動作を使って`0`から`100`までの整数について反復しています。" #. type: Fenced code block (haskell) #: text/chapter12.md:194 @@ -9880,19 +9635,13 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:for}}\n" #. type: Plain text #: text/chapter12.md:199 #, fuzzy -#| 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:" 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:" msgstr "" -"それぞれの繰り返しでのdo記法ブロックは、`0`と`1`の間に分布する3つの乱数を生成" -"することから始まります。\n" -"これらの数は `0`から `1`の間に無作為に分布しており、それぞれ `x`座標、 `y`座" -"標、半径 `r`を表しています。" +"各繰り返しでのdo記法ブロックは、`0`と`1`の間に分布する3つの乱数を生成することから始まります。\n" +"これらの数は`0`から`1`の間に無作為に分布しており、それぞれ`x`座標、`y`座標、半径`r`を表しています。" #. type: Fenced code block (haskell) #: text/chapter12.md:200 @@ -9905,9 +9654,7 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:random}}\n" 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`を作成し、最" -"後に現在のスタイルに従って円弧を塗り潰し線描きします。" +msgstr "次のコードでは各円について、これらの変数に基づいて`Arc`を作成し、最後に現在のスタイルに従って円弧を塗り潰し線描きします。" #. type: Fenced code block (haskell) #: text/chapter12.md:206 @@ -10005,22 +9752,15 @@ msgstr "" msgid "" "The `translate` action performs a translation whose components are specified " "by the properties of the `TranslateTransform` record." -msgstr "" -"`translate`アクションは`TranslateTransform`レコードのプロパティで指定した大き" -"さだけ平行移動します。" +msgstr "`translate`動作は`TranslateTransform`レコードのプロパティで指定した大きさだけ平行移動します。" #. type: Plain text #: text/chapter12.md:245 #, fuzzy -#| msgid "" -#| "The `rotate` action performs a rotation around the origin, through some " -#| "number of radians specified by the first argument." msgid "" "The `rotate` action rotates around the origin through some number of radians " "specified by the first argument." -msgstr "" -"`rotate`アクションは最初の引数で指定されたラジアンの値に応じて、原点を中心と" -"して回転します。" +msgstr "`rotate`動作は最初の引数で指定されたラジアンの値に応じて、原点を中心として回転します。" #. type: Plain text #: text/chapter12.md:247 @@ -10029,9 +9769,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 @@ -10039,17 +9778,15 @@ 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 msgid "" "Any shapes rendered after these actions have been invoked will automatically " "have the appropriate transformation applied." -msgstr "" -"これらのアクションが呼び出された後に描画される図形は、自動的に適切な座標変換" -"が適用されます。" +msgstr "これらの動作が呼び出された後に描画される図形は、自動的に適切な座標変換が適用されます。" #. type: Plain text #: text/chapter12.md:253 @@ -10059,10 +9796,8 @@ msgid "" "if multiple transformations applied after one another, then their effects " "are actually applied in reverse:" msgstr "" -"実際には、これらの関数のそれぞれの作用は、コンテキストの現在の変換行列に対し" -"て変換行列を*右から乗算*していきます。\n" -"つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されてい" -"きます。" +"実際には、これらの関数の各作用は、文脈の現在の変換行列に対して変換行列を*右から乗算*していきます。\n" +"つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されていきます。" #. type: Fenced code block (haskell) #: text/chapter12.md:254 @@ -10087,15 +9822,13 @@ msgstr "" msgid "" "The effect of this sequence of actions is that the scene is rotated, then " "scaled, and finally translated." -msgstr "" -"この一連のアクションの作用では、まずシーンが回転され、それから拡大縮小され、" -"最後に平行移動されます。" +msgstr "この一連の動作の作用では、まずシーンが回転され、それから拡大縮小され、最後に平行移動されます。" #. type: Title ## #: text/chapter12.md:265 #, no-wrap msgid "Preserving the Context" -msgstr "コンテキストの保存" +msgstr "文脈の保存" #. type: Plain text #: text/chapter12.md:268 @@ -10147,20 +9880,11 @@ msgid "" "The `save` action pushes the current state of the context (including the " "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`アクションはスタックの一番上の状態をポップ" -"し、コンテキストの状態を復元します。" +msgstr "`save`動作は現在の文脈の状態(現在の変換行列や描画スタイル)をスタックにプッシュし、`restore`動作はスタックの一番上の状態をポップし、文脈の状態を復元します。" #. type: Plain text #: text/chapter12.md:284 #, fuzzy -#| 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 transformation afterwards:" msgid "" "This allows us to save the current state, apply some styles and " "transformations, render some primitives, and finally restore the original " @@ -10168,10 +9892,8 @@ msgid "" "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 @@ -10195,10 +9917,7 @@ msgid "" "In the interest of abstracting over common use cases using higher-order " "functions, the `canvas` library provides the `withContext` function, which " "performs some canvas action while preserving the original context state:" -msgstr "" -"こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元" -"のコンテキスト状態を保存しつつ幾つかのキャンバスアクションを実行する " -"`withContext`関数が提供されています。" +msgstr "こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元の文脈状態を保存しつつ幾つかのキャンバス動作を実行する`withContext`関数が提供されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:295 @@ -10305,15 +10024,10 @@ msgstr "" #. type: Plain text #: text/chapter12.md:329 #, fuzzy -#| msgid "" -#| "The code starts by creating a new reference containing the value `0`, by " -#| "using the `new` action:" msgid "" "The code starts by creating a new reference containing the value `0` by " "using the `new` action:" -msgstr "" -"このコードでは最初に`new`アクションを使って値`0`を含む新しい参照を作成してい" -"ます。" +msgstr "このコードでは最初に`new`動作を使って値`0`を含む新しい参照を作成しています。" #. type: Fenced code block (haskell) #: text/chapter12.md:330 @@ -10326,9 +10040,7 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Refs.purs:clickCount}}\n" msgid "" "Inside the click event handler, the `modify` action is used to update the " "click count, and the updated value is returned." -msgstr "" -"クリックイベント制御子の内部では、 `modify`アクションを使用してクリック数を更" -"新し、更新された値が返されています。" +msgstr "クリックイベント制御子の内部では、`modify`動作を使用してクリック数を更新し、更新された値が返されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:336 @@ -10352,18 +10064,11 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}}\n" #. type: Plain text #: text/chapter12.md:347 #, fuzzy -#| msgid "" -#| "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):" msgid "" "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`を使用しており、それ" -"から一連の変換を適用しています(変換が下から上に適用されることを思い出してく" -"ださい)。" +msgstr "この動作では元の変換を保存するために `withContext`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。" #. type: Bullet: '- ' #: text/chapter12.md:352 @@ -10391,13 +10096,10 @@ msgstr "矩形が原点を中心に`10`の倍数分の角度で回転します #. type: Bullet: '- ' #: text/chapter12.md:352 #, fuzzy -#| msgid "" -#| "The rectangle is translated through `(300, 300)` so that it center lies " -#| "at the center of the canvas." msgid "" "The rectangle is translated through `(300, 300)`, so its center lies at the " "center of the canvas." -msgstr "矩形が`(300, 300)`だけ平行移動し、中心がcanvasの中心に来ます。" +msgstr "矩形が`(300, 300)`だけ平行移動し、中心がキャンバスの中心に来ます。" #. type: Plain text #: text/chapter12.md:354 @@ -10482,12 +10184,6 @@ msgstr "" #. type: Plain text #: text/chapter12.md:372 #, fuzzy -#| 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 of letters." 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 " @@ -10495,10 +10191,8 @@ msgid "" "process is iterated some number of times, starting with the initial sequence " "of letters." msgstr "" -"L-Systemは*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生" -"成規則*の集合で定義されています。\n" -"各生成規則は、アルファベットの文字をとり、それを置き換える文字の配列を返しま" -"す。\n" +"L-Systemは*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生成規則*の集合で定義されています。\n" +"各生成規則は、アルファベットの文字を取り、それを置き換える文字の配列を返します。\n" "この処理は文字の初期配列から始まり、複数回繰り返されます。" #. type: Plain text @@ -10507,9 +10201,7 @@ msgid "" "If each letter of the alphabet is associated with some instruction to " "perform on the canvas, the L-system can be rendered by following the " "instructions in order." -msgstr "" -"もしアルファベットの各文字がcanvas上で実行される命令と対応付けられていれば、" -"その指示に順番に従うことでL-Systemを描画できます。" +msgstr "もしアルファベットの各文字がキャンバス上で実行される命令と対応付けられていれば、その指示に順番に従うことでL-Systemを描画できます。" #. type: Plain text #: text/chapter12.md:376 @@ -10644,23 +10336,15 @@ msgstr "これはまさに上記の仕様をそのまま書き写したもので #. type: Plain text #: text/chapter12.md:420 #, fuzzy -#| 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? 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." msgid "" "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 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 @@ -10693,12 +10377,6 @@ msgstr "最初の2つの引数の型は、値 `initial`と `productions`に対 #. type: Plain text #: text/chapter12.md:434 #, fuzzy -#| 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`." msgid "" "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 " @@ -10706,8 +10384,7 @@ msgid "" "right in the case of the letter `R`, and moving forward in the case of a " "letter `F`." msgstr "" -"3番目の引数は、アルファベットの文字を取り、canvas上の幾つかのアクションを実行" -"することによって*解釈*する関数を表します。\n" +"3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行することによって*解釈*する関数を表します。\n" "この例では、文字`L`は左回転、文字 `R`で右回転、文字 `F`は前進を意味します。" #. type: Plain text @@ -10969,8 +10646,7 @@ msgid "" msgstr "" "しかし、話はこれで終わりではありません。\n" "ここで与えた型は、実際はまだ特殊化されすぎています。\n" -"この定義ではcanvasの操作が実装のどこにも使われていないことに注目してくださ" -"い。\n" +"この定義ではキャンバスの操作が実装のどこにも使われていないことに注目してください。\n" "それに、全く`Effecta`モナドの構造を利用していません。\n" "実際には、この関数は*どんな*モナド`m`についても動作します。" @@ -11103,14 +10779,12 @@ msgid "" "part of the state of the system." msgstr "" "なお、この章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`関数は `main`関数内で `let`束縛を使用して定義されています。\n" -"`State`型がコンテキストを持つように変更できるでしょうが、それはこのシステムの状態の変化する部分ではないので不適切でしょう。" +"`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`アクションを使用するだけで" -"す。" +msgstr "このL-Systemを描画するには、次のような`strokePath`動作を使用するだけです。" #. type: Fenced code block (haskell) #: text/chapter12.md:543 @@ -11177,19 +10851,12 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 #, fuzzy -#| 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." msgid "" "(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. ' @@ -11371,10 +11038,7 @@ msgid "" "For examples of games rendered to the canvas, see the \"Behavior\" and " "\"Signal\" recipes in the [cookbook](https://github.com/JordanMartinez/" "purescript-cookbook/blob/master/README.md#recipes)." -msgstr "" -"canvasに描画されるゲームの例については[cookbook](https://github.com/" -"JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の" -"「Behavior」と「Signal」のレシピを見てください。" +msgstr "キャンバスに描画されるゲームの例については[cookbook](https://github.com/JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の「Behavior」と「Signal」のレシピを見てください。" #. type: Title # #: text/chapter13.md:1 @@ -11971,10 +11635,9 @@ 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 @@ -12335,21 +11998,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:275 #, fuzzy -#| 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 " -#| "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." msgid "" "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" +"つまり関数の引数を使って、乱数生成器の無作為な出力を変更しているのです。" #. type: Plain text #: text/chapter13.md:277 @@ -12649,12 +12305,6 @@ msgstr "副作用のないテスト" #. type: Plain text #: text/chapter13.md:365 #, fuzzy -#| 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." 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 " @@ -12662,12 +12312,9 @@ msgid "" "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" +"しかし、副作用を使わない`quickCheckPure`と呼ばれる`quickCheck`関数の亜種もあります。\n" +"`quickCheckPure`は、入力として乱数の種を取り、テスト結果の配列を返す純粋な関数です。" #. type: Plain text #: text/chapter13.md:367 @@ -12715,10 +12362,8 @@ msgid "" "cases to generate, and the property to test. If all tests pass, you should " "see an array of `Success` data constructors printed to the console." msgstr "" -"`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を" -"とります。\n" -"もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出" -"力されます。" +"`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を取ります。\n" +"もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出力されます。" #. type: Plain text #: text/chapter13.md:386 @@ -12884,9 +12529,7 @@ msgid "" "The `Game` monad and its associated actions, developed in chapter 11, " "constitute a domain-specific language for the domain of _text adventure game " "development_." -msgstr "" -"第11章で開発された `Game`モナドと関連するアクションは、 _テキストアドベン" -"チャーゲーム開発_ という領域に対しての領域特化言語を構成しています。" +msgstr "第11章で開発された`Game`モナドと関連する動作は、*テキストアドベンチャーゲーム開発*という領域に対しての領域特化言語を構成しています。" #. type: Bullet: '- ' #: text/chapter14.md:11 @@ -13340,9 +12983,7 @@ msgstr "既にライブラリに幾つもの大きな改良が加わっている 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要素は表現できません(もちろん、ライブラリが提供する要素" -"名に制限されています)。" +msgstr "不正な名前を持つHTML要素は表現できません(勿論ライブラリが提供する要素名に制限されています)。" #. type: Bullet: '- ' #: text/chapter14.md:148 @@ -14031,20 +13672,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:392 #, fuzzy -#| 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 actions." 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 " "actions." msgstr "" -"しかし、do記法だけがFreeモナドの恩恵だというわけではありません。Freeモナドが" -"あれば、モナドのアクションの _表現_ をその _解釈_ から分離し、同じアクション" -"に _複数の解釈_ を持たせることさえできます。" +"しかし、do記法だけがFreeモナドの恩恵だというわけではありません。\n" +"Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複数の解釈*を持たせることさえできます。" #. type: Plain text #: text/chapter14.md:394 @@ -14096,23 +13731,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:405 #, fuzzy -#| 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:" 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`. 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 @@ -14176,21 +13804,14 @@ msgstr "type Content = Free ContentF\n" #. type: Plain text #: text/chapter14.md:425 #, fuzzy -#| 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 " -#| "`Content` data constructor, we restrict our users to only using the " -#| "monadic actions we provide." 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 " "`Content` data constructor, we restrict our users to only using the monadic " "actions we provide." msgstr "" -"型シノニムの代わりにnewtypeを使用して、使用者に対してライブラリの内部表現を露" -"出することを避けられます。\n" -"`Content`データ構築子を隠すことで、提供しているモナドのアクションだけを使うこ" -"とを使用者に制限しています。" +"型同義語の代わりにnewtypeを使用して、使用者に対してライブラリの内部表現を露出することを避けられます。\n" +"`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使用者に制限しています。" #. type: Plain text #: text/chapter14.md:427 @@ -14231,21 +13852,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:439 #, fuzzy -#| 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 type:" 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 " "type:" msgstr "" -"また、 `Content`モナドについての新しいモナドのアクションになる `elem`と " -"`text`関数を変更する必要があります。\n" -"これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えま" -"す。\n" +"また、`Content`モナドについての新しいモナドの動作になる`elem`と`text`関数を変更する必要があります。\n" +"これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えます。\n" "この関数の型は次のようになっています。" #. type: Fenced code block (haskell) @@ -14257,18 +13871,13 @@ msgstr "liftF :: forall f a. f a -> Free f a\n" #. type: Plain text #: text/chapter14.md:445 #, fuzzy -#| 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:" 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 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 @@ -14349,8 +13958,8 @@ 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 @@ -14379,7 +13988,7 @@ msgid "" "will use the `Writer String` monad to accumulate an HTML string as our " "result." msgstr "" -"まず、アクションを解釈できるモナドを選ばなければなりません。\n" +"まず、動作を解釈できるモナドを選ばなければなりません。\n" "`Writer String`モナドを使って、結果のHTML文字列を累算することにします。" #. type: Plain text @@ -14424,7 +14033,7 @@ msgstr "" msgid "" "The definition of `renderElement` is straightforward, using the `tell` " "action from the `Writer` monad to accumulate several small strings:" -msgstr "`renderElement`の定義は直感的で、複数の小さな文字列を累算するために `Writer`モナドの `tell`アクションを使っています。" +msgstr "`renderElement`の定義は直感的で、複数の小さな文字列を累算するために`Writer`モナドの`tell`動作を使っています。" #. type: Fenced code block (haskell) #: text/chapter14.md:499 @@ -14558,18 +14167,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:551 #, fuzzy -#| msgid "" -#| "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." msgid "" "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 @@ -14616,11 +14220,9 @@ msgid "" "the new action using `liftF`. Update the interpretation `renderContentItem` " "to interpret your new constructor appropriately." msgstr "" -"(普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメント" -"を出力する新しいアクション `comment`に対応してください。\n" -"`liftF`を使ってこの新しいアクションを実装してください。\n" -"新しい構築子を適切に解釈するように、解釈 `renderContentItem`を更新してくださ" -"い。" +"(普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメントを出力する新しい動作`comment`に対応してください。\n" +"`liftF`を使ってこの新しい動作を実装してください。\n" +"新しい構築子を適切に解釈するように、解釈`renderContentItem`を更新してください。" #. type: Title ## #: text/chapter14.md:573 @@ -14635,23 +14237,16 @@ 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 #, fuzzy -#| 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." msgid "" "Let's illustrate the power of the free monad construction by extending our " "language with a new monadic action that returns a non-trivial result." -msgstr "" -"非自明な結果を返す新しいモナドアクションでこの言語を拡張することで、Freeモナ" -"ド構造の威力をお見せしましょう。" +msgstr "非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナド構造の威力をお見せしましょう。" #. type: Plain text #: text/chapter14.md:580 @@ -14682,17 +14277,11 @@ msgstr "開発者がアンカー名を1つ以上の箇所で打ち間違うか #. type: Plain text #: text/chapter14.md:585 #, fuzzy -#| 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." msgid "" "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 "" -"開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい" -"一意な名前を生成するためのモナドアクションを提供できます。" +msgstr "開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい一意な名前を生成するためのモナド動作を提供できます。" #. type: Plain text #: text/chapter14.md:587 @@ -14832,7 +14421,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 @@ -14861,8 +14453,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 @@ -14890,14 +14481,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:656 #, fuzzy -#| msgid "" -#| "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:" msgid "" "Finally, we need to update our interpretation function to interpret the new " "action. We previously used the `Writer String` monad to interpret our " @@ -14906,12 +14489,9 @@ msgid "" "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" +"最後に、新しい動作を解釈するために解釈関数を更新する必要があります。\n" +"以前は計算を解釈するために `Writer String`モナドを使っていましたが、このモナドは新しい名前を生成する能力を持っていないので、何か他のものに切り替えなければなりません。\n" +"`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせることができます。\n" "型注釈を短く保てるように、この解釈モナドを型同義語として定義しておきます。" #. type: Fenced code block (haskell) @@ -14932,12 +14512,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:664 #, fuzzy -#| 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, need to modify the handler used to run our computation. Instead " -#| "of just `execWriter`, we now need to use `evalState` as well:" 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 " @@ -14945,13 +14519,10 @@ msgid "" "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" +"`Writer`と `WriterT`モナドはそれらの動作を抽象化するのに同じ型クラスメンバを使うので、どの動作も変更する必要がありません。\n" +"必要なのは、 `Writer String`への参照全てを `Interp`で置き換えることだけです。\n" "しかし、これを計算するために使われる制御子を変更しなければいけません。\n" -"こうなると単なる`execWriter`の代わりに、ここでも`evalState`を使う必要がありま" -"す。" +"こうなると単なる`execWriter`の代わりに、ここでも`evalState`を使う必要があります。" #. type: Fenced code block (haskell) #: text/chapter14.md:665 @@ -15077,9 +14648,7 @@ msgstr "" 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`を返す新しいアクションを作ってください。" +msgstr "`p`や`img`のような(返る型が`Element`の)関数を`elem`動作と結合して、型`Content Unit`を返す新しい動作を作ってください。" #. type: Bullet: ' - ' #: text/chapter14.md:711 @@ -15093,26 +14662,19 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:711 #, fuzzy -#| 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" msgid "" "(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" +" 1. (普通)型同義語の代わりに`newtype`を使うことによって`Content`モナドの実装を隠してください。\n" " `newtype`用のデータ構築子はエクスポートすべきではありません。\n" -" 1. (難しい)`ContentF`型を変更して以下の新しいアクションに対応してくださ" -"い。\n" +" 1. (難しい)`ContentF`型を変更して以下の新しい動作に対応してください。\n" #. type: Bullet: ' 1. ' #: text/chapter14.md:711 msgid "(Difficult) Modify the `ContentF` type to support a new action" -msgstr "(難しい)`ContentF`型を変更して以下の新しいアクションに対応してください。" +msgstr "(難しい)`ContentF`型を変更して以下の新しい動作に対応してください。" #. type: Plain text #: text/chapter14.md:715 @@ -15130,14 +14692,14 @@ msgstr "" #: 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: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 @@ -15193,20 +14755,14 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter14.md:728 #, fuzzy -#| 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." 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." msgstr "" -"_Freeモナド_ を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変" -"えました。それからこの表現を新しいモナドアクションに対応するよう拡張し、標準" -"モナド変換子を使ってモナドの計算を解釈しました。" +"*Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。\n" +"それからこの表現を新しいモナド動作に対応するよう拡張し、標準モナド変換子を使ってモナドの計算を解釈しました。" #. type: Plain text #: text/chapter14.md:730 @@ -16411,10 +15967,9 @@ msgid "" "`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 @@ -21641,7 +21196,7 @@ msgid "" "the bounds of a single shape using pattern matching." msgstr "" "累算関数`combine`は`where`ブロックで定義されています。\n" -"`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`を引数にとり、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。\n" +"`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`を引数に取り、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。\n" "`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。" #. type: Bullet: '1. ' @@ -24259,14 +23814,6 @@ msgstr "アプリカティブによる検証" #. type: Plain text #: text/chapter7.md:6 -#, fuzzy -#| msgid "" -#| "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 " -#| "convert code which usually involves a lot of boilerplate checking into a " -#| "simple, declarative description of our form." msgid "" "In this chapter, we will meet an important new abstraction – the " "_applicative functor_, described by the `Applicative` type class. Don't " @@ -24275,12 +23822,11 @@ msgid "" "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 @@ -24294,14 +23840,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:10 -#, fuzzy -#| 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 " -#| "user interface, to display errors to the user as part of a data entry " -#| "form." 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 " @@ -24309,10 +23847,10 @@ msgid "" "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 @@ -24353,19 +23891,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:21 -#, fuzzy -#| msgid "" -#| "The `Data.AddressBook` module defines data types and `Show` instances for " -#| "the types in our project, and the `Data.AddressBook.Validation` module " -#| "contains validation rules for those types." msgid "" "The `Data.AddressBook` module defines data types and `Show` instances for " "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 @@ -24384,16 +23916,10 @@ msgstr "" #. type: Plain text #: text/chapter7.md:27 -#, fuzzy -#| msgid "" -#| "The source code for this module defines a function `address` which has " -#| "the following type:" msgid "" "The source code for this module defines a function `address` that has the " "following type:" -msgstr "" -"このモジュールのソースコードでは、次のような型を持つ`address`関数が定義されて" -"います。" +msgstr "このモジュールのソースコードでは、次の型を持つ`address`関数が定義されています。" #. type: Fenced code block (haskell) #: text/chapter7.md:28 @@ -24476,16 +24002,12 @@ msgstr "" #. type: Plain text #: text/chapter7.md:61 -#, fuzzy -#| msgid "" -#| "Of course, this is an expected type error - `address` takes strings as " -#| "arguments, not values of type `Maybe String`." msgid "" "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 @@ -24596,18 +24118,11 @@ msgstr "forall a b c d. (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> M #. type: Plain text #: text/chapter7.md:99 -#, fuzzy -#| msgid "" -#| "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`." msgid "" "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`で包まれた新しい関数へと持ち上げる、ということです。" +msgstr "この型で書かれているのは、3引数の任意の関数を取り、その関数を引数と返り値が`Maybe`で包まれた新しい関数へと持ち上げられる、ということです。" #. type: Plain text #: text/chapter7.md:101 @@ -24617,10 +24132,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`に対する型クラス制約から`Apply`型クラスを取" -"り除いていました。\n" +"勿論、どんな型構築子`f`についても持ち上げができるわけではないのですが、それでは`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。\n" +"さて、先ほどの型の特殊化では、`f`に対する型クラス制約から`Apply`型クラスを取り除いていました。\n" "`Apply`はPreludeで次のように定義されています。" #. type: Fenced code block (haskell) @@ -24702,10 +24215,6 @@ msgstr "この型クラスのインスタンスで書かれているのは、任 #. type: Plain text #: text/chapter7.md:129 -#, fuzzy -#| msgid "" -#| "Now we'll see how `map` and `apply` can be used together to lift " -#| "functions of arbitrary number of arguments." msgid "" "Now we'll see how `map` and `apply` can be used together to lift functions " "of an arbitrary number of arguments." @@ -24715,8 +24224,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:131 -#, fuzzy -#| 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`をそのまま使うだけです。" @@ -24762,10 +24269,9 @@ msgstr "" #. type: Plain text #: text/chapter7.md:150 -#, fuzzy, no-wrap -#| msgid "It is left as an exercise for the reader to verify the types involved in this expression." +#, no-wrap msgid "> It is left as an exercise for the reader to verify the types involved in this expression.\n" -msgstr "この式の型がちゃんと整合しているかの確認は、読者への演習として残しておきます。" +msgstr "> この式に関する型の検証は、読者への演習として残しておきます。\n" #. type: Plain text #: text/chapter7.md:152 @@ -24800,22 +24306,15 @@ msgstr "" #. type: Plain text #: text/chapter7.md:164 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 @@ -24897,18 +24396,11 @@ msgstr "" #. type: Plain text #: text/chapter7.md:199 -#, fuzzy -#| msgid "" -#| "If we think of applicative functors as functors which allow lifting of " -#| "functions, then `pure` can be thought of as lifting functions of zero " -#| "arguments." msgid "" "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`は引数のない関数の持ち上げだというように考えることができます。" +msgstr "アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、`pure`は引数のない関数の持ち上げだというように考えられます。" #. type: Title ## #: text/chapter7.md:200 @@ -24929,10 +24421,10 @@ msgstr "" #. type: Plain text #: text/chapter7.md:205 -#, fuzzy, no-wrap +#, 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" msgstr "" -"例えば関手`Maybe`は省略可能な値の副作用を表現しています。\n" +"例えば関手`Maybe`は欠けている可能性がある値の副作用を表現しています。\n" "その他の例としては、型`err`のエラーの可能性の副作用を表す`Either err`や、大域的な構成を読み取る副作用を表すArrow関手 (arrow functor) `r ->`があります。\n" "ここでは`Maybe`関手についてのみ考えることにします。\n" @@ -24950,16 +24442,10 @@ msgstr "" #. type: Plain text #: text/chapter7.md:209 -#, fuzzy -#| msgid "" -#| "`pure` lifts pure (side-effect free) values into the larger language, and " -#| "for functions, we can use `map` and `apply` as described above." msgid "" "`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`を使うことができます。" +msgstr "`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数については上で述べた通り`map`と`apply`を使えます。" #. type: Plain text #: text/chapter7.md:211 @@ -25032,17 +24518,9 @@ msgstr "" "> fullName \"Phillip\" \"A\" \"Freeman\"\n" "Freeman, Phillip A\n" +# XXX: Maybeを行中コードとしてマークアップしたいです。 #. type: Plain text #: text/chapter7.md:230 -#, fuzzy -#| 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:" msgid "" "Suppose that this function forms the implementation of a (very simple!) web " "service with the three arguments provided as query parameters. We want to " @@ -25051,12 +24529,9 @@ msgid "" "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 @@ -25081,8 +24556,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:242 text/chapter7.md:292 text/chapter7.md:444 #: text/chapter7.md:479 text/chapter7.md:525 -#, fuzzy -#| msgid "or with _applicative do_" msgid "Or with _applicative do_:" msgstr "または*アプリカティブdo*で次のようにします。" @@ -25139,20 +24612,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:267 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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 @@ -25241,13 +24707,13 @@ msgstr "" "> :type fullNameEither\n" "Maybe String -> Maybe String -> Maybe String -> Either String String\n" +# FIXME: Maybeの行中コードのマークアップが崩れている気がします。 #. type: Plain text #: text/chapter7.md:307 -#, fuzzy msgid "" "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`の結果のどちらかを返します。" +msgstr "これでこの関数は`Maybe`を使う3つの省略可能な引数を取り、`String`のエラー文言か`String`の結果のどちらかを返します。" #. type: Plain text #: text/chapter7.md:309 @@ -25278,14 +24744,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:322 -#, fuzzy 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:" msgstr "" "このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラー文言が表示されます。\n" -"しかし、もし複数の入力が省略されているとき、最初のエラーしか見ることができません。" +"しかし、もし複数の入力が省略されているとき、最初のエラーしか見れません。" #. type: Fenced code block (text) #: text/chapter7.md:323 @@ -25316,18 +24781,11 @@ msgstr "作用の結合" #. type: Plain text #: text/chapter7.md:333 -#, fuzzy -#| 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`." msgid "" "As an example of working with applicative functors abstractly, this section " "will show how to write a function that generically combines side-effects " "encoded by an applicative functor `f`." -msgstr "" -"抽象的にアプリカティブ関手を扱う例として、アプリカティブ関手`f`によって表現さ" -"れた副作用を一般的に組み合わせる関数を書く方法をこの節では示します。" +msgstr "抽象的にアプリカティブ関手を扱う例として、この節ではアプリカティブ関手`f`によって表現された副作用を一般的に組み合わせる関数を書く方法を示します。" #. type: Plain text #: text/chapter7.md:335 @@ -25354,14 +24812,13 @@ msgstr "" #. type: Plain text #: text/chapter7.md:337 -#, fuzzy, 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" +#, no-wrap 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 @@ -25460,7 +24917,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:376 -#, fuzzy msgid "" "When specialized to `Maybe`, our function returns a `Just` only if every " "list element is `Just`; otherwise, it returns `Nothing`. This is consistent " @@ -25468,25 +24924,20 @@ msgid "" "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 -#, fuzzy, 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" +#, no-wrap 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 -#, fuzzy -#| msgid "" -#| "We will see the `combineList` function again later, when we consider " -#| "`Traversable` functors." msgid "" "We will see the `combineList` function again later when we consider " "`Traversable` functors." @@ -25496,15 +24947,15 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:386 -#, fuzzy 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`." msgstr "" -"(普通)数値演算子`+`、`-`、`*`、`/`の省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返す版を書いてください。\n" -"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けます。\n" +"(普通)数値演算子`+`、`-`、`*`、`/`の別のバージョンを書いてください。\n" +"ただし省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返します。\n" +"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けてください。\n" "*手掛かり*:`lift2`を使ってください。" #. type: Bullet: ' 1. ' @@ -25521,35 +24972,25 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:386 -#, fuzzy 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 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 -#, fuzzy -#| 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:" 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 exported by the `Data.AddressBook` module have the following " "types:" msgstr "" -"この章のソースコードでは住所録アプリケーションで使うことのできるいろいろな" -"データ型が定義されています。\n" -"詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされ" -"る重要な関数は次のような型を持っています。" +"この章のソースコードでは住所録アプリケーションで使うであろう幾つかのデータ型が定義されています。\n" +"詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされる鍵となる関数は次のような型を持ちます。" #. type: Fenced code block (haskell) #: text/chapter7.md:391 @@ -25569,8 +25010,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:400 -#, fuzzy -#| msgid "where `PhoneType` is defined as an algebraic data type:" msgid "Where `PhoneType` is defined as an algebraic data type:" msgstr "ここで、`PhoneType`は次のような代数的データ型として定義されています。" @@ -25582,17 +25021,12 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook.purs:PhoneType}}\n #. type: Plain text #: text/chapter7.md:406 -#, fuzzy -#| 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`:" msgid "" "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 @@ -25681,21 +25115,15 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:450 -#, fuzzy -#| 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 " -#| "with the `Right` constructor." 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 " "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 @@ -25709,10 +25137,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:454 -#, fuzzy -#| msgid "" -#| "This function can be seen to work in PSCi, but has a limitation which we " -#| "have seen before:" msgid "" "This function can be seen to work in PSCi, but it has a limitation that we " "have seen before:" @@ -25732,29 +25156,17 @@ msgstr "" #. type: Plain text #: text/chapter7.md:461 -#, fuzzy -#| 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." 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." msgstr "" -"`Either String`アプリカティブ関手は遭遇した最初のエラーだけを返します。\n" -"でもこの入力では、名前の不足と姓の不足という2つのエラーがわかるようにしたくな" -"るでしょう。" +"`Either String`アプリカティブ関手は最初に遭遇したエラーだけを返します。\n" +"仮にこの入力だったとすると、2つのエラーが分かったほうが良いでしょう。\n" +"1つは名前の不足で、2つ目は姓の不足です。" #. type: Plain text #: text/chapter7.md:463 -#, fuzzy -#| 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." msgid "" "There is another applicative functor that the `validation` library provides. " "This functor is called `V`, and it can return errors in any _semigroup_. For " @@ -25762,9 +25174,8 @@ msgid "" "errors, concatenating new errors onto the end of the array." msgstr "" "`validation`ライブラリでは別のアプリカティブ関手も提供されています。\n" -"これは単に`V`と呼ばれていて、何らかの*半群*でエラーを返す機能があります。\n" -"例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、" -"`String`の配列をエラーとして返すことができます。" +"これは`V`という名前で、何らかの*半群*でエラーを返せます。\n" +"例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、`String`の配列をエラーとして返せます。" #. type: Plain text #: text/chapter7.md:465 @@ -25813,11 +25224,6 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:485 -#, fuzzy -#| 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." msgid "" "`validateAddress` validates an `Address` structure. It checks that the " "`street` and `city` fields are non-empty and that the string in the `state` " @@ -25973,12 +25379,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:545 -#, fuzzy -#| 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 cheatsheet and interactive test environment." msgid "" "(Medium) Write a regular expression `nonEmptyRegex :: Regex` to check that a " "string is not entirely whitespace. _Hint_: If you need help developing this " @@ -26048,16 +25448,10 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va #. type: Plain text #: text/chapter7.md:563 -#, fuzzy -#| msgid "" -#| "`validatePhoneNumbers` uses a new function we haven't seen before - " -#| "`traverse`." msgid "" "`validatePhoneNumbers` uses a new function we haven't seen before – " "`traverse`." -msgstr "" -"`validatePhoneNumbers`はこれまでに見たことのない新しい関数、`traverse`を使い" -"ます。" +msgstr "`validatePhoneNumbers`はこれまでに見たことのない新しい関数である`traverse`を使っています。" #. type: Plain text #: text/chapter7.md:565 @@ -26093,24 +25487,15 @@ msgstr "" #. type: Plain text #: text/chapter7.md:575 -#, fuzzy -#| msgid "" -#| "Every traversable functor is both a `Functor` and `Foldable` (recall that " -#| "a _foldable functor_ was a type constructor which 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." msgid "" "Every traversable functor is both a `Functor` and `Foldable` (recall that a " "_foldable functor_ was a type constructor that supported a fold operation, " "reducing a structure to a single value). In addition, a traversable functor " "can combine a collection of side-effects that depend on its structure." msgstr "" -"全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能" -"関手*は、構造を1つの値へと纏める畳み込み操作を提供する型構築子であったことを" -"思い出してください)。\n" -"それに加えて、`Traversable`関手はその構造に依存した副作用の集まりを連結する機" -"能を提供します。" +"全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能関手*は畳み込み操作に対応する型構築子であったことを思い出してください。\n" +"畳み込みとは構造を1つの値へと簡約するものでした)。\n" +"それに加えて、巡回可能関手はその構造に依存した副作用の集まりを組み合わせられます。" #. type: Plain text #: text/chapter7.md:577 @@ -26161,14 +25546,6 @@ msgstr "traverse :: forall a b. (a -> V Errors b) -> Array a -> V Errors (Array #. type: Plain text #: text/chapter7.md:591 -#, fuzzy -#| msgid "" -#| "This type signature says that if we have a validation function `m` for a " -#| "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 successively." msgid "" "This type signature says that if we have a validation function `m` for a " "type `a`, then `traverse m` is a validation function for arrays of type " @@ -26177,12 +25554,9 @@ msgid "" "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 @@ -26220,13 +25594,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:607 -#, fuzzy -#| 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 as an exercise for the interested reader." msgid "" "Traversable functors capture the idea of traversing a data structure, " "collecting a set of effectful computations, and combining their effects. In " @@ -26234,10 +25601,11 @@ msgid "" "`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 @@ -26273,13 +25641,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:620 -#, fuzzy -#| 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." msgid "" "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 " @@ -26287,11 +25648,10 @@ msgid "" "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 @@ -26336,7 +25696,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:639 -#, fuzzy msgid "" "These examples show that traversing the `Nothing` value returns `Nothing` " "with no validation, and traversing `Just x` uses the validation function to " @@ -26345,26 +25704,20 @@ msgid "" "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 -#, fuzzy -#| msgid "" -#| "Other traversable functors include `Array`, and `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." msgid "" "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 @@ -26389,20 +25742,18 @@ msgstr "" #. type: Plain text #: text/chapter7.md:651 -#, fuzzy, 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" +#, no-wrap 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 -#, fuzzy, 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" +#, no-wrap 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 @@ -26418,11 +25769,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:659 -#, fuzzy -#| msgid "" -#| "(Medium) Write a `Traversable` instance for `Tree a`, which combines side-" -#| "effects from left-to-right. _Hint_: There are some additional instance " -#| "dependencies that need to be defined for `Traversable`." msgid "" "(Medium) Write a `Traversable` instance for `Tree a`, which combines side-" "effects left-to-right. _Hint_: There are some additional instance " @@ -26435,16 +25781,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter7.md:661 -#, fuzzy -#| msgid "" -#| "(Medium) Write a function `traversePreOrder :: forall a m b. Applicative " -#| "m => (a -> m b) -> Tree a -> m (Tree b)` that performs a pre-order " -#| "traversal 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." msgid "" "(Medium) Write a function `traversePreOrder :: forall a m b. Applicative m " "=> (a -> m b) -> Tree a -> m (Tree b)` that performs a pre-order traversal " @@ -26529,12 +25865,6 @@ msgstr "" #. type: Plain text #: text/chapter7.md:675 -#, fuzzy -#| 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." 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 " @@ -26542,10 +25872,8 @@ msgid "" "perform its side-effects in parallel." msgstr "" "しかし一般には、アプリカティブ関手はこれよりももっと一般的です。\n" -"アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しませ" -"ん。\n" -"実際、並列に副作用を実行するためのアプリカティブ関手というものは妥当になりえ" -"ます。" +"アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しません。\n" +"実際、並列に副作用を実行するアプリカティブ関手は妥当でしょう。" #. type: Plain text #: text/chapter7.md:677 @@ -26555,29 +25883,19 @@ msgid "" "it would not matter what order we ran the various validators. We could even " "run them in parallel over the data structure!" msgstr "" -"例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだ" -"としてもやはり正常に動き、このときどんな順序でそれぞれの検証器を実行しても問" -"題はありません。\n" +"例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだとしてもやはり正常に動き、このときどんな順序で各検証器を実行しても問題はありません。\n" "データ構造に対して並列にこれの実行さえできるのです。" #. type: Plain text #: text/chapter7.md:679 -#, fuzzy -#| 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_:" msgid "" "As a second example, the `parallel` package provides a type class `Parallel` " "which supports _parallel computations_. `Parallel` provides a function " "`parallel` that uses some `Applicative` functor to compute the result of its " "input computation _in parallel_:" msgstr "" -"別の例として、`parallel`パッケージは、*並列計算*に対応する`Parallel`型クラス" -"を与えます。\n" -"`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入" -"力の計算を*並列に*計算できます。" +"2つ目の例として、`parallel`パッケージは*並列計算*に対応する`Parallel`型クラスを提供します。\n" +"`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入力の計算の結果を*並列に*計算します。" #. type: Fenced code block (haskell) #: text/chapter7.md:680 @@ -26611,15 +25929,10 @@ msgstr "" #. type: Plain text #: text/chapter7.md:690 -#, fuzzy -#| msgid "" -#| "Applicative functors are a natural way to capture side-effects which can " -#| "be combined in parallel." msgid "" "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 @@ -26628,36 +25941,24 @@ msgstr "この章では新しい考え方を沢山扱いました。" #. type: Bullet: '- ' #: text/chapter7.md:698 -#, fuzzy -#| msgid "" -#| "We introduced the concept of an _applicative functor_ which generalizes " -#| "the idea of function application to type constructors which capture some " -#| "notion of side-effect." msgid "" "We introduced the concept of an _applicative functor_ which generalizes the " "idea of function application to type constructors that captures some notion " "of side-effect." msgstr "" -"関数適用の概念を副作用の観念を捉えた型構築子へと一般化する、 _アプリカティブ" -"関手_ の概念を導入しました。" +"*アプリカティブ関手*の概念を導入しました。\n" +"これは、関数適用の概念から副作用の観念を捉えた型構築子へと一般化するものです。" #. type: Bullet: '- ' #: text/chapter7.md:698 -#, fuzzy -#| 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 structure." msgid "" "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 @@ -26669,17 +25970,9 @@ msgstr "" "`Traversable`型クラスに出会いました。*巡回可能関手*の考え方を内包するものであ" "り、要素が副作用を持つ値の結合に使うことができる容れ物でした。" +# FIXME: DSLの行中強調が欠けています。 #. type: Plain text #: text/chapter7.md:700 -#, fuzzy -#| msgid "" -#| "Applicative functors are an interesting abstraction which provide 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_." msgid "" "Applicative functors are an interesting abstraction that provides neat " "solutions to a number of problems. We will see them a few more times " @@ -26689,14 +25982,10 @@ msgid "" "perform that validation. In general, we will see that applicative functors " "are a useful tool for the design of _domain specific languages." msgstr "" -"アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化で" -"す。\n" +"アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化です。\n" "本書を通じて何度も見ることになるでしょう。\n" -"今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、" -"これにより検証器が*どうやって*検証するかではなく、*何を*検証すべきなのかを定" -"義できました。\n" -"一般に、アプリカティブ関手は*領域特化言語*を設計する上で便利な道具になりま" -"す。" +"今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、これにより検証器が*どうやって*検証を実施するかではなく、*何を*検証すべきなのかを定義できました。\n" +"一般にアプリカティブ関手が*領域特化言語*を設計する上で便利な道具になることを見ていきます。" #. type: Plain text #: text/chapter7.md:701 @@ -27335,27 +26624,20 @@ msgstr "" #. type: Plain text #: text/chapter8.md:192 #, fuzzy -#| 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`." msgid "" "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 msgid "" "In `c1`, the two expressions `m1` and `m2` are grouped into their own do " "notation block." -msgstr "" -"`c1`では2つの式 `m1`と `m2`がそれぞれのdo記法ブロック内にグループ化されていま" -"す。" +msgstr "`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグループ化されています。" #. type: Plain text #: text/chapter8.md:196 @@ -27479,18 +26761,12 @@ msgid "" "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 #, fuzzy -#| 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 of results would consist of all folds over all possible paths. " -#| "This corresponds to a traversal of a graph!" 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 " @@ -27498,11 +26774,8 @@ msgid "" "of results would consist of all folds over all possible paths. This " "corresponds to a traversal of a graph!" msgstr "" -"もし `m`として配列の型構築子 `Array`を選ぶとすると、畳み込みのそれぞれの段階" -"で複数の結果を返すことができ、畳み込みは結果それぞれに対して次の手順を継続し" -"ます。\n" -"最後に、結果の集まりは、可能な経路全ての畳み込みから構成されることになりま" -"す。\n" +"もし`m`として配列の型構築子`Array`を選ぶとすると、畳み込みの各段階で複数の結果を返すことができ、畳み込みは各結果に対して次の手順を継続します。\n" +"最後に、結果の集まりは、可能な経路全ての畳み込みから構成されることになります。\n" "これはグラフの走査と対応しています。" #. type: Plain text @@ -28320,17 +27593,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:443 #, fuzzy -#| 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 " -#| "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 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." msgid "" "As mentioned previously, the `Effect` monad is of central importance to " "PureScript. The reason why it's central is that it is the conventional way " @@ -28343,15 +27605,10 @@ msgid "" "doesn't do much except encapsulate side effects." msgstr "" "以前言及したように`Effect`モナドはPureScriptで核心的な重要さがあります。\n" -"なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやりとりす" -"る上での常套手段だからです。\n" -"`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕" -"組みを提供します。\n" -"`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように" -"動作しどう使うのか理解することもまた極めて大事なことですので、実際に" -"PureScriptで何か動かす前にその章を読まれることをお勧めします。\n" -"要は`Effect`モナドは結構単純なのです。幾つかの補助関数がありますが、それを差" -"し置いても副作用を内包すること以外には大したことはしません。" +"なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りする上での常套手段だからです。\n" +"`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕組みを提供します。\n" +"`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように動作しどう使うのか理解することもまた極めて大事なことですので、実際にPureScriptで何か動かす前にその章を読まれることをお勧めします。\n" +"要は`Effect`モナドは結構単純なのです。幾つかの補助関数がありますが、それを差し置いても副作用を内包すること以外には大したことはしません。" #. type: Plain text #: text/chapter8.md:447 @@ -28541,8 +27798,8 @@ 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:513 @@ -28567,12 +27824,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:524 #, fuzzy -#| 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." 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 " @@ -28581,10 +27832,8 @@ msgid "" "type system." msgstr "" "`new`は型`STRef r a`の変更可能な参照領域を新しく作るのに使われます。\n" -"`STRef r a`は `read`アクションを使って状態を読み取ったり、`write`アクション" -"や `modify`アクションで状態を変更するのに使われます。\n" -"型`a`は領域に格納された値の型で、型 `r`は型システムで*メモリ領域*(または*" -"ヒープ*)を表しています。" +"`STRef r a`は`read`動作を使って状態を読み取ったり、`write`動作や`modify`動作で状態を変更するのに使われます。\n" +"型`a`は領域に格納された値の型で、型 `r`は型システムで*メモリ領域*(または*ヒープ*)を表しています。" #. type: Plain text #: text/chapter8.md:526 @@ -28702,10 +27951,8 @@ msgid "" "the parentheses_ on the left of the function arrow. That means that whatever " "action we pass to `run` has to work with _any region_ `r` whatsoever." msgstr "" -"ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化" -"されているということです。\n" -"`run`に渡したどんなアクションでも、*任意の領域*`r`が何であれ動作するというこ" -"とを意味しています。" +"ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化されているということです。\n" +"`run`に渡したどんな動作でも、*任意の領域*`r`が何であれ動作するということを意味しています。" #. type: Plain text #: text/chapter8.md:563 @@ -28958,18 +28205,11 @@ msgstr "" #. type: Plain text #: text/chapter8.md:666 #, fuzzy -#| 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." 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." -msgstr "" -"局所的な変更可能状態を扱うとき、特に作用が絡むループを生成する`for`、 " -"`foreach`、 `while`のようなアクションを一緒に使うときには、`ST`作用は短い" -"JavaScriptを生成する良い方法となります。" +msgstr "局所的な変更可能状態を扱うとき、特に作用が絡むループを生成する`for`、 `foreach`、 `while`のような動作を一緒に使うときには、`ST`作用は短いJavaScriptを生成する良い方法となります。" #. type: Bullet: '1. ' #: text/chapter8.md:672 @@ -29543,24 +28783,15 @@ msgstr "Tuple person setPerson <- useState examplePerson\n" #. type: Plain text #: text/chapter8.md:815 #, fuzzy -#| 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." 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 results in a slightly less convenient architecture in this case." msgstr "" -"なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部" -"品に分解することが自在にできます。\n" -"例えば`Person`のそれぞれのレコードフィールドについて分離した状態の部品を使っ" -"て、このアプリを書き直すことができるでしょう。\n" -"しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいま" -"す。" +"なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部品に分解することが自在にできます。\n" +"例えば`Person`の各レコードフィールドについて分離した状態の部品を使って、このアプリを書き直すことができるでしょう。\n" +"しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいます。" #. type: Plain text #: text/chapter8.md:817 @@ -29640,7 +28871,7 @@ msgstr "" #. type: Plain text #: 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:845 @@ -30014,9 +29245,7 @@ msgstr "" 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`フックに適切なレコード更新呼び出しを実施します。" +msgstr "`setValue`は`formField`の各呼び出しに与えた関数で、文字列を取り`setPerson`フックに適切なレコード更新呼び出しを実施します。" #. type: Plain text #: text/chapter8.md:963 @@ -30082,19 +29311,13 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter8.md:980 #, fuzzy -#| msgid "" -#| "(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." msgid "" "(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」背景に集めて表示させています。\n" +"空の線で分割することにより、各検証エラーにpink-alert背景を持たせるように変更してください。" #. type: Plain text #: text/chapter8.md:983 @@ -30103,8 +29326,9 @@ 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:985 @@ -30244,12 +29468,6 @@ msgstr "非同期作用" #. type: Plain text #: text/chapter9.md:6 #, fuzzy -#| 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." msgid "" "This chapter focuses on the `Aff` monad, which is similar to the `Effect` " "monad, but represents _asynchronous_ side-effects. We'll demonstrate " @@ -30257,10 +29475,10 @@ msgid "" "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 @@ -30822,12 +30040,6 @@ msgstr "`sequential`:反対方向に変換します。" #. type: Plain text #: text/chapter9.md:156 #, fuzzy -#| msgid "" -#| "The `aff` library provides a `Parallel` instance for the `Aff` monad. It " -#| "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." msgid "" "The `aff` library provides a `Parallel` instance for the `Aff` monad. It " "uses mutable references to combine `Aff` actions in parallel by keeping " @@ -30836,8 +30048,7 @@ msgid "" "continuation." msgstr "" "`aff`ライブラリは `Aff`モナドの `Parallel`インスタンスを提供します。\n" -"これは、2つの継続 (continuation) のどちらが呼び出されたかを把握することによっ" -"て、変更可能な参照を使用して並列に `Aff`アクションを組み合わせます。\n" +"これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に `Aff`動作を組み合わせます。\n" "両方の結果が返されたら、最終結果を計算してメインの継続に渡すことができます。" #. type: Plain text diff --git a/translation/terms.txt b/translation/terms.txt index 6519c1b1..07415ad5 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -5,3 +5,6 @@ accumulator: 累算器。一般には「累積」とされることもあるよ pattern match: パターン照合 JavaScript runtime: 実行器 hash code: ハッシュコード。「ハッシュ値」とされていました。 +context: 文脈。一般には単に「コンテキスト」とされるようです。 +synonym: 同義語。 +canvas: 固有名詞、HTML 5で導入された機能としてのCanvasは英単語として、一般名詞としては「キャンバス」と片仮名にします。 From e62d546e9ba92ca9a81b6d45425d3cdd6bc6e372 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Wed, 9 Aug 2023 08:44:10 +0900 Subject: [PATCH 13/29] [ update ] chapter 8 translation --- translation/ja.po | 615 ++++++++++-------------------------------- translation/terms.txt | 1 + 2 files changed, 139 insertions(+), 477 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index 921b5afa..3b37f8ed 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-06 23:23+0900\n" +"PO-Revision-Date: 2023-08-12 18:56+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -26004,28 +26004,22 @@ msgstr "作用モナド" #. type: Plain text #: text/chapter8.md:6 -#, fuzzy msgid "" "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" +"副作用とは省略可能な値、エラー文言、検証などです。\n" +"この章では、副作用を扱うためのより表現力の高い別の抽象化である*モナド*を導入します。" #. type: Plain text #: text/chapter8.md:8 -#, fuzzy -#| msgid "" -#| "The goal of this chapter is to explain why monads are a useful " -#| "abstraction, and their connection with _do notation_." msgid "" "The goal of this chapter is to explain why monads are a useful abstraction " "and their connection with _do notation_." -msgstr "" -"この章の目的は、なぜモナドが便利な抽象化なのかということと、 _do記法_ との関" -"係を説明することです。" +msgstr "この章の目的は、なぜモナドが便利な抽象化なのかということと、*do記法*との関係を説明することです。" #. type: Plain text #: text/chapter8.md:12 @@ -26034,31 +26028,20 @@ msgstr "このプロジェクトでは、以下の依存関係が追加されて #. type: Bullet: '- ' #: text/chapter8.md:15 -#, fuzzy -#| msgid "" -#| "`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." msgid "" "`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 install it " "explicitly." msgstr "" -"`effect`: 章の後半の主題である`Effect`モナドを定義しています。この依存関係は" -"全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存" -"関係にありました)、明示的にインストールしなければいけないことは稀です。" +"`effect`: 章の後半の主題である`Effect`モナドを定義しています。\n" +"この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存関係にありました)、明示的にインストールしなければいけないことは稀です。" #. type: Bullet: '- ' #: text/chapter8.md:15 -#, fuzzy -#| 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 "`react-basic-hooks`: アドレス帳アプリに使うWebフレームワークです。" +msgstr "`react-basic-hooks`: アドレス帳アプリに使うwebフレームワークです。" #. type: Title ## #: text/chapter8.md:16 @@ -26100,24 +26083,15 @@ msgstr "2回目の投擲で値 `y`を _選択_ します。" #. type: Bullet: '- ' #: text/chapter8.md:25 -#, fuzzy -#| 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 "" -"もし `x`と `y`の和が `n`なら組 `[x, y]`を返し、そうでなければ失敗します。" +msgstr "もし`x`と`y`の和が`n`なら組`[x, y]`を返し、そうでなければ失敗します。" #. type: Plain text #: text/chapter8.md:27 -#, fuzzy -#| msgid "" -#| "Array comprehensions allow us to write this non-deterministic algorithm " -#| "in a natural way:" msgid "" "Array comprehensions allow us to write this non-deterministic algorithm " "naturally:" -msgstr "" -"配列内包表記を使うと、この非決定的アルゴリズムを自然に書くことができます。" +msgstr "配列内包表記を使うと、この非決定的アルゴリズムを自然に書けます。" #. type: Fenced code block (hs) #: text/chapter8.md:28 @@ -26176,16 +26150,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:52 -#, fuzzy -#| msgid "" -#| "In general, 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 types)." msgid "" "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 " @@ -26196,15 +26160,10 @@ msgid "" "`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 @@ -26225,10 +26184,6 @@ msgstr "child :: XML -> String -> Maybe XML\n" #. type: Plain text #: text/chapter8.md:60 -#, fuzzy -#| msgid "" -#| "which looks for a child element of a node, and returns `Nothing` if no " -#| "such element exists." msgid "" "Which looks for a child element of a node and returns `Nothing` if no such " "element exists." @@ -26238,11 +26193,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:62 -#, fuzzy -#| 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 encoded as an XML document:" msgid "" "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 " @@ -26272,13 +26222,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:73 -#, fuzzy -#| 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." msgid "" "The `userCity` function looks for a child element `profile`, an element " "`address` inside the `profile` element, and finally, an element `city` " @@ -26286,10 +26229,9 @@ msgid "" "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 @@ -26337,16 +26279,10 @@ msgstr "ここで鍵となる関数は `Bind`型クラスで定義されてい #. type: Plain text #: text/chapter8.md:90 -#, fuzzy -#| msgid "" -#| "The `Monad` type class extends `Bind` with the operations of the " -#| "`Applicative` type class that we have already seen." msgid "" "The `Monad` type class extends `Bind` with the operations of the " "`Applicative` type class we've already seen." -msgstr "" -"`Monad`型クラスは、既に見てきた `Applicative`型クラスの操作で `Bind`を拡張し" -"ます。" +msgstr "`Monad`型クラスは、既に見てきた`Applicative`型クラスの操作で`Bind`を拡張します。" #. type: Plain text #: text/chapter8.md:92 @@ -26404,19 +26340,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:111 -#, fuzzy -#| 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 some computation:" msgid "" "Let's see how the `Bind` type class is related to do notation. Consider a " "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 @@ -26489,10 +26419,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:143 -#, fuzzy, 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" +#, no-wrap 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" +msgstr "" +"do記法を使って表現されたコードは、`>>=`演算子を使う等価なコードより遥かに読みやすくなることがよくあることも特筆すべき点です。\n" +"しかしながら、明示的に`>>=`を使って束縛を書くと、*ポイントフリー*形式でコードが書けるようになることがよくあります。\n" +"ただし、読みやすさにはやはり注意が要ります。\n" #. type: Title ## #: text/chapter8.md:144 @@ -26623,14 +26555,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:192 -#, fuzzy msgid "" "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`に束縛されます。" +"どちらの場合でも`m1`の結果は結局は名前`x`に束縛され、`m2`の結果は名前`y`に束縛されます。" #. type: Plain text #: text/chapter8.md:194 @@ -26641,10 +26572,6 @@ msgstr "`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグルー #. type: Plain text #: text/chapter8.md:196 -#, fuzzy -#| msgid "" -#| "In `c2`, all three expressions `m1`, `m2` and `m3` appear in the same do " -#| "notation block." msgid "" "In `c2`, all three expressions `m1`, `m2`, and `m3` appear in the same do " "notation block." @@ -26693,13 +26620,6 @@ msgstr "モナドで畳み込む" #. type: Plain text #: text/chapter8.md:212 -#, fuzzy -#| 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." msgid "" "As an example of working with monads abstractly, this section will present a " "function that works with any type constructor in the `Monad` type class. " @@ -26707,25 +26627,18 @@ msgid "" "programming \"in a larger language\" with side-effects, and also illustrate " "the generality which programming with monads brings." msgstr "" -"抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で" -"機能する関数を紹介していきます。\n" -"これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと" -"対応しているという直感的理解を補強しますし、モナドによるプログラミングがもた" -"らす一般性も示しています。" +"抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で機能する関数を紹介していきます。\n" +"これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと対応しているという直感的理解を補強しますし、モナドによるプログラミングが齎す一般性も示しています。" #. type: Plain text #: text/chapter8.md:214 -#, fuzzy -#| 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:" msgid "" "The function we will write is called `foldM`. It generalizes the `foldl` " "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 @@ -26755,18 +26668,16 @@ msgstr "直感的には、`foldM`は様々な副作用の組み合わせに対 #. type: Plain text #: text/chapter8.md:225 -#, fuzzy 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 " "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 -#, fuzzy 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 " @@ -26774,9 +26685,9 @@ msgid "" "of results would consist of all folds over all possible paths. This " "corresponds to a traversal of a graph!" msgstr "" -"もし`m`として配列の型構築子`Array`を選ぶとすると、畳み込みの各段階で複数の結果を返すことができ、畳み込みは各結果に対して次の手順を継続します。\n" -"最後に、結果の集まりは、可能な経路全ての畳み込みから構成されることになります。\n" -"これはグラフの走査と対応しています。" +"もし`m`として型構築子`Array`を選ぶとすると、畳み込みの各段階で0以上の結果を返せるため、畳み込みは各結果に対して独立に次の手順を継続します。\n" +"最後に、結果の集まりは可能な経路の全ての畳み込みから構成されることになります。\n" +"これはグラフの走査と対応していますね。" #. type: Plain text #: text/chapter8.md:229 @@ -26834,33 +26745,24 @@ msgstr "" #. type: Plain text #: text/chapter8.md:249 -#, fuzzy -#| msgid "" -#| "Note that this implementation is almost identical to that of `foldl` on " -#| "lists, with the exception of do notation." msgid "" "Note that this implementation is almost identical to that of `foldl` on " "lists, except for do notation." msgstr "" -"なお、do記法を除けば、この実装は配列に対する `foldl`の実装とほとんど同じで" -"す。" +"なお、この実装はリストに対する`foldl`の実装とほとんど同じです。\n" +"ただしdo記法である点を除きます。" #. type: Plain text #: text/chapter8.md:251 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 @@ -26897,14 +26799,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:270 -#, fuzzy msgid "" "The `foldM safeDivide` function returns `Nothing` if a division by zero was " "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 @@ -26957,16 +26858,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:288 -#, fuzzy -#| msgid "" -#| "The interested reader can check that `ap` agrees with `apply` for the " -#| "monads we have already encountered: `Array`, `Maybe` and `Either e`." msgid "" "The interested reader can check that `ap` agrees with `apply` for the monads " "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 @@ -26987,7 +26884,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:292 -#, fuzzy 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 " @@ -26995,7 +26891,8 @@ msgid "" "user's city in an XML document that encoded their user profile:" msgstr "" "しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法の構文で強調されています。\n" -"利用者情報をエンコードしたXML文書から利用者の都市を検索する、`userCity`の例についてもう一度考えてみましょう。" +"`userCity`の例についてもう一度考えてみましょう。\n" +"利用者情報をエンコードしたXML文書から利用者の市町村を検索するものでした。" #. type: Plain text #: text/chapter8.md:303 @@ -27026,14 +26923,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:307 -#, fuzzy -#| msgid "" -#| "In the last chapter, we saw that the `Applicative` type class can be used " -#| "to 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." msgid "" "In the last chapter, we saw that the `Applicative` type class can be used to " "express parallelism. This was precisely because the function arguments being " @@ -27041,22 +26930,13 @@ msgid "" "computations to depend on the results of previous computations, the same " "does not apply – a monad has to combine its side-effects in sequence." msgstr "" -"前の章では `Applicative`型クラスは並列処理を表現できることを見ました。\n" -"持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りで" -"す。\n" -"`Monad`型クラスは計算が前の計算の結果に依存できるようにしますから、同じように" -"はなりません。\n" -"モナドは副作用を順番に組み合わせなければいけません。" +"前の章では`Applicative`型クラスは並列処理を表現できることを見ました。\n" +"持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りです。\n" +"`Monad`型クラスは計算が前の計算の結果に依存できるようになっており、同じようにはなりません。\n" +"つまりモナドは副作用を順番に組み合わせなければならないのです。" #. type: Bullet: ' 1. ' #: text/chapter8.md:312 -#, fuzzy -#| msgid "" -#| "(Easy) Write a function `third` which 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 the `Maybe` monad to combine these functions." msgid "" "(Easy) Write a function `third` that returns the third element of an array " "with three or more elements. Your function should return an appropriate " @@ -27064,12 +26944,10 @@ msgid "" "from the `Data.Array` module in the `arrays` package. Use do notation with " "the `Maybe` monad to combine these functions." msgstr "" -"(簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてくださ" -"い。\n" +"(簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてください。\n" "関数は適切な`Maybe`型で返します。\n" -"*手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数" -"の型を見つけ出してください。\n" -"これらの関数を繋げるには`Maybe`モナドと共にdo記法を使ってください。" +"*手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数の型を見つけ出してください。\n" +"これらの関数を組み合わせるには`Maybe`モナドと共にdo記法を使ってください。" #. type: Bullet: ' 1. ' #: text/chapter8.md:312 @@ -27110,25 +26988,21 @@ msgstr "" #. type: Plain text #: text/chapter8.md:325 -#, fuzzy, 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" -#| " 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" +#, 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.\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 @@ -27186,11 +27060,10 @@ msgstr "" #. type: Plain text #: text/chapter8.md:345 -#, fuzzy, no-wrap -#| msgid " where the `Apply` instance uses the `ap` function defined above. Recall that `lift2` was defined as follows:\n" +#, no-wrap 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 @@ -27221,16 +27094,10 @@ msgstr "ネイティブな作用" #. type: Plain text #: text/chapter8.md:356 -#, fuzzy -#| msgid "" -#| "We will now look at one particular monad which is of central importance " -#| "in PureScript - the `Effect` monad." msgid "" "We will now look at one particular monad of central importance in PureScript " "– the `Effect` monad." -msgstr "" -"ここではPureScriptの中核となる重要なモナド、 `Effect`モナドについて見ていきま" -"す。" +msgstr "ここではPureScriptで中心的な重要性のあるモナドの1つ、`Effect`モナドについて見ていきます。" #. type: Plain text #: text/chapter8.md:358 @@ -27245,18 +27112,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:360 -#, fuzzy -#| msgid "" -#| "What are native side-effects? They are the side-effects which distinguish " -#| "JavaScript expressions from idiomatic PureScript expressions, which " -#| "typically are free from side-effects. Some examples of native effects are:" msgid "" "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" "ネイティブな作用の例を以下に示します。" @@ -27322,7 +27184,6 @@ msgstr "配列やリストで表現される多値関数" #. type: Plain text #: text/chapter8.md:380 -#, fuzzy 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 " @@ -27334,9 +27195,9 @@ msgid "" "is implemented at runtime." msgstr "" "これらの区別はわかりにくいので注意してください。\n" -"エラー文言は例外の形でJavaScriptの式の副作用となることがあります。\n" -"その意味では例外はネイティブな副作用を表していて、 `Effect`を使用して表現できます。\n" -"しかし、 `Either`を使用して実装されたエラー文言はJavaScript実行器の副作用ではなく、 `Effect`を使うスタイルでエラー文言を実装するのは適切ではありません。\n" +"例えば、エラー文言は例外の形でJavaScriptの式の副作用となることがあると言えます。\n" +"その意味では例外はネイティブな副作用を表していて、`Effect`を使用して表現できます。\n" +"しかし、`Either`を使用して実装されたエラー文言はJavaScript実行時の副作用ではなく、`Effect`を使うスタイルでエラー文言を実装するのは不適切です。\n" "そのため、ネイティブなのは作用自体というより、実行時にどのように実装されているかです。" #. type: Title ## @@ -27347,81 +27208,51 @@ msgstr "副作用と純粋性" #. type: Plain text #: text/chapter8.md:384 -#, fuzzy -#| msgid "" -#| "In a pure language like PureScript, one question which presents itself " -#| "is: without side-effects, how can one write useful real-world code?" msgid "" "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 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| 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." msgid "" "Values with side-effects have different types from pure values. As such, it " "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 -#, fuzzy -#| 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." msgid "" "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から実行することです。" +msgstr "`Effect`モナドで管理された副作用を現す手段は、型`Effect a`の計算をJavaScriptから実行することです。" #. type: Plain text #: text/chapter8.md:392 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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`モナドでの計算であることが要求されます。" +"Spagoビルドツール(や他のツール)は早道を用意しており、アプリケーションの起動時に`main`計算を呼び出すための追加のJavaScriptコードを生成します。\n" +"`main`は`Effect`モナドでの計算であることが要求されます。" #. type: Plain text #: text/chapter8.md:396 @@ -27434,45 +27265,23 @@ msgstr "" #. type: Plain text #: text/chapter8.md:398 -#, fuzzy -#| 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." msgid "" "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" -"`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコ" -"ンソールIOです。\n" -"`Unit`はいかなる*意味のある*データも返らないことを示しています。\n" -"`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられ" -"ます。" +"馴染みのある`log`関数から返る型を見てみましょう。\n" +"`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコンソールIOです。" #. type: Plain text #: text/chapter8.md:400 -#, fuzzy -#| 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." 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 "" -"馴染みのある`log`関数から返る型をもう少し見てみましょう。\n" -"`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコ" -"ンソールIOです。\n" "`Unit`はいかなる*意味のある*データも返らないことを示しています。\n" -"`Unit`はC、Javaなど他の言語での`void`キーワードと似たようなものとして考えられ" -"ます。" +"`Unit`はC、Javaなど他の言語での`void`キーワードと似たものとして考えられます。" #. type: Fenced code block (hs) #: text/chapter8.md:401 @@ -27571,13 +27380,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:439 -#, fuzzy, 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" +#, 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 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:441 @@ -27592,7 +27400,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:443 -#, fuzzy msgid "" "As mentioned previously, the `Effect` monad is of central importance to " "PureScript. The reason why it's central is that it is the conventional way " @@ -27608,20 +27415,17 @@ msgstr "" "なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りする上での常套手段だからです。\n" "`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕組みを提供します。\n" "`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように動作しどう使うのか理解することもまた極めて大事なことですので、実際にPureScriptで何か動かす前にその章を読まれることをお勧めします。\n" -"要は`Effect`モナドは結構単純なのです。幾つかの補助関数がありますが、それを差し置いても副作用を内包すること以外には大したことはしません。" +"要は`Effect`モナドは結構単純なのです。\n" +"幾つかの補助関数がありますが、副作用を内包すること以外には大したことはしません。" #. type: Plain text #: text/chapter8.md:447 -#, fuzzy -#| msgid "" -#| "Let's examine a function from the `node-fs` package that involves two " -#| "_native_ side effects: reading mutable state, and exceptions:" msgid "" "Let's examine a function from the `node-fs` package that involves two " "_native_ side effects: reading mutable state and exceptions:" msgstr "" -"2つの _ネイティブな_ 副作用が絡む`node-fs`パッケージの関数を調べましょう。こ" -"こでの副作用は可変状態の読み取りと例外です。" +"2つの*ネイティブな*副作用が絡む`node-fs`パッケージの関数を調べましょう。\n" +"ここでの副作用は可変状態の読み取りと例外です。" #. type: Fenced code block (hs) #: text/chapter8.md:448 @@ -27725,11 +27529,6 @@ msgstr "try :: forall a. Effect a -> Effect (Either Error a)\n" #. type: Plain text #: text/chapter8.md:495 -#, fuzzy -#| 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`." msgid "" "We can also generate our own exceptions. Here is an alternative " "implementation of `Data.List.head` that throws an exception if the list is " @@ -27823,7 +27622,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:524 -#, fuzzy 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 " @@ -27831,24 +27629,20 @@ msgid "" "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:526 -#, fuzzy -#| 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." 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 many small " "time steps." msgstr "" -"例を示します。小さな時間刻みで簡単な更新関数の実行を何度も繰り返すことによっ" -"て、重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。" +"例を示します。\n" +"重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。\n" +"これには小さな時間刻みで簡単な更新関数の実行を何度も繰り返します。" #. type: Plain text #: text/chapter8.md:528 @@ -27904,10 +27698,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:551 -#, fuzzy -#| msgid "" -#| "At the end of the computation, we read the final value of the reference " -#| "cell, and return the position of the particle." msgid "" "At the end of the computation, we read the final value of the reference cell " "and return the position of the particle." @@ -27916,21 +27706,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:553 -#, fuzzy -#| msgid "" -#| "Note that even though this function uses 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." msgid "" "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 program parts. We will see that this is exactly what the `ST` effect " "disallows." msgstr "" -"なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの" -"他の部分で使われるのが許されない限り、これは純粋な関数のままです。\n" -"`ST`作用が禁止するものが正確には何であるのかについては後ほど見ます。" +"なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの他の部分での使用が許されない限り、これは純粋な関数のままです。\n" +"このことが正に`ST`作用が禁止するものであることを見ていきます。" #. type: Plain text #: text/chapter8.md:555 @@ -27956,23 +27739,14 @@ msgstr "" #. type: Plain text #: text/chapter8.md:563 -#, fuzzy -#| 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!" 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 allows `run` to safely remove the " "`ST` effect and turn `simulate` into a pure function!" msgstr "" -"しかし、ひとたび参照領域が `new`によって作成されると、その領域の型は既に固定" -"されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エ" -"ラーになるでしょう。\n" -"`run`が安全に `ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由" -"なのです。" +"しかし、ひとたび参照領域が`new`によって作成されると、その領域の型は既に固定されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エラーになるでしょう。\n" +"`run`が安全に`ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由なのです。" #. type: Fenced code block (hs) #: text/chapter8.md:564 @@ -28072,20 +27846,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:610 -#, fuzzy -#| 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`:" msgid "" "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" -"`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになりま" -"す。" +"そうして、参照領域はそのスコープから逃れられないことと、安全に`ref`を`var`に変換できることにコンパイラが気付きます。\n" +"`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになります。" #. type: Fenced code block (javascript) #: text/chapter8.md:611 @@ -28139,12 +27906,12 @@ msgstr "" #. type: Plain text #: text/chapter8.md:637 -#, fuzzy, no-wrap +#, 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:639 @@ -28204,12 +27971,13 @@ msgstr "" #. type: Plain text #: text/chapter8.md:666 -#, fuzzy 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." -msgstr "局所的な変更可能状態を扱うとき、特に作用が絡むループを生成する`for`、 `foreach`、 `while`のような動作を一緒に使うときには、`ST`作用は短いJavaScriptを生成する良い方法となります。" +msgstr "" +"局所的な変更可能状態を扱うとき、`ST`作用は短いJavaScriptを生成する良い方法となります。\n" +"作用を持つ繰り返しを生成する`for`、`foreach`、`while`のような動作を一緒に使うときは特にそうです。" #. type: Bullet: '1. ' #: text/chapter8.md:672 @@ -28267,10 +28035,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:678 -#, fuzzy -#| msgid "" -#| "There are a number of PureScript packages for working directly with the " -#| "DOM, or with open-source DOM libraries. For example:" msgid "" "There are several PureScript packages for working directly with the DOM or " "open-source DOM libraries. For example:" @@ -28281,26 +28045,14 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:682 -#, fuzzy -#| msgid "" -#| "[`web-dom`](https://github.com/purescript-web/purescript-web-dom) " -#| "provides type definitions and low level interface implementations for the " -#| "W3C DOM spec." msgid "" "[`web-dom`](https://github.com/purescript-web/purescript-web-dom) provides " "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規格に向けた型定義と低水準インターフェース実装を提供します。" +msgstr "[`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3CのDOM規格に向けた型定義と低水準インターフェース実装を提供します。" #. type: Bullet: '- ' #: text/chapter8.md:682 -#, fuzzy -#| msgid "" -#| "[`web-html`](https://github.com/purescript-web/purescript-web-html) " -#| "provides type definitions and low level interface implementations for the " -#| "W3C HTML5 spec." msgid "" "[`web-html`](https://github.com/purescript-web/purescript-web-html) provides " "type definitions and low-level interface implementations for the W3C HTML5 " @@ -28320,23 +28072,15 @@ msgstr "" #. type: Plain text #: text/chapter8.md:684 -#, fuzzy -#| msgid "" -#| "There are also PureScript libraries which build abstractions on top of " -#| "these libraries, such as" msgid "" "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:688 -#, fuzzy -#| msgid "" -#| "[`thermite`](https://github.com/paf31/purescript-thermite), which builds " -#| "on [`react`](https://github.com/purescript-contrib/purescript-react)" msgid "" "[`thermite`](https://github.com/paf31/purescript-thermite) builds on " "[`react`](https://github.com/purescript-contrib/purescript-react)" @@ -28347,11 +28091,6 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:688 -#, fuzzy -#| msgid "" -#| "[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-" -#| "hooks), which builds on [`react-basic`](https://github.com/lumihq/" -#| "purescript-react-basic)" msgid "" "[`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-" "hooks) builds on [`react-basic`](https://github.com/lumihq/purescript-react-" @@ -28363,11 +28102,6 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:688 -#, fuzzy -#| msgid "" -#| "[`halogen`](https://github.com/purescript-halogen/purescript-halogen) " -#| "which provides a type-safe set of abstractions on top of a custom virtual " -#| "DOM library." msgid "" "[`halogen`](https://github.com/purescript-halogen/purescript-halogen) " "provides a type-safe set of abstractions on top of a custom virtual DOM " @@ -28424,7 +28158,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:698 -#, fuzzy msgid "" "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 " @@ -28433,8 +28166,8 @@ msgid "" "validation errors will be updated." msgstr "" "利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。\n" -"フォームには、様々なフィールド(姓、名前、都市、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。\n" -"テキストボックスに利用者がテキストを入力すると、検証エラーが更新されます。" +"フォームには、様々なフィールド(姓、名、市町村、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。\n" +"テキストボックスに利用者がテキストを入力する度に、検証エラーが更新されます。" #. type: Plain text #: text/chapter8.md:700 @@ -28482,17 +28215,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:712 -#, fuzzy -#| 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 " -#| "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/documentation/blob/master/ecosystem/Editor-and-tool-support." -#| "md#editors) that supports [`purs ide`](https://github.com/purescript/" -#| "purescript/tree/master/psc-ide) or are running [`pscid`](https://github." -#| "com/kRITZCREEK/pscid)." 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 " @@ -28515,16 +28237,10 @@ msgstr "" #. type: Plain text #: text/chapter8.md:714 -#, fuzzy -#| 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." msgid "" "In this Address Book app, you can enter some values into the form fields and " "see the validation errors printed onto the page." -msgstr "" -"このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上" -"に出力された検証エラーを見ることができるでしょう。" +msgstr "このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上で出力された検証エラーが見られます。" #. type: Plain text #: text/chapter8.md:716 @@ -28640,10 +28356,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:763 -#, fuzzy -#| 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`." 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`." @@ -28739,16 +28451,10 @@ msgstr "" #. type: Plain text #: text/chapter8.md:798 -#, fuzzy -#| msgid "" -#| "Next we'll examine some of the additional complexities of the full " -#| "Address Book component." msgid "" "Next, we'll examine some of the additional complexities of the full Address " "Book component." -msgstr "" -"次に完全なアドレス帳コンポーネントにある幾つかの複雑な事柄をもう少し調べてい" -"きます。" +msgstr "次に、完全なアドレス帳コンポーネントにある幾つかの複雑な事柄を調べていきます。" #. type: Plain text #: text/chapter8.md:800 @@ -28782,7 +28488,6 @@ msgstr "Tuple person setPerson <- useState examplePerson\n" #. type: Plain text #: text/chapter8.md:815 -#, fuzzy 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 " @@ -28875,12 +28580,6 @@ msgstr "`person`は各再描画の時点で現在の状態にアクセスする #. type: Plain text #: text/chapter8.md:845 -#, fuzzy -#| 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:" msgid "" "`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 " @@ -28905,8 +28604,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:852 -#, fuzzy -#| msgid "or as shorthand:" msgid "Or as shorthand:" msgstr "あるいは短かく以下です。" @@ -29024,14 +28721,6 @@ msgstr "" #. type: Plain text #: text/chapter8.md:897 -#, fuzzy -#| msgid "" -#| "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, converted to JSX. There are usually three variants " -#| "of each of these functions:" msgid "" "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." @@ -29040,11 +28729,10 @@ msgid "" "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:901 @@ -29183,19 +28871,13 @@ msgstr "targetValue :: EventFn SyntheticEvent (Maybe String)\n" #. type: Plain text #: text/chapter8.md:941 -#, fuzzy -#| 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." msgid "" "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:943 @@ -29267,20 +28949,16 @@ msgstr "" "`traverse_`の定義を調査して、両方の形式が確かに等価であることをご確認くださ" "い。" +# ここでのsourceはソースコードを意味していると思われます。 #. type: Plain text #: text/chapter8.md:971 -#, fuzzy -#| 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." msgid "" "That covers the basics of our component implementation. However, you should " "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:973 @@ -29310,14 +28988,13 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter8.md:980 -#, fuzzy msgid "" "(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:983 @@ -29332,10 +29009,11 @@ msgstr "" #. type: Plain text #: text/chapter8.md:985 -#, fuzzy, 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" +#, 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" +msgstr "" +" *手掛かり*:検証器によって返されるエラーの型を、エラーの原因となっているフィールドを示すために拡張するべきです。\n" +" 以下の変更されたエラー型を使うと良いでしょう。\n" #. type: Plain text #: text/chapter8.md:993 @@ -29375,8 +29053,7 @@ msgstr "" #. type: Plain text #: text/chapter8.md:1000 -#, fuzzy, no-wrap -#| msgid " You will need to write a function which extracts the validation error for a particular `Field` from the `Errors` structure.\n" +#, no-wrap 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" @@ -29390,56 +29067,40 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter8.md:1011 -#, fuzzy -#| 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 "`Monad`型クラスとdo記法との関係性に出会いました。" +msgstr "`Monad`型クラスとdo記法との関係性を見ました。" +# they allow usが訳せているかどうか…… #. type: Bullet: '- ' #: text/chapter8.md:1011 -#, fuzzy -#| msgid "" -#| "We introduced the monad laws, and saw how they allow us to transform code " -#| "written using do notation." msgid "" "We introduced the monad laws and saw how they allow us to transform code " "written using do notation." -msgstr "" -"モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。" +msgstr "モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。" +# monads can be usedが訳せているかどうか…… #. type: Bullet: '- ' #: text/chapter8.md:1011 -#, fuzzy -#| msgid "" -#| "We saw how monads can be used abstractly, to write code which works with " -#| "different side-effects." msgid "" "We saw how monads can be used abstractly to write code that works with " "different side-effects." -msgstr "" -"異なる副作用を扱うコードを書くために、モナドを抽象的に使う方法を見ました。" +msgstr "異なる副作用を扱うコードを書く上で、モナドを抽象的に使う方法を見ました。" #. type: Bullet: '- ' #: 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." -msgstr "" -"モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算" -"を可能にするのかということ、そして2つの手法の違いを説明しました。" +msgstr "モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算を可能にするのかということ、そして2つの手法の違いを説明しました。" #. type: Bullet: '- ' #: text/chapter8.md:1011 -#, fuzzy -#| msgid "" -#| "The concept of native effects was defined, and we met the `Effect` monad, " -#| "which is used to handle native side-effects." msgid "" "The concept of native effects was defined, and we met the `Effect` monad, " "which handles native side-effects." msgstr "" -"ネイティブな作用の概念を定義し、ネイティブな副作用を処理するために使用する " -"`Effect`モナドを導入しました。" +"ネイティブな作用の概念を定義し、`Effect`モナドを見ました。\n" +"これはネイティブな副作用を扱うものでした。" #. type: Bullet: '- ' #: text/chapter8.md:1011 diff --git a/translation/terms.txt b/translation/terms.txt index 07415ad5..768c646e 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -8,3 +8,4 @@ hash code: ハッシュコード。「ハッシュ値」とされていました context: 文脈。一般には単に「コンテキスト」とされるようです。 synonym: 同義語。 canvas: 固有名詞、HTML 5で導入された機能としてのCanvasは英単語として、一般名詞としては「キャンバス」と片仮名にします。 +pair: 組 From 93206ab4eec55468902f60d05526c3a03ec519a8 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Mon, 14 Aug 2023 09:23:25 +0900 Subject: [PATCH 14/29] [ update ] chapter 9 translation --- translation/ja.po | 175 ++++++++-------------------------------------- 1 file changed, 28 insertions(+), 147 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index 3b37f8ed..3b95d552 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-12 18:56+0900\n" +"PO-Revision-Date: 2023-08-15 06:48+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -29128,7 +29128,6 @@ msgstr "非同期作用" #. type: Plain text #: text/chapter9.md:6 -#, fuzzy msgid "" "This chapter focuses on the `Aff` monad, which is similar to the `Effect` " "monad, but represents _asynchronous_ side-effects. We'll demonstrate " @@ -29138,7 +29137,7 @@ msgid "" msgstr "" "この章では`Aff`モナドに集中します。\n" "これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。\n" -"ファイルシステムとやり取りしてHTTPリクエストを作る、非同期な例を実演していきます。\n" +"非同期にファイルシステムとやり取りしたりHTTPリクエストしたりする例を実演していきます。\n" "また非同期作用の直列ないし並列な実行の管理方法も押さえます。" #. type: Plain text @@ -29168,18 +29167,12 @@ msgstr "`parallel` - `Aff`の並列実行。" #. type: Plain text #: text/chapter9.md:17 -#, fuzzy -#| 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 " -#| "dependency in the `package.json` of this chapter. Install that by running:" 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 a " "dependency in the `package.json` of this chapter. Install that by running:" msgstr "" -"(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリは" -"`xhr2`NPMモジュールが必要です。\n" +"(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリには`xhr2`NPMモジュールが必要です。\n" "このモジュールはこの章の`package.json`中の依存関係に挙げられています。\n" "以下を走らせてインストールします。" @@ -29249,10 +29242,6 @@ msgstr "" #. type: Plain text #: text/chapter9.md:43 -#, fuzzy -#| msgid "" -#| "It is also possible to use callbacks or synchronous functions, but those " -#| "are less desireable because:" msgid "" "It is also possible to use callbacks or synchronous functions, but those are " "less desirable because:" @@ -29308,36 +29297,23 @@ msgstr "" #. type: Plain text #: text/chapter9.md:58 -#, fuzzy -#| 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` respectively), but those share the same downsides as discussed " -#| "earlier with JavaScript, and so that coding style is not recommended." 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`, " "respectively), but those share the same downsides as discussed earlier with " "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 -#, fuzzy -#| 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." 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." msgstr "" "`Aff`を扱う文法は`Effect`を扱うものと大変似ています。\n" -"どちらもモナドですし、したがってdo記法で書くことができます。" +"どちらもモナドですし、したがってdo記法で書けます。" #. type: Plain text #: text/chapter9.md:62 @@ -29406,10 +29382,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter9.md:90 -#, fuzzy -#| msgid "" -#| "(Easy) Write a `concatenateFiles` function which concatenates two text " -#| "files." msgid "" "(Easy) Write a `concatenateFiles` function that concatenates two text files." msgstr "" @@ -29418,17 +29390,12 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter9.md:92 -#, fuzzy -#| 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`." msgid "" "(Medium) Write a function `concatenateMany` to concatenate multiple text " "files, given an array of input and output file names. _Hint_: use `traverse`." msgstr "" -"(普通)入力ファイル名の配列と出力ファイル名が与えられたとき、複数のテキスト" -"ファイルを連結する関数`concatenateMany`を書いてください。\n" +"(普通)複数のテキストファイルを連結する関数`concatenateMany`を書いてください。\n" +"入力ファイル名の配列と出力ファイル名が与えられます。\n" "*手掛かり*:`traverse`を使ってください。" #. type: Bullet: ' 1. ' @@ -29449,23 +29416,14 @@ msgstr "更なるAffの資料" #. type: Plain text #: text/chapter9.md:98 -#, fuzzy -#| 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." msgid "" "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で何" -"らかの関数を見付けだす助けになるかもしれません。" +"もしまだ[公式のAffの手引き](https://pursuit.purescript.org/packages/purescript-aff/)を見ていなければ、今ざっと目を通してください。\n" +"この章の残りの演習を完了する上で事前に直接必要なことではありませんが、Pursuitで何らかの関数を見付けだす助けになるかもしれません。" #. type: Plain text #: text/chapter9.md:100 @@ -29500,18 +29458,6 @@ msgstr "HTTPクライアント" #. type: Plain text #: text/chapter9.md:107 -#, fuzzy -#| msgid "" -#| "The `affjax` library offers a convenient way to make asynchronous AJAX " -#| "HTTP 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:" msgid "" "The `affjax` library offers a convenient way to make asynchronous AJAX HTTP " "requests with `Aff`. Depending on what environment you are targeting, you " @@ -29519,32 +29465,11 @@ msgid "" "contrib/purescript-affjax-web) or the [purescript-affjax-node](https://" "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`を使いま" -"す。\n" -"より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript." -"org/packages/purescript-affjax)にあたってください。\n" -"以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例" -"です。" +"`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)のどちらかのライブラリを使う必要があります。" #. type: Plain text #: text/chapter9.md:110 -#, fuzzy -#| msgid "" -#| "The `affjax` library offers a convenient way to make asynchronous AJAX " -#| "HTTP 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:" msgid "" "In the rest of this chapter, we will be targeting node and thus using " "`purescript-affjax-node`. Consult the [Affjax docs](https://pursuit." @@ -29552,17 +29477,9 @@ msgid "" "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" -"対象としている環境が何であるかによって、[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`を使いま" -"す。\n" -"より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript." -"org/packages/purescript-affjax)にあたってください。\n" -"以下は与えられたURLに向けてHTTP GETを要求し、応答本文ないしエラー文言を返す例" -"です。" +"この章の以降ではnodeを対象としていくので、`purescript-affjax-node`を使います。\n" +"より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript.org/packages/purescript-affjax)にあたってください。\n" +"以下は与えられたURLに向けてHTTPのGET要求をして、応答本文ないしエラー文言を返す例です。" #. type: Fenced code block (hs) #: text/chapter9.md:111 @@ -29643,15 +29560,6 @@ msgstr "" #. type: Plain text #: text/chapter9.md:143 -#, fuzzy -#| 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 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:" msgid "" "The `parallel` package defines a type class `Parallel` for monads like " "`Aff`, which support parallel execution. When we met applicative functors " @@ -29660,12 +29568,9 @@ msgid "" "a correspondence between a monad `m` (such as `Aff`) and an applicative " "functor `f` that can be used to combine computations in parallel:" msgstr "" -"`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義して" -"おり、並列実行に対応しています。\n" -"以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリ" -"カティブ関手がどれほど便利なのかを見ました。\n" -"実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を合" -"成するために使われるアプリカティブ関手`f`との対応関係を定義しているのです。" +"`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義しており、並列実行に対応しています。\n" +"以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリカティブ関手がどれほど便利なのかを見ました。\n" +"実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を組み合わせるために使えるアプリカティブ関手`f`との対応関係を定義しているのです。" #. type: Fenced code block (hs) #: text/chapter9.md:144 @@ -29700,7 +29605,6 @@ msgstr "`sequential`:反対方向に変換します。" #. type: Plain text #: text/chapter9.md:156 -#, fuzzy msgid "" "The `aff` library provides a `Parallel` instance for the `Aff` monad. It " "uses mutable references to combine `Aff` actions in parallel by keeping " @@ -29708,9 +29612,9 @@ msgid "" "have been returned, we can compute the final result and pass it to the main " "continuation." msgstr "" -"`aff`ライブラリは `Aff`モナドの `Parallel`インスタンスを提供します。\n" -"これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に `Aff`動作を組み合わせます。\n" -"両方の結果が返されたら、最終結果を計算してメインの継続に渡すことができます。" +"`aff`ライブラリは`Aff`モナドの`Parallel`インスタンスを提供します。\n" +"これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に`Aff`動作を組み合わせます。\n" +"両方の結果が返されたら、最終結果を計算してメインの継続に渡せます。" #. type: Plain text #: text/chapter9.md:158 @@ -29727,21 +29631,15 @@ msgstr "" #. type: Plain text #: text/chapter9.md:160 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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:164 @@ -29847,11 +29745,6 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter9.md:204 -#, fuzzy -#| msgid "" -#| "(Easy) Write a `concatenateManyParallel` function which has the same " -#| "signature as the earlier `concatenateMany` function, but reads all input " -#| "files in parallel." msgid "" "(Easy) Write a `concatenateManyParallel` function with the same signature as " "the earlier `concatenateMany` function but reads all input files in parallel." @@ -29887,13 +29780,6 @@ msgstr "文字列の応答:時間制限を越える前に要求が成功した #. type: Bullet: '1. ' #: text/chapter9.md:210 -#, fuzzy -#| msgid "" -#| "(Difficult) Write a `recurseFiles` function which 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 some helpful functions for negotiating directories." msgid "" "(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 " @@ -29901,13 +29787,10 @@ msgid "" "directory of the file they appear in. _Hint:_ The `node-path` module has " "some helpful functions for negotiating directories." msgstr "" -"(難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして" -"一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてくださ" -"い。\n" +"(難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてください。\n" "一覧にあるファイルを並列に読んでください。\n" -"パスはそのファイルが表れたディレクトリから相対的なものです。\n" -"*手掛かり*:`node_path`モジュールにはディレクトリを扱う上で便利な関数がありま" -"す。" +"パスはそのファイルが現れたディレクトリから相対的なものです。\n" +"*手掛かり*:`node-path`モジュールにはディレクトリを扱う上で便利な関数があります。" #. type: Plain text #: text/chapter9.md:212 @@ -29965,10 +29848,8 @@ msgstr "[\"root.txt\",\"a.txt\",\"b/a.txt\",\"b/b.txt\",\"b/c/a.txt\",\"c/a/a.tx #. type: Plain text #: text/chapter9.md:241 -#, fuzzy -#| 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 "この章では非同期エフェクトと以下の方法を押さえました。" +msgstr "この章では非同期作用と以下の方法を押さえました。" #. type: Bullet: '- ' #: text/chapter9.md:244 From 0e95d832f65bffa8936fc165f1821211ff9577c2 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Thu, 17 Aug 2023 08:56:11 +0900 Subject: [PATCH 15/29] [ update ] chapter 10 translation * [ generate ] translation --- .po4a-version | 2 +- text-ja/chapter1.md | 8 +- text-ja/chapter10.md | 445 +++++++--------- text-ja/chapter3.md | 10 +- text-ja/chapter5.md | 4 +- text-ja/chapter6.md | 922 ++++++++++++++++++++++++++++++++ text-ja/chapter7.md | 824 +++++++++++++++++++++++++++++ text-ja/chapter8.md | 1174 +++++++++++++++++++++++++++++++++++++++++ text-ja/chapter9.md | 102 ++-- text-ja/index.md | 4 +- translation/ja.po | 701 +++++------------------- translation/terms.txt | 3 + 12 files changed, 3317 insertions(+), 882 deletions(-) create mode 100644 text-ja/chapter6.md create mode 100644 text-ja/chapter7.md create mode 100644 text-ja/chapter8.md 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/text-ja/chapter1.md b/text-ja/chapter1.md index 3a1a805a..a9a57a69 100644 --- a/text-ja/chapter1.md +++ b/text-ja/chapter1.md @@ -84,7 +84,7 @@ iterate f n x = iterate f (n - 1) (f x) 実際に、根本的に型駆動な抽象化の強力な形式である型クラスをPureScriptは提供しています。 この型クラスとは、関数型プログラミング言語Haskellによって有名になりました。 -## 多言語Webプログラミング +## 多言語webプログラミング 関数型プログラミングは成功を収めてきました。 特に成功している応用例を挙げると、データ解析、構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理といった具合に、枚挙に暇がありません。 @@ -169,7 +169,7 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 3 ``` -各章には演習が含まれており、それぞれ難易度も示されています。 +各章には演習が含まれており、難易度も示されています。 内容を完全に理解するために、各章の演習に取り組むことを強くお勧めします。 本書は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。 @@ -192,10 +192,10 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 - 非公式の[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コードの例が沢山あります。 diff --git a/text-ja/chapter10.md b/text-ja/chapter10.md index bf5f0fc0..917260e7 100644 --- a/text-ja/chapter10.md +++ b/text-ja/chapter10.md @@ -2,9 +2,9 @@ ## この章の目標 -This chapter will introduce PureScript's _foreign function interface_ (or -_FFI_), which enables communication from PureScript code to JavaScript code -and vice versa. We will cover how to: +本章ではPureScriptの*外部関数インターフェース* (foreign function interface; *FFI*) を紹介します。 +これによりPureScriptコードからJavaScriptコードへの呼び出し、及びその逆が可能になります。 +以下の方法を押さえていきます。 - 純粋で、作用のある、非同期なJavaScript関数をPureScriptから呼び出す。 - 型付けされていないデータを扱う。 @@ -16,19 +16,16 @@ and vice versa. We will cover how to: - 利用者にポップアップ通知で警告する。 - フォームのデータを直列化してブラウザのローカルストレージに保存し、アプリケーションが再起動したときにそれを再読み込みする -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: +さらに一般にはそこまで重用されない幾つかの追加の話題を押さえた補遺もあります。 +ご自由にこれらの節を読んで構いませんが、学習目標にあまり関係しなければ、本書の残りを読み進める妨げにならないようにしてください。 - 実行時のPureScriptの値の表現を理解する。 - JavaScriptからPureScriptを呼び出す。 ## プロジェクトの準備 -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 -source files from those chapters. +このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。 +そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれています。 この章は`argonaut`ライブラリを依存関係として導入しています。 このライブラリはJSONにエンコードしたりJSONをデコードしたりするために使います。 @@ -41,18 +38,14 @@ test`を走らせることによって`test/Main.purs`中の単体試験につ ## 免責事項 -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 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. +JavaScriptの扱いをできる限り単純にするため、PureScriptは直感的な外部関数インターフェースを提供しています。 +しかし、FFIはこの言語の*応用的な*機能であることには心に留めておかれると良いでしょう。 +安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現について理解していなければなりません。 +この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝授することを目指します。 -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 -of foreign code. Code in the standard libraries tends to favor the latter -approach. +PureScriptのFFIはとても柔軟に設計されています。 +実際には、外部関数にとても単純な型を与えるか、型システムを利用して外部のコードの誤った使い方を防ぐようにするか、開発者が選べるようになっています。 +標準ライブラリのコードは、後者の手法を採る傾向にあります。 簡単な例としては、JavaScriptの関数で戻り値が `null`にならないことは保証できません。 実のところ、JavaScriptらしさのあるコードはかなり頻繁に `null`を返します。 @@ -76,7 +69,8 @@ node> encodeURIComponent('Hello World') 'Hello%20World' ``` -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. +この関数は関数の型`String -> String`について適切な実行時表現を持っています。 +`null`でない文字列を取って`null`でない文字列にするもので、副作用を持たないからです。 次のような外部インポート宣言を使うと、この関数に型を割り当てることができます。 @@ -84,12 +78,10 @@ This function has the correct runtime representation for the function type `Stri {{#include ../exercises/chapter10/test/URI.purs}} ``` -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 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 `_encodeURIComponent`: +インポートしてくるための外部JavaScriptモジュールを書く必要もあります。 +対応する外部JavaScriptモジュールは、同名で拡張子が`.purs`から`.js`に変わったものです。 +上のPureScriptモジュールが`URI.purs`として保存されているなら、外部JavaScriptモジュールを`URI.js`として保存します。 +`encodeURIComponent`は既に定義されているので、`_encodeURIComponent`としてエクスポートせねばなりません。 ```javascript {{#include ../exercises/chapter10/test/URI.js}} @@ -145,9 +137,9 @@ $ spago repl {{#include ../exercises/chapter10/test/Examples.purs:diagonal}} ``` -Recall that functions in PureScript are _curried_. `diagonal` is a function -that takes a `Number` and returns a _function_ that takes a `Number` and -returns a `Number`. +PureScriptの関数は*カリー化*されていることを思い出してください。 +`diagonal`は`Number`を取って*関数*を返す関数です。 +そして返された関数は`Number`を取って`Number`を返します。 ```js {{#include ../exercises/chapter10/test/Examples.js:diagonal}} @@ -199,11 +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`をインポートしました。 -We can then call it with `runFn2`, which takes the uncurried function and -then the arguments. +そうして`runFn2`を使って呼び出せます。 +これはカリー化されていない関数と引数を取るものです。 ```text $ spago repl @@ -218,11 +210,10 @@ $ spago repl ## カリー化されていない関数についての補足 -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 -code, it is sometimes necessary to define uncurried JavaScript functions -which accept multiple arguments. +PureScriptのカリー化された関数には勿論利点があります。 +部分的に関数を適用でき、関数型に型クラスインスタンスを与えられるのです。 +しかし効率上の代償も付いてきます。 +効率性が決定的に重要なコードでは時々、多変数を受け付けるカリー化されていないJavaScript関数を定義する必要があります。 PureScriptでカリー化されていない関数を作ることもできます。 2引数の関数については`mkFn2`関数が使えます。 @@ -254,8 +245,8 @@ var uncurriedSum = uncurriedAdd(3, 10); {{#include ../exercises/chapter10/test/Examples.purs:curried_add}} ``` -And the resulting generated code, which is less compact due to the nested -functions: +そして生成結果のコードが以下です。 +入れ子の関数のため比較的簡潔ではありません。 ```javascript var curriedAdd = function (n) { @@ -269,19 +260,13 @@ var curriedSum = curriedAdd(3)(10); ## 現代的なJavaScriptの構文についての補足 -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 browser. +前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しすればIE11)と互換性がありません。 +執筆時点でwebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことができないと推計](https://caniuse.com/#feat=arrow-functions)されています。 -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. +ほとんどの利用者にとって互換性があるようにするため、PureScriptコンパイラによって生成されるJavaScriptコードは矢印関数を使っていません。 +また、同じ理由で**公開するライブラリでも矢印関数を避ける**ことが推奨されます。 -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. +それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程でES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/babel#intro)などのツールを含めると良いでしょう。 ES6の矢印関数がより読みやすく感じたら[Lebab](https://github.com/lebab/lebab)のようなツールを使ってコンパイラの`output`ディレクトリにJavaScriptのコードを変換できます。 @@ -320,10 +305,8 @@ Record | Object `String`と`Number`という原始型の例は既に見てきました。 ここから`Array`や`Record`(JavaScriptでは`Object`)といった構造的な型を眺めていきます。 -To demonstrate passing `Array`s, here's how to call a JavaScript function -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. +`Array`を渡すところを実演するために、以下に`Int`の`Array`を取って別の配列として累計の和を返すJavaScriptの関数の呼び出し方を示します。 +前にありましたが、JavaScriptは`Int`のための分離した型を持たないため、PureScriptでの`Int`と`Number`は両方共JavaScriptでの`Number`に翻訳されます。 ```hs foreign import cumulativeSums :: Array Int -> Array Int @@ -349,10 +332,8 @@ $ spago repl [1,3,6] ``` -To demonstrate passing `Records`, here's how to call a JavaScript function -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: +`Record`を渡すところを実演するために、以下に2つの`Complex`な数をレコードとして取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。 +PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意してください。 ```hs type Complex = { @@ -380,11 +361,10 @@ $ spago repl { imag: 6.0, real: 4.0 } ``` -Note that the above techniques require trusting that JavaScript will return -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. +なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要があります。 +PureScriptはJavaScriptのコードに型検査を適用できないからです。 +この型安全性の配慮について後のJSONの節でより詳しく解説していきます。 +型の不整合から身を守る手法についても押さえます。 ## 演習 @@ -457,14 +437,13 @@ maybeHead arr = maybeHeadImpl Just Nothing arr forall a. (forall x. x -> Maybe x) -> (forall x. Maybe x) -> Array a -> Maybe a ``` -And not: +以下ではないことに注意です。 ```hs forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a ``` -While both forms work, the latter is more vulnerable to unwanted inputs in -place of `Just` and `Nothing`. +どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に対してより脆弱です。 例えば、比較的脆い方では、以下のように呼び出せるでしょう。 @@ -474,15 +453,15 @@ maybeHeadImpl (\_ -> Just 1000) (Just 1000) [1,2,3] これは如何なる配列の入力に対しても`Just 1000`を返します。 -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). +この脆弱性では、`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)`であり、後者は唯一残っている脆弱性になるのです。 ## 外部型の定義 -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`. +`Maybe a`を返す代わりに`arr[0]`を返したいのだとしましょう。 +型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する型がほしいです。 +この型を`Undefined a`と呼びましょう。 _外部インポート宣言_ を使うと、*外部型* (foreign type) を定義できます。構文は外部関数を定義するのと似ています。 @@ -496,7 +475,7 @@ foreign import data Undefined :: Type -> Type この場合は`Undefined`の種が `Type -> Type`であると宣言しています。 言い換えれば`Undefined`は型構築子です。 -We can now reuse our original definition for `head`: +これで元の`head`の定義を再利用できます。 ```javascript export const undefinedHead = arr => @@ -509,12 +488,12 @@ PureScriptモジュールには以下を追加します。 foreign import undefinedHead :: forall a. Array a -> Undefined a ``` -The body of the `undefinedHead` function returns `arr[0]`, which may be -`undefined`, and the type signature correctly reflects that fact. +`undefinedHead`関数の本体は`undefined`かもしれない`arr[0]`を返します。 +そしてこの型シグネチャはその事実を正しく反映しています。 -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! +この関数はその型の適切な実行時表現を持っていますが、型`Undefined a`の値を使用する方法がないので、全く役に立ちません。 +いや、言い過ぎました。 +別のFFIでこの型を使えますからね。 値が未定義かどうかを教えてくれる関数を書くことができます。 @@ -536,11 +515,9 @@ isEmpty :: forall a. Array a -> Boolean isEmpty = isUndefined <<< undefinedHead ``` -Here, the foreign function we defined is very simple, which means we can -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. +このように、定義したこの外部関数はとても単純です。 +つまりPureScriptの型検査器を使うことによる利益が最大限得られるのです。 +一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理はPureScriptコードへ移動しておくことをお勧めします。 ## 例外 @@ -595,13 +572,11 @@ export const unsafeHead = arr => { ## 型クラスメンバー関数を使う -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. +つい先程までFFI越しに`Maybe`の構築子を渡す手引きをしましたが、今回はJavaScriptを呼び出すPureScriptを書く別の場合です。 +JavaScriptの呼び出しでも続けざまにPureScriptの関数を呼び出します。 +ここでは型クラスのメンバー関数をFFI越しに渡す方法を探ります。 -We start with writing a foreign JavaScript function that expects the -appropriate instance of `show` to match the type of `x`. +型`x`に合う適切な`show`のインスタンスを期待する外部JavaScript関数を書くことから始めます。 ```js export const boldImpl = show => x => @@ -614,14 +589,14 @@ export const boldImpl = show => x => foreign import boldImpl :: forall a. (a -> String) -> a -> String ``` -And a wrapper function that passes the correct instance of `show`: +そして`show`の正しいインスタンスを渡す梱包関数も書きます。 ```hs bold :: forall a. Show a => a -> String bold x = boldImpl show x ``` -Alternatively, in point-free form: +代えてポイントフリー形式だとこうです。 ```hs bold :: forall a. Show a => a -> String @@ -688,8 +663,7 @@ yell :: forall a. Show a => a -> Effect Unit yell = yellImpl show ``` -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. +REPLで試すと文字列が(引用符で囲まれず)直接コンソールに印字され`unit`値が返ることがわかります。 ```text $ spago repl @@ -705,11 +679,9 @@ unit これらは既に見た`Data.Function.Uncurried`の梱包`Fn`に似ています。 これらの梱包があればカリー化されていない作用のある関数をPureScriptで呼び出すことができます。 -You'd generally only use these if you want to call existing JavaScript -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 wouldn't find that in the existing JavaScript ecosystem. +一般的にこれらを使うのは、こうしたAPIをカリー化された関数に包むのではなく、既存のJavaScriptライブラリのAPIを直接呼び出したいときぐらいです。 +したがってカリー化していない`yell`の例を見せてもあまり意味がありません。 +というのもJavaScriptがPureScriptの型クラスのメンバーに依っているからで、更にそれは既存のJavaScriptの生態系にそのメンバーが見付からないためです。 翻って以前の`diagonal`の例を変更し、結果を返すことに加えてログ出力を含めるとこうなります。 @@ -784,9 +756,8 @@ unit done waiting ``` -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. +REPLでの非同期ログ出力はブロック全体が実行を終了するまで印字を待機する点に注意しましょう。 +このコードを`spago test`で走らせた場合、印字の*合間に*僅かな遅延があり、より予測に近い挙動をします。 他にプロミスから値を返す例を見てみましょう。 この関数は`async`と`await`を使って書かれていますが、これはプロミスの糖衣構文に過ぎません。 @@ -833,10 +804,10 @@ unit ## JSON -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 -passing structural data over the FFI. +アプリケーションでJSONを使うことには多くの理由があります。 +例えばwebのAPIと疎通するよくある手段であるためです。 +この節では他の用例についてもお話ししましょう。 +構造的なデータをFFI越しに渡す場合に型安全性を向上させる手法から始めます。 少し前のFFI関数`cumulativeSums`と`addComplex`を再訪し、それぞれに1つバグを混入させてみましょう。 @@ -860,8 +831,7 @@ export const addComplexBroken = a => b => { }; ``` -We can use the original type signatures, and the code will still compile, -despite the incorrect return types. +実際は返る型が正しくないのですが、元々の型シグネチャを使うことができ、依然としてコードはコンパイルされます。 ```hs foreign import cumulativeSumsBroken :: Array Int -> Array Int @@ -907,7 +877,7 @@ PureScriptのコードにバグ一匹通さないようにするため、JavaScr `argonaut`ライブラリにはこのために必要なJSONのデコードとエンコードの機能が備わっています。 このライブラリには素晴らしい[ドキュメント](https://github.com/purescript-contrib/purescript-argonaut#documentation)があるので、本書では基本的な用法だけを押さえます。 -返る型を`Json`として定義するようにして、代わりとなる外部インポートをつくるとこうなります。 +返る型を`Json`として定義するようにして、代わりとなる外部インポートを作るとこうなります。 ```hs foreign import cumulativeSumsJson :: Array Int -> Json @@ -1026,13 +996,20 @@ Map String Int JsonDecodeError (Set v)`です。 なお、`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。 コンパイラが導いてくれます。 -1. (Medium) Rewrite the earlier `quadraticRoots` function as - `quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON - (instead of as a `Pair`). -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. -_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". -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. -1. (Medium) The following data type represents a binary tree with values at the leaves: +1. (普通)少し前の`quadraticRoots`関数を書き換えて`quadraticRootSet`としてください。 + この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返します。 +1. (難しい)少し前の`quadraticRoots`関数を書き換えて`quadraticRootsSafe`としてください。 + この関数はJSONを使って`Complex`の根の`Pair`をFFI越しに渡します。 + JavaScriptでは`Pair`構築子を使わないでください。 + その代わり、デコーダーに互換性のある形式で対を返すだけにしてください。 + *手掛かり*:`DecodeJson`インタンスを`Pair`用に書く必要があるでしょう。 + 独自のデコードインスタンスを書く上での説明については[argonautのドキュメント](https://github.com/purescript-contrib/purescript-argonaut-codecs/tree/main/docs#writing-new-instances)をあたってください。 + [decodeJsonTuple](https://github.com/purescript-contrib/purescript-argonaut-codecs/blob/master/src/Data/Argonaut/Decode/Class.purs)インスタンスも参考になるかもしれません。 + 「孤立インスタンス」を作ることを避けるために、`Pair`に`newtype`の梱包が必要になる点に注意してください。 +1. (普通)2次元配列を含むJSON文字列を構文解析してデコードする`parseAndDecodeArray2D :: String -> Either String (Array (Array Int))`関数を書いてください。 + 例えば`"[[1, 2, 3], [4, 5], [6]]"`です。 + *手掛かり*:デコードの前に`jsonParser`を使って`String`を`Json`に変換する必要があるでしょう。 +1. (普通)以下のデータ型は値が葉にある二分木を表現します。 ```haskell data Tree a @@ -1057,16 +1034,15 @@ _Hint_: You'll need to write a `DecodeJson` instance for `Pair`. Consult the [ar ## 住所録 -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: +この節では新しく獲得したFFIとJSONの知識を応用して、第8章の住所録の例を構築していきたいと思います。 +以下の機能を加えていきます。 - 保存ボタンをフォームの一番下に配置し、クリックしたときにフォームの状態をJSONに直列化してローカルストレージに保存します。 - ページの再読み込み時にローカルストレージからJSON文書を自動的に取得します。 フォームのフィールドにはこの文書の内容を入れます。 - フォームの状態を保存したり読み込んだりするのに問題があればポップアップの警告を出します。 -`Effect.Storage`モジュールに以下のWebストレージAPIのためのFFIの梱包をつくることから始めていきます。 +`Effect.Storage`モジュールに以下のwebストレージAPIのためのFFIの梱包を作ることから始めていきます。 - `setItem`はキーと値(両方とも文字列)を受け取り、指定されたキーでローカルストレージに値を格納する計算を返します。 - `getItem`はキーを取り、ローカルストレージから関連付けられたバリューの取得を試みます。 @@ -1125,10 +1101,9 @@ validateAndSave = do Data.Argonaut.Encode.Class.EncodeJson PhoneType ``` -This is because `PhoneType` in the `Person` record needs an `EncodeJson` -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: +これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンスを必要としているからです。 +また、ついでに汎用のエンコードインスタンスとデコードインスタンスを導出していきます。 +この仕組みについての詳細情報はargonautのドキュメントにあります。 ```hs {{#include ../exercises/chapter10/src/Data/AddressBook.purs:import}} @@ -1146,12 +1121,10 @@ argonaut docs: item <- getItem "person" ``` -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. +そうしてローカルストレージ由来の文字列から`Person`レコードへ変換する補助関数を作ります。 +なお、このストレージ中の文字列は`null`かもしれないので、正常に`String`としてデコードされるまでは外部の`Json`として表現します。 +道中には他にも多くの変換工程があり、それぞれで`Either`の値を返します。 +そのためこれらをまとめて`do`ブロックの中に纏めるのは理に適っています。 ```hs processItem :: Json -> Either String Person @@ -1161,9 +1134,9 @@ processItem item = do decodeJson j ``` -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. +そうしてこの結果が成功しているかどうか調べます。 +もし失敗していればエラーをログ出力し、既定の`examplePerson`を使います。 +そうでなければローカルストレージから取得した人物を使います。 ```hs initialPerson <- case processItem item of @@ -1189,7 +1162,7 @@ mkAddressBookApp = Tuple person setPerson <- useState props.initialPerson ``` -仕上げとして、それぞれの`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向上させます。 +仕上げとして、各`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向上させます。 ```hs processItem :: Json -> Either String Person @@ -1199,17 +1172,17 @@ processItem item = do lmap ("Cannot decode Person: " <> _) $ decodeJson j ``` -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. +最初のエラーのみがこのアプリの通常の操作内で起こります。 +他のエラーはwebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。 +どのようにJSON文字列を変更したかが、どのエラーを引き起こすかを決定します。 +各エラーを引き起こせるかご確認ください。 -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. +これでローカルストレージについては押さえました。 +次に`alert`動作を実装していきます。 +この動作は`Effect.Console`モジュールの`log`動作に似ています。 +唯一の相違点は`alert`動作が`window.alert`メソッドを使うことで、対して`log`動作は`console.log`メソッドを使っています。 +そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができます。 +webブラウザなどです。 ```hs foreign import alert :: String -> Effect Unit @@ -1245,19 +1218,15 @@ alert $ "Error: " <> err <> ". Loading examplePerson" ## まとめ -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 -using the FFI: +この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。 +また、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。 - 外部関数が正しい表現を持っていることを確かめる重要性を見てきました。 -- 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. +- 外部型や`Json`データ型を使用することによって、null値やJavaScriptの他の型のデータのような特殊な場合に対処する方法を学びました。 - 安全にJSONデータを直列化・直列化復元する方法を見ました。 -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. +より多くの例については、GitHubの`purescript`組織、`purescript-contrib`組織、及び`purescript-node`組織が、FFIを使用するライブラリの例を多数提供しています。 +残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾つか見ていきます。 ## 補遺 @@ -1289,10 +1258,9 @@ import Test from 'Test.js'; Test.gcd(15)(20); ``` -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`. +ここでは`spago build`でコンパイルされていることを前提としています。 +SpagoはPureScriptモジュールをESモジュールにコンパイルするものです。 +そのため、`import`を使って`Test`モジュールをインポートした後、`Test`オブジェクトの`gcd`関数を参照できました。 `spago bundle-app`や`spago bundle-module`コマンドを使って生成されたJavaScriptを単一のファイルにまとめることもできます。 @@ -1300,10 +1268,9 @@ bundle-module`コマンドを使って生成されたJavaScriptを単一のフ ### 名前の生成を理解する -PureScript aims to preserve names during code generation as much as -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. +PureScriptはコード生成時にできるだけ名前を保持することを目指します。 +とりわけ、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存されることが期待できます。 +少なくとも最上位で宣言される名前についてはそうです。 識別子としてJavaScriptのキーワードを使う場合は、名前は2重のドル記号でエスケープされます。 例えば次のPureScriptコードを考えてみます。 @@ -1312,7 +1279,7 @@ top-level declarations. null = [] ``` -Generates the following JavaScript: +これは以下のJavaScriptを生成します。 ```javascript var $$null = []; @@ -1325,24 +1292,21 @@ var $$null = []; example' = 100 ``` -Generates the following JavaScript: +これは以下のJavaScriptを生成します。 ```javascript var example$prime = 100; ``` -Where compiled PureScript code is intended to be called from JavaScript, it -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. +コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めします。 +ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。 ### 実行時のデータ表現 -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 -mean? In PureScript, it means that the type of an expression should be -compatible with its representation at runtime. +型はプログラムがある意味で「正しい」ことをコンパイル時に論証できるようにします。 +つまり、その点については壊れることがありません。 +しかし、これは何を意味するのでしょうか。 +PureScriptでは、式の型は実行時の表現と互換性があることを意味します。 そのため、PureScriptとJavaScriptコードを一緒に効率的に使用できるように、実行時のデータ表現について理解することが重要です。 これはつまり、与えられた任意のPureScriptの式について、その値が実行時にどのように評価されるかという挙動を理解できるべきだということです。 @@ -1355,43 +1319,38 @@ compatible with its representation at runtime. つまり、型 `Boolean`の式は `true`もしくは `false`のどちらか一方の(JavaScriptの)値へと評価されます。 特に`null`や `undefined`に評価される型`Boolean`なPureScriptの式はありません。 -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`. +`Int`や`Number`や`String`の型の式についても似た法則が成り立ちます。 +`Int`や`Number`型の式はnullでないJavaScriptの数へと評価されますし、`String`型の式はnullでないJavaScriptの文字列へと評価されます。 +`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式は実行時に整数に評価されます。 -What about `Unit`? Well, since `Unit` has only one inhabitant (`unit`) and -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`). +`Unit`についてはどうでしょうか。 +`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何で表現されるかは重要ではありません。 +古いコードは`{}`を使って表現する傾向がありました。 +しかし比較的新しいコードでは`undefined`を使う傾向にあります。 +なので、`Unit`を表現するのに使うものは何であれ差し支えありませんが、`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を返します)。 もっと複雑な型についてはどうでしょうか。 -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. +既に見てきたように、PureScriptの関数は引数が1つのJavaScriptの関数に対応しています。 +厳密に言えばこうなります。 +ある型`a`と`b`について、式`f`の型が`a -> b`で、式`x`が型`a`についての適切な実行時表現の値へと評価されるとします。 +このとき`f`はJavaScriptの関数へと評価されますが、この関数は`x`を評価した結果に`f`を適用すると型`b`の適切な実行時表現を持ちます。 +単純な例としては、`String -> String`型の式は、nullでないJavaScript文字列からnullでないJavaScript文字列への関数へと評価されます。 -As you might expect, PureScript's arrays correspond to JavaScript -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 -type `a`. +ご想像の通り、PureScriptの配列はJavaScriptの配列に対応しています。 +しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っていることは覚えておいてください。 +具体的には、もしPureScriptの式`e`が何らかの型`a`について型`Array +a`を持つなら、`e`は(nullでない)JavaScript配列へと評価されます。 +この配列の全ての要素は型`a`の適切な実行時表現を持ちます。 -We've already seen that PureScript's records evaluate to JavaScript -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. +PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てきました。 +関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールド中のデータの実行時の表現について論証できます。 +勿論、レコードのフィールドは、同じ型である必要はありません。 ### ADTの表現 -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 that create new JavaScript objects -based on those prototypes. +代数的データ型の全ての構築子について、PureScriptコンパイラは関数を定義することで新たなJavaScriptオブジェクト型を作成します。 +これらの構築子はプロトタイプに基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。 例えば次のような単純なADTを考えてみましょう。 @@ -1416,25 +1375,25 @@ 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`関数を生成します。 -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 a curried function of -two arguments. For example, this algebraic data type: +1引数より多く取る構築子についてはどうでしょうか。 +その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成します。 +ただしこの場合、補助関数は2引数のカリー化された関数です。 +例えば次のような代数的データ型を考えます。 ```haskell data Two a b = Two a b ``` -Generates this JavaScript code: +このコードからは、次のようなJavaScriptコードが生成されます。 ```javascript function Two(value0, value1) { @@ -1449,23 +1408,19 @@ Two.create = function (value0) { }; ``` -Here, values of the object type `Two` can be created using the `new` keyword -or by using the `Two.create` function. +ここで、オブジェクト型`Two`の値はキーワード`new`または`Two.create`関数を使用すると作成できます。 -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 -the same as its argument type. +newtypeの場合はまた少し異なります。 +newtypeは代数的データ型のようなもので、単一の引数を取る単一の構築子を持つよう制限されていたことを思い出してください。 +この場合、newtypeの実行時表現は、その引数の型と同じになります。 -For example, this newtype represents telephone numbers is represented as a -JavaScript string at runtime: +例えば、以下の電話番号を表すnewtypeは実行時にJavaScriptの文字列として表現されます。 ```haskell newtype PhoneNumber = PhoneNumber String ``` -This is useful for designing libraries since newtypes provide an additional -layer of type safety without the runtime overhead of another function call. +newtypeは、関数呼び出しによる実行時のオーバーヘッドなく更なる型安全性のための層を提供するため、ライブラリを設計するのに便利です。 ### 量化された型の表現 @@ -1494,12 +1449,11 @@ identity a = a 量化された型 `forall a. t`の実行時表現はどうなっているのでしょうか。さて、この型の実行時表現を持つ任意の式は、型 `a`をどのように選んでも型 `t`の適切な実行時表現を持っていなければなりません。上の例では、型 `forall a. a -> a`の関数は、 `String -> String`、 `Number -> Number`、 `Array Boolean -> Array Boolean`などといった型について、適切な実行時表現を持っていなければなりません。 これらは、文字列から文字列、数から数の関数でなくてはなりません。 -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 -argument in its implementation. This additional condition prevents -problematic implementations such as the following JavaScript function from -inhabiting a polymorphic type: +しかし、それだけでは充分ではありません。 +量化された型の実行時表現は、これよりも更に厳しいものです。 +任意の式が*パラメトリック多相的*であることを要求しています。 +つまり、その実装において、引数の型についてのどんな情報も使うことができないのです。 +この追加の条件は、以下のJavaScriptの関数のような問題のある実装が多相型に現住することを防止します。 ```javascript function invalid(a) { @@ -1511,26 +1465,23 @@ function invalid(a) { } ``` -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`. +確かにこの関数は文字列を取って文字列を返し、数を取って数を返す、といったものです。 +しかしこの関数は追加条件を満たしていません。 +引数の実行時の型を調べており、型`forall a. a -> a`の正しい現住にはならないからです。 -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`. +関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけです。 +したがって`id`は確かに`forall a. a -> a`の唯一の現住なのです。 -A full discussion of _parametric polymorphism_ and _parametricity_ is beyond -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), so this -representation of polymorphic data is appropriate. +*パラメトリック多相*と*パラメトリック性*についての詳しい議論は本書の範囲を超えています。 +ただ、PureScriptの型は実行時に*消去*されており、PureScriptの多相関数は(FFIを使わない限り)引数の実行時表現を検査*できない*ため、この多相的なデータの表現が適切になっているという点にはご留意ください。 ### 制約のある型の表現 -Functions with a type class constraint have an interesting representation at -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. +型クラス制約を持つ関数は、実行時に面白い表現を持っています。 +関数の挙動はコンパイラによって選ばれた型クラスのインスタンスに依存する可能性があるため、関数には*型クラス辞書*と呼ばれる追加の引数が与えられます。 +この辞書には選ばれたインスタンスから提供される型クラスの関数の実装が含まれます。 -For example, here is a simple PureScript function with a constrained type -that uses the `Show` type class: +例えば以下は、`Show`型クラスを使う制約付きの型を持つ、単純なPureScript関数です。 ```haskell shout :: forall a. Show a => a -> String @@ -1574,11 +1525,10 @@ shout(showNumber)(42); ### 副作用の表現 -The `Effect` monad is also defined as a foreign type. Its runtime -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`. +`Effect`モナドも外部型として定義されています。 +その実行時表現はとても単純です。 +型`Effect a`の式は**引数なしの**JavaScript関数へと評価されます。 +この関数はあらゆる副作用を実行し、型`a`の適切な実行時表現を持つ値を返します。 `Effect`型構築子の定義は、 `Effect`モジュールで次のように与えられています。 @@ -1598,10 +1548,9 @@ foreign import random :: Effect Number export const random = Math.random; ``` -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, -returns it, and the return value matches the runtime representation of the -`Number` type: it is a non-null JavaScript number. +`random`関数は実行時には引数なしの関数として表現されていることに注目してください。 +この関数は乱数生成という副作用を実行して返しますが、返り値は`Number`型の実行時表現と一致します。 +`Number`型はnullでないJavaScriptの数です。 もう少し興味深い例として、`console`パッケージ中の`Effect.Console`モジュールで定義された `log`関数を考えてみましょう。 `log`関数は次の型を持っています。 @@ -1632,5 +1581,5 @@ import { main } from 'Main' main(); ``` -When using `spago bundle-app --to` or `spago run`, this call to `main` is -generated automatically whenever the `Main` module is defined. +`spago bundle-app --to`または`spago +run`を使用する場合、`Main`モジュールが定義されている場合は常に、この`main`の呼び出しを自動的に生成できます。 diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md index 1a7e1dd7..bf771dd8 100644 --- a/text-ja/chapter3.md +++ b/text-ja/chapter3.md @@ -126,7 +126,7 @@ forall a b c. (a -> b -> c) -> b -> a -> c forall a b. a -> b -> a ``` -ファイルのトップレベルでは、等号の直前に引数を指定することで関数を定義できます。 +ファイルの最上位では、等号の直前に引数を指定することで関数を定義できます。 ```haskell add :: Int -> Int -> Int @@ -279,9 +279,9 @@ PureScriptで新たな問題に取り組むときは、まずはこれから扱 ## 型構築子と種 -`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`に*適用*されたもので、項目のリストを表しています。 @@ -323,7 +323,7 @@ PureScriptの _種システム_ は他にも面白い種に対応しています それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。 まずは関数に型を与えることから始めます。 型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくようにすると良いでしょう。 -実際、トップレベルの宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。 +実際、最上位の宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。 型宣言は関数の名前とその型を `::`記号で区切るようにして書きます。 ```haskell diff --git a/text-ja/chapter5.md b/text-ja/chapter5.md index bcae3047..748adc52 100644 --- a/text-ja/chapter5.md +++ b/text-ja/chapter5.md @@ -129,7 +129,7 @@ true 数式\\( n! / k! (n - k)! \\)を使ってください。 ここで \\( ! \\) は前に書いた階乗関数です。 *手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。 - 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、コーナーケースを更に追加してみてください。 + 長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、特殊な場合を更に追加してみてください。 1. (普通)[_パスカルの法則_](https://en.wikipedia.org/wiki/Pascal%27s_rule)を使って前の演習と同じ2項係数を計算する関数`pascal`を書いてください。 ## 配列パターン @@ -651,7 +651,7 @@ $ spago repl 累算関数`combine`は`where`ブロックで定義されています。 `combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の -`Shape`を引数にとり、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。 +`Shape`を引数に取り、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。 `shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。 ## 演習 diff --git a/text-ja/chapter6.md b/text-ja/chapter6.md new file mode 100644 index 00000000..4ed2f1d2 --- /dev/null +++ b/text-ja/chapter6.md @@ -0,0 +1,922 @@ +# 型クラス + +## この章の目標 + +この章では、PureScriptの型システムにより可能になっている強力な抽象化の形式を導入します。 +そう、型クラスです。 + +データ構造をハッシュ化するためのライブラリを本章の動機付けの例とします。 +データ自体の構造について直接考えることなく複雑な構造のデータのハッシュ値を求める上で、型クラスの仕組みがどのように働くかを見ていきます。 + +また、PureScriptのPreludeや標準ライブラリに含まれる、標準的な型クラスも見ていきます。PureScriptのコードは概念を簡潔に表現するために型クラスの強力さに大きく依存しているので、これらのクラスに慣れておくと役に立つでしょう。 + +オブジェクト指向の方面から入って来た方は、「クラス」という単語がそれまで馴染みのあるものとこの文脈とでは _かなり_ +異なるものを意味していることに注意してください。 + +## プロジェクトの準備 + +この章のソースコードは、ファイル `src/data/Hashable.purs`で定義されています。 + +このプロジェクトには以下の依存関係があります。 + +- `maybe`: 省略可能な値を表す `Maybe`データ型が定義されています。 +- `tuples`: 値の組を表す `Tuple`データ型が定義されています。 +- `either`: 非交和を表す `Either`データ型が定義されています。 +- `strings`: 文字列を操作する関数が定義されています。 +- `functions`: PureScriptの関数を定義するための補助関数が定義されています。 + +モジュール `Data.Hashable`では、これらのパッケージによって提供されるモジュールの幾つかをインポートしています。 + +## 見せて! + +型クラスの最初の簡単な例は、既に何回か見たことがある関数で提供されています。 +`show`は何らかの値を取り、文字列として表示する関数です。 + +`show`は `Prelude`モジュールの `Show`と呼ばれる型クラスで次のように定義されています。 + +```haskell +class Show a where + show :: a -> String +``` + +このコードでは、型変数 `a`でパラメータ化された、`Show`という新しい _型クラス_ (type class) を宣言しています。 + +型クラス _インスタンス_ には、型クラスで定義された関数の、その型に特殊化された実装が含まれています。 + +例えば、Preludeにある `Boolean`値に対する `Show`型クラスインスタンスの定義は次の通りです。 + +```haskell +instance Show Boolean where + show true = "true" + show false = "false" +``` + +このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。 +PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインスタンスに名前を付けられます。 +このとき、`Boolean`型は*`Show`型クラスに属している*といいます。 + +PSCiで、いろいろな型の値を`Show`型クラスを使って表示してみましょう。 + +```text +> import Prelude + +> show true +"true" + +> show 1.0 +"1.0" + +> show "Hello World" +"\"Hello World\"" +``` + +この例では様々な原始型の値を `show`しましたが、もっと複雑な型を持つ値も`show`できます。 + +```text +> import Data.Tuple + +> show (Tuple 1 true) +"(Tuple 1 true)" + +> import Data.Maybe + +> show (Just "testing") +"(Just \"testing\")" +``` + +`show`の出力は、REPLに(あるいは`.purs`ファイルに)貼り戻せば、表示されたものを再作成できるような文字列であるべきです。 +以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出すものであり、引用符なしに文字列が表示されます。 +`unit`の表示は無視してください。 +第8章で`log`のような`Effect`を調べるときに押さえます。 + +```text +> import Effect.Console + +> logShow (Tuple 1 true) +(Tuple 1 true) +unit + +> logShow (Just "testing") +(Just "testing") +unit +``` + +型 `Data.Either`の値を表示しようとすると、興味深いエラー文言が表示されます。 + +```text +> import Data.Either +> show (Left 10) + +The inferred type + + forall a. Show a => String + +has type variables which are not mentioned in the body of the type. Consider adding a type annotation. +``` + +ここでの問題は `show`しようとしている型に対する +`Show`インスタンスが存在しないということではなく、PSCiがこの型を推論できなかったということです。 +これは推論された型で*未知の型*`a`とされていることが示しています。 + +`::`演算子を使って式に註釈を付け、、PSCiが正しい型クラスインスタンスを選べるようにできます。 + +```text +> show (Left 10 :: Either Int String) +"(Left 10)" +``` + +`Show`インスタンスを全く持っていない型もあります。 +関数の型 `->`がその一例です。 +`Int`から `Int`への関数を `show`しようとすると、型検証器によってその旨のエラー文言が表示されます。 + +```text +> import Prelude +> show $ \n -> n + 1 + +No type class instance was found for + + Data.Show.Show (Int -> Int) +``` + +型クラスインスタンスは次の2つのうち何れかの形で定義されます。 +型クラスが定義されている同じモジュールで定義するか、型クラスに「属して」いる型と同じモジュールで定義するかです。 +これらとは別の場所で定義されるインスタンスは[「孤立インスタンス」](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#orphan-instances)と呼ばれ、PureScriptコンパイラでは許されていません。 +この章の演習の幾つかでは、その型の型クラスインスタンスを定義できるように、型の定義を自分の`MySolutions`モジュールに複製する必要があります。 + +## 演習 + +1. (簡単)`Show`インスタンスを`Point`に定義してください。 + 前の章の`showPoint`関数と同じ出力に一致するようにしてください。 + *補足*:`Point`はここでは(`type`同義語ではなく)`newtype`です。 + そのため`show`の仕方を変えられます。 + こうでもしないとレコードへの既定の`Show`インスタンスから逃れられません。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Point}} + ``` + +## よく見かける型クラス + +この節では、Preludeや標準ライブラリで定義されている標準的な型クラスを幾つか見ていきましょう。 +これらの型クラスはPureScript特有の抽象化をする上で多くのよくあるパターンの基礎を形成しています。 +そのため、これらの関数の基本についてよく理解しておくことを強くお勧めします。 + +### Eq + +`Eq`型クラスは`eq`関数を定義しています。 +この関数は2つの値について等値性を調べます。 +実は`==`演算子は`eq`の別名です。 + +```haskell +class Eq a where + eq :: a -> a -> Boolean +``` + +何れにせよ、2つの引数は同じ型を持つ必要があります。 +異なる型の2つの値を等値性に関して比較しても意味がありません。 + +PSCiで `Eq`型クラスを試してみましょう。 + +```text +> 1 == 2 +false + +> "Test" == "Test" +true +``` + +### Ord + +`Ord`型クラスは`compare`関数を定義します。 +この関数は2つの値を比較するのに使えるもので、その値の型は順序付けに対応したものです。 +比較演算子`<`、`>`と厳密な大小比較ではない`<=`、`>=`は`compare`を用いて定義されます。 + +*補足*:以下の例ではクラスシグネチャに`<=`が含まれています。 +この文脈での`<=`の使われ方はEqがOrdの上位クラスであり、比較演算子としての`<=`の用途を表す意図はありません。 +後述の[上位クラス](#上位クラス)の節を参照してください。 + +```haskell +data Ordering = LT | EQ | GT + +class Eq a <= Ord a where + compare :: a -> a -> Ordering +``` + +`compare`関数は2つの値を比較して`Ordering`を返します。 +これには3つ選択肢があります。 + +- `LT`- 最初の引数が2番目の値より小さいとき。 +- `EQ`- 最初の引数が2番目の値と等しいとき。 +- `GT`- 最初の引数が2番目の値より大きいとき。 + +ここでも`compare`関数についてPSCiで試してみましょう。 + +```text +> compare 1 2 +LT + +> compare "A" "Z" +LT +``` + +### Field + +`Field`型クラスは加算、減算、乗算、除算などの数値演算子に対応した型を示します。 +これらの演算子を抽象化して提供されているので、適切な場合に再利用できるのです。 + +> *補足*:型クラス`Eq`ないし`Ord`とちょうど同じように、`Field`型クラスはPureScriptコンパイラで特別に扱われ、`1 + 2 * 3`のような単純な式は単純なJavaScriptへと変換されます。 +> 型クラスの実装に基いて呼び出される関数呼び出しとは対照的です。 + +```haskell +class EuclideanRing a <= Field a +``` + +`Field`型クラスは、幾つかのより抽象的な*上位クラス*が組み合わさってできています。 +このため、`Field`の操作の全てを提供しているわけではないが、その一部を提供する型について抽象的に説明できます。 +例えば、自然数の型は加算及び乗算については閉じていますが、減算については必ずしも閉じていません。 +そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタンスですが、`Ring`や`Field`のインスタンスではありません。 + +上位クラスについては、この章の後半で詳しく説明します。 +しかし、全ての[数値型クラスの階層](https://a-guide-to-the-purescript-numeric-hierarchy.readthedocs.io/en/latest/introduction.html)([チートシート](https://harry.garrood.me/numeric-hierarchy-overview/))について述べるのはこの章の目的から外れています。 +この内容に興味のある読者は`prelude`内の `Field`に関するドキュメントを参照してください。 + +### 半群とモノイド + +`Semigroup`(半群)型クラスは、2つの値を連結する演算子 `append`を提供する型を示します。 + +```haskell +class Semigroup a where + append :: a -> a -> a +``` + +文字列は普通の文字列連結について半群をなし、配列も同様です。 +その他の標準的なインスタンスは`prelude`パッケージで提供されています。 + +以前に見た `<>`連結演算子は、 `append`の別名として提供されています。 + +(`prelude`パッケージで提供されている)`Monoid`型クラスには`mempty`という名前の空の値の概念があり、`Semigroup`型クラスを拡張します。 + +```haskell +class Semigroup m <= Monoid m where + mempty :: m +``` + +ここでも文字列や配列はモノイドの簡単な例になっています。 + +ある型にとっての`Monoid`型クラスインスタンスとは、「空」の値から始めて新たな結果に組み合わせ、その型を持つ結果を*累算*する方法を記述するものです。 +例えば、畳み込みを使って何らかのモノイドの値の配列を連結する関数を書けます。 +PSCiで以下の通りです。 + +```haskell +> import Prelude +> import Data.Monoid +> import Data.Foldable + +> foldl append mempty ["Hello", " ", "World"] +"Hello World" + +> foldl append mempty [[1, 2, 3], [4, 5], [6]] +[1,2,3,4,5,6] +``` + +`prelude`パッケージにはモノイドと半群の多くの例を提供しており、以降もこれらを本書で扱っていきます。 + +### Foldable + +`Monoid`型クラスが畳み込みの結果になるような型を示す一方、`Foldable`型クラスは畳み込みの元のデータとして使えるような型構築子を示しています。 + +また、 `Foldable`型クラスは配列や +`Maybe`などの幾つかの標準的なコンテナのインスタンスを含む`foldable-traversable`パッケージで提供されています。 + +`Foldable`クラスに属する関数の型シグネチャは、これまで見てきたものよりも少し複雑です。 + +```haskell +class Foldable f where + foldr :: forall a b. (a -> b -> b) -> b -> f a -> b + foldl :: forall a b. (b -> a -> b) -> b -> f a -> b + foldMap :: forall a m. Monoid m => (a -> m) -> f a -> m +``` + +`f`を配列の型構築子として特殊化すると分かりやすいです。 +この場合、任意の`a`について`f a`を`Array +a`に置き換えられますが、そうすると`foldl`と`foldr`の型が、最初に配列に対する畳み込みで見た型になると気付きます。 + +`foldMap`についてはどうでしょうか。 +これは `forall a m. Monoid m => (a -> m) -> Array a -> m`になります。 +この型シグネチャでは、型`m`が`Monoid`型クラスのインスタンスであれば、返り値の型として任意に選べると書かれています。 +配列の要素をそのモノイドの値へと変える関数を与えられれば、そのモノイドの構造を利用して配列上で累算し、1つの値にして返せます。 + +それではPSCiで `foldMap`を試してみましょう。 + +```text +> import Data.Foldable + +> foldMap show [1, 2, 3, 4, 5] +"12345" +``` + +ここでは文字列用のモノイドと`show`関数を選んでいます。 +前者は文字列を連結するもので、後者は`Int`を文字列として書き出すものです。 +そうして数の配列を渡すと、それぞれの数を`show`して1つの文字列へと連結した結果を得ました。 + +しかし畳み込み可能な型は配列だけではありません。 +`foldable-traversable`では`Maybe`や`Tuple`のような型にも`Foldable`インスタンスが定義されており、`lists`のような他のライブラリでは、各々のデータ型に対して`Foldable`インスタンスが定義されています。 +`Foldable`は*順序付きコンテナ*の概念を見据えたものなのです。 + +### 関手と型クラス則 + +PureScriptでは、副作用を伴う関数型プログラミングのスタイルを可能にするための型クラスの集まりも定義されています。 +`Functor`や`Applicative`、`Monad`といったものです。 +これらの抽象化については後ほど本書で扱いますが、ここでは`Functor`型クラスの定義を見てみましょう。 +既に`map`関数の形で見たものです。 + +```haskell +class Functor f where + map :: forall a b. (a -> b) -> f a -> f b +``` + +`map`関数(別名`<$>`)は関数をそのデータ構造まで「持ち上げる」(lift) ことができます。 +ここで「持ち上げ」という言葉の具体的な定義は問題のデータ構造に依りますが、既に幾つかの単純な型についてその動作を見てきました。 + +```text +> import Prelude + +> map (\n -> n < 3) [1, 2, 3, 4, 5] +[true, true, false, false, false] + +> import Data.Maybe +> import Data.String (length) + +> map length (Just "testing") +(Just 7) +``` + +`map`演算子は様々な構造の上でそれぞれ異なる挙動をしますが、 `map`演算子の意味はどのように理解すればいいのでしょうか。 + +直感的には、 `map`演算子はコンテナのそれぞれの要素へ関数を適用し、その結果から元のデータと同じ形状を持った新しいコンテナを構築するものとできます。 +しかし、この着想を精密にするにはどうしたらいいでしょうか。 + +`Functor`の型クラスのインスタンスは、*関手則*と呼ばれる法則を順守するものと期待されています。 + +- `map identity xs = xs` +- `map g (map f xs) = map (g <<< f) xs` + +最初の法則は _恒等射律_ (identity law) +です。これは、恒等関数(引数を変えずに返す関数)をその構造まで持ち上げると、元の構造をそのまま返すという意味です。恒等関数は入力を変更しませんから、これは理にかなっています。 + +第2の法則は*合成律*です。 +構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。 + +「持ち上げ」の一般的な意味が何であれ、データ構造に対する持ち上げ関数の正しい定義はこれらの法則に従っていなければなりません。 + +標準の型クラスの多くには、このような法則が付随しています。 +一般に、型クラスに与えられた法則は、型クラスの関数に構造を与え、普遍的にインスタンスについて調べられるようにします。 +興味のある読者は、既に見てきた標準の型クラスに属する法則について調べてみてもよいでしょう。 + +### インスタンスの導出 + +インスタンスを手作業で描く代わりに、ほとんどの作業をコンパイラにさせることができます。 +この[型クラス導出手引き](https://github.com/purescript/documentation/blob/master/guides/Type-Class-Deriving.md)を見てください。 +そちらの情報が以下の演習を解く手助けになることでしょう。 + +## 演習 + +(簡単)次のnewtypeは複素数を表します。 + +```haskell +{{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Complex}} +``` + +1. (簡単)`Complex`に`Show`インスタンスを定義してください。 + 出力の形式はテストで期待される形式と一致させてください(例:`1.2+3.4i`、`5.6-7.7i`など)。 + +2. (簡単)`Eq`インスタンスを`Complex`に導出してください。 + *補足*:代わりにこのインスタンスを手作業で書いてもよいですが、しなくていいのになぜすることがありましょう。 + +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`に導出してください。 + *補足*:代わりにこのインスタンスを手作業で書くこともできますが、そう手軽にはできません。 + + 以下は前章からの`Shape`のADTです。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Shape}} + ``` + +5. (普通)(`Generic`を介して)`Show`インスタンスを`Shape`に導出してください。 + コードの量はどのくらいになりましたか。 + また、前の章の`showShape`と比較して`String`の出力はどうなりましたか。 + *手掛かり*:[型クラス導出](https://github.com/purescript/documentation/blob/master/guides/Type-Class-Deriving.md)手引きの[`Generic`から導出する](https://github.com/purescript/documentation/blob/master/guides/Type-Class-Deriving.md#deriving-from-generic)節を見てください。 + +## 型クラス制約 + +型クラスを使うと、関数の型に制約を加えられます。 +例を示しましょう。 +`Eq`型クラスインスタンスを使って定義された等値性を使って、3つの値が等しいかどうかを調べる関数を書きたいとします。 + +```haskell +threeAreEqual :: forall a. Eq a => a -> a -> a -> Boolean +threeAreEqual a1 a2 a3 = a1 == a2 && a2 == a3 +``` + +この型宣言は `forall`を使って定義された通常の多相型のようにも見えます。 +しかし、二重線矢印 `=>`で型の残りの部分から区切られた、型クラス制約 (type class constraint) `Eq a`があります。 + +インポートされたモジュールのどれかに `a`に対する `Eq`インスタンスが存在するなら、どんな型 `a`を選んでも +`threeAsEqual`を呼び出すことができる、とこの型は言っています。 + +制約された型には複数の型クラスインスタンスを含めることができますし、インスタンスの型は単純な型変数に限定されません。 `Ord`と +`Show`のインスタンスを使って2つの値を比較する例を次に示します。 + +```haskell +showCompare :: forall a. Ord a => Show a => a -> a -> String +showCompare a1 a2 | a1 < a2 = + show a1 <> " is less than " <> show a2 +showCompare a1 a2 | a1 > a2 = + show a1 <> " is greater than " <> show a2 +showCompare a1 a2 = + show a1 <> " is equal to " <> show a2 +``` + +`=>`シンボルを複数回使って複数の制約を指定できることに注意してください。 +複数の引数のカリー化された関数を定義するのと同様です。 +しかし、2つの記号を混同しないように注意してください。 + +- `a -> b`は _型_ `a`から _型_ `b`への関数の型を表します。 +- 一方で、`a => b`は _制約_ `a`を型`b`に適用します。 + +PureScriptコンパイラは、型の注釈が提供されていない場合、制約付きの型を推論しようとします。これは、関数に対してできる限り最も一般的な型を使用したい場合に便利です。 + +PSCiで `Semiring`のような標準の型クラスの何れかを使って、このことを試してみましょう。 + +```text +> import Prelude + +> :type \x -> x + x +forall a. Semiring a => a -> a +``` + +ここで、この関数に`Int -> Int`または`Number -> Number`と註釈を付けることはできます。 +しかし、PSCiでは最も一般的な型が`Semiring`で動作することが示されています。 +こうすると`Int`と`Number`の両方で関数を使えます。 + +## インスタンスの依存関係 + +制約された型を使うと関数の実装が型クラスインスタンスに依存できるように、型クラスインスタンスの実装は他の型クラスインスタンスに依存できます。これにより、型を使ってプログラムの実装を推論するという、プログラム推論の強力な形式を提供します。 + +`Show`型クラスを例に考えてみましょう。 +それぞれの要素を `show`する方法がある限り、その要素の配列を `show`する型クラスインスタンスを書くことができます。 + +```haskell +instance Show a => Show (Array a) where + ... +``` + +型クラスインスタンスが複数の他のインスタンスに依存する場合、括弧で囲んでそれらのインスタンスをコンマで区切り、それを`=>`シンボルの左側に置くことになります。 + +```haskell +instance (Show a, Show b) => Show (Either a b) where + ... +``` + +これらの2つの型クラスインスタンスは `prelude`ライブラリにあります。 + +プログラムがコンパイルされると、`Show`の正しい型クラスのインスタンスは `show`の引数の推論された型に基づいて選ばれます。 +選択されたインスタンスが沢山のそうしたインスタンスの関係に依存しているかもしれませんが、このあたりの複雑さに開発者が関与することはありません。 + +## 演習 + +1. (簡単)以下の宣言では型 `a`の要素の空でない配列の型を定義しています。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:NonEmpty}} + ``` + + `Eq a`と`Eq (Array a)`のインスタンスを再利用し、型`NonEmpty`に`Eq`インスタンスを書いてください。 + *補足*:代わりに`Eq`インスタンスを導出できます。 + +1. (普通)`Array`の`Semigroup`インスタンスを再利用して、`NonEmpty`への`Semigroup`インスタンスを書いてください。 + +1. (普通)`NonEmpty`に`Functor`インスタンスを書いてください。 + +1. (普通)`Ord`のインスタンス付きの任意の型`a`が与えられているとすると、新しくそれ以外のどんな値よりも大きい「無限の」値を付け加えられます。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Extended}} + ``` + + `a`への`Ord`インスタンスを再利用して、`Extended a`に`Ord`インスタンスを書いてください。 + +1. (難しい)`NonEmpty`に`Foldable`インスタンスを書いてください。 + *手掛かり*:配列への`Foldable`インスタンスを再利用してください。 + +1. (難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持っている)ような型構築子 + `f`が与えられたとき、追加の要素を先頭に含める新たなコンテナ型を作れます。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:OneMore}} + ``` + + このコンテナ `OneMore f`もまた順序を持っています。 + ここで、新しい要素は任意の `f`の要素よりも前にきます。 + この `OneMore f`の `Foldable`インスタンスを書いてみましょう。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:OneMore_Foldable}} + ... + ``` + +1. (普通)`nubEq`関数を使い、配列から重複する`Shape`を削除する`dedupShapes :: Array Shape -> Array + Shape`関数を書いてください。 + +1. (普通)`dedupShapesFast`関数を書いてください。 + `dedupShapes`とほぼ同じですが、より効率の良い`nub`関数を使います。 + +## 多変数型クラス + +型クラスが引数として1つの型だけを取れるのかというと、そうではありません。 +その場合がほとんどですが、型クラスは*ゼロ個以上の*型変数を持てます。 + +それでは2つの型引数を持つ型クラスの例を見てみましょう。 + +```haskell +module Stream where + +import Data.Array as Array +import Data.Maybe (Maybe) +import Data.String.CodeUnits as String + +class Stream stream element where + uncons :: stream -> Maybe { head :: element, tail :: stream } + +instance Stream (Array a) a where + uncons = Array.uncons + +instance Stream String Char where + uncons = String.uncons +``` + +この `Stream`モジュールでは、要素のストリームのような型を示すクラス `Stream`が定義されています。 +`uncons`関数を使ってストリームの先頭から要素を取り出すことができます。 + +`Stream`型クラスは、ストリーム自身の型だけでなくその要素の型も型変数として持っていることに注意してください。これによって、ストリームの型が同じでも要素の型について異なる型クラスインスタンスを定義できます。 + +このモジュールでは2つの型クラスインスタンスが定義されています。 +`uncons`がパターン照合で配列の先頭の要素を取り除くような配列のインスタンスと、文字列から最初の文字を取り除くような文字列のインスタンスです。 + +任意のストリーム上で動作する関数を記述できます。 +例えば、ストリームの要素に基づいて `Monoid`に結果を累算する関数は次のようになります。 + +```haskell +import Prelude +import Data.Monoid (class Monoid, mempty) + +foldStream :: forall l e m. Stream l e => Monoid m => (e -> m) -> l -> m +foldStream f list = + case uncons list of + Nothing -> mempty + Just cons -> f cons.head <> foldStream f cons.tail +``` + +PSCiで使って、異なる `Stream`の型や異なる `Monoid`の型について `foldStream`を呼び出してみましょう。 + +## 関数従属性 + +多変数型クラスは非常に便利ですが、紛らわしい型や型推論の問題にも繋がります。 +単純な例として、上記で与えられた`Stream`クラスを使い、ストリームに対して汎用的な`tail`関数を書くことを考えてみましょう。 + +```haskell +genericTail xs = map _.tail (uncons xs) +``` + +これはやや複雑なエラー文言を出力します。 + +```text +The inferred type + + forall stream a. Stream stream a => stream -> Maybe stream + +has type variables which are not mentioned in the body of the type. Consider adding a type annotation. +``` + +エラーは、 `genericTail`関数が `Stream`型クラスの定義で言及された +`element`型を使用しないので、その型は未解決のままであることを指しています。 + +更に残念なことに、特定の型のストリームに`genericTail`を適用できません。 + +```text +> map _.tail (uncons "testing") + +The inferred type + + forall a. Stream String a => Maybe String + +has type variables which are not mentioned in the body of the type. Consider adding a type annotation. +``` + +ここでは、コンパイラが `streamString`インスタンスを選択することを期待しています。 +結局のところ、 `String`は `Char`のストリームであり、他の型のストリームであってはなりません。 + +コンパイラは自動的にそう推論できず、`streamString`インスタンスに目が向きません。 +しかし、型クラス定義に手掛かりを追加すると、コンパイラを補助できます。 + +```haskell +class Stream stream element | stream -> element where + uncons :: stream -> Maybe { head :: element, tail :: stream } +``` + +ここで、 `stream -> element`は _関数従属性_ (functional dependency) と呼ばれます。関数従属性は、多変数型クラスの型引数間の関数関係を宣言します。この関数の依存関係は、ストリーム型から(一意の)要素型への関数があることをコンパイラに伝えるので、コンパイラがストリーム型を知っていれば要素の型を割り当てられます。 + +この手掛かりがあれば、コンパイラが上記の汎用的な尾鰭関数の正しい型を推論するのに充分です。 + +```text +> :type genericTail +forall stream element. Stream stream element => stream -> Maybe stream + +> genericTail "testing" +(Just "esting") +``` + +多変数の型クラスを使用して何らかのAPIを設計する場合、関数従属性が便利なことがあります。 + +## 型変数のない型クラス + +ゼロ個の型変数を持つ型クラスさえも定義できます。 +これらは関数に対するコンパイル時の表明に対応しており、型システム内においてそのコードの大域的な性質を把握できます。 + +重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあります。 +`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。 +この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。 +そのため配列が空のときに失敗する可能性があります。 + +```haskell +head :: forall a. Partial => Array a -> a + +tail :: forall a. Partial => Array a -> Array a +``` + +`Partial`モジュールの `Partial`型クラスのインスタンスを定義していないことに注意してください。 +こうすると目的を達成できます。 +このままの定義では `head`関数を使用しようとすると型エラーになるのです。 + +```text +> head [1, 2, 3] + +No type class instance was found for + + Prim.Partial +``` + +代わりに、これらの部分関数を利用する全ての関数で `Partial`制約を再発行できます。 + +```haskell +secondElement :: forall a. Partial => Array a -> a +secondElement xs = head (tail xs) +``` + +前章で見た`unsafePartial`関数を使用し、部分関数を通常の関数として(不用心に)扱うことができます。この関数は +`Partial.Unsafe`モジュールで定義されています。 + +```haskell +unsafePartial :: forall a. (Partial => a) -> a +``` + +`Partial`制約は関数の矢印の左側の括弧の中に現れますが、外側の `forall`では現れません。 +つまり、 `unsafePartial`は部分的な値から通常の値への関数です。 + +```text +> unsafePartial head [1, 2, 3] +1 + +> unsafePartial secondElement [1, 2, 3] +2 +``` + +## 上位クラス + +インスタンスを別のインスタンスに依存させることによって型クラスのインスタンス間の関係を表現できるように、いわゆる*上位クラス*を使って型クラス間の関係を表現できます。 + +あるクラスのどんなインスタンスも、別のクラスのインスタンスである必要があるとき、後者の型クラスは前者の型クラスの上位クラスであるといいます。 +そしてクラス定義で逆向きの太い矢印 (`<=`) を使って上位クラス関係を示します。 + +[既に上位クラスの関係の例を目にしました](#ord)。 +`Eq`クラスは`Ord`の上位クラスですし、`Semigroup`クラスは`Monoid`の上位クラスです。 +`Ord`クラスの全ての型クラスインスタンスについて、その同じ型に対応する `Eq`インスタンスが存在しなければなりません。 +これは理に適っています。 +多くの場合、`compare`関数が2つの値の大小を付けられないと報告した時は、同値であるかを判定するために`Eq`クラスを使うことでしょう。 + +一般に、下位クラスの法則が上位クラスの構成要素に言及しているとき、上位クラス関係を定義するのは筋が通っています。 +例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インスタンスの下で同値であるなら、`compare`関数は`EQ`を返すはずだと推定するのは理に適っています。 +言い換えれば、`a == b`が真であるのは`compare a b`が厳密に`EQ`に評価されるときなのです。 +法則のレベルでのこの関係は、`Eq`と`Ord`の間の上位クラス関係の正当性を示します。 + +上位クラス関係を定義する別の理由となるのは、この2つのクラスの間に明白な "is-a" の関係があることです。 +下位クラスの全ての構成要素は、上位クラスの構成要素でもあるということです。 + +## 演習 + +1. (普通)部分関数`unsafeMaximum :: Partial => Array Int -> Int`を定義してください。 + この関数は空でない整数の配列の最大値を求めます。 + `unsafePartial`を使ってPSCiで関数を試してください。 + *手掛かり*:`Data.Foldable`の`maximum`関数を使います。 + +1. (普通)次の `Action`クラスは、ある型の別の型での動作を定義する、多変数型クラスです。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Action}} + ``` + + *動作*とは、他の型の値を変更する方法を決めるために使われるモノイドな値を記述する関数です。 + `Action`型クラスには2つの法則があります。 + + - `act mempty a = a` + - `act (m1 <> m2) a = act m1 (act m2 a)` + + 空の動作を提供しても何も起こりません。 + そして2つの動作を連続で適用することは結合した動作を適用することと同じです。 + つまり、動作は`Monoid`クラスで定義される操作に倣っています。 + + 例えば自然数は乗算のもとでモノイドを形成します。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Multiply}} + + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:semigroupMultiply}} + + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:monoidMultiply}} + ``` + + この動作を実装するインスタンスを書いてください。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Multiply_Action}} + ... + ``` + + インスタンスが上で挙げた法則を見たさなくてはならないことを思い出してください。 + +1. (難しい)`Action Multiply Int`のインスタンスを実装するには複数の方法があります。 + どれだけ思い付きますか。 + PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える必要があるでしょう。 + *補足*:テストでは4つの実装を押さえています。 + +1. (普通)入力の文字列を何回か繰り返す`Action`インスタンスを書いてください。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:actionMultiplyString}} + ... + ``` + + *手掛かり*:Pursuitでシグネチャが[`String -> Int -> String`](https://pursuit.purescript.org/search?q=String%20-%3E%20Int%20-%3E%20String)の補助関数を検索してください。 + なお、`String`は(`Monoid`のような)より汎用的な型として現れます。 + + このインスタンスは上に挙げた法則を満たすでしょうか。 + +1. (普通)インスタンス `Action m a => Action m (Array a)`を書いてみましょう。 + ここで、 配列上の動作はそれぞれの要素を独立に実行するものとして定義されます。 + +1. (難しい)以下のnewtypeが与えらえているとき、`Action m (Self m)`のインスタンスを書いてください。 + ここでモノイド`m`はそれ自体が持つ`append`を用いて動作します。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Self}} + ``` + + *補足*:テストフレームワークでは`Self`と`Multiply`型に`Show`と`Eq`インスタンスが必要になります。 + 手作業でこれらのインスタンスを書いてもよいですし、[`derive newtype instance`](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#derive-from-newtype)と書くだけでコンパイラに取り仕切ってもらうこともできます。 + +1. (難しい)多変数型のクラス `Action`の引数は、何らかの関数従属性によって関連づけられるべきですか。 + なぜそうすべき、あるいはそうすべきでないでしょうか。 + *補足*:この演習にはテストがありません。 + +## ハッシュの型クラス + +この最後の節では、章の残りを使ってデータ構造をハッシュ化するライブラリを作ります。 + +> なお、このライブラリは説明だけを目的としており、堅牢なハッシュ化の仕組みの提供は意図していません。 + +ハッシュ関数に期待される性質とはどのようなものでしょうか。 + +- ハッシュ関数は決定的でなくてはなりません。 + つまり、同じ値は同じハッシュコードに写さなければなりません。 +- ハッシュ関数はいろいろなハッシュ値の集合で結果が一様に分布しなければなりません。 + +最初の性質はちゃんとした型クラスの法則のように見えます。 +その一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型システムによって確実に強制できるようなものではなさそうです。 +しかし、これは型クラスから次のような直感が得られるでしょう。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:Hashable}} +``` + +これに、 `a == b`ならば `hash a == hash b`を示唆するという関係性の法則が付随しています。 + +この節の残りの部分を費やして、`Hashable`型クラスに関連付けられているインスタンスと関数のライブラリを構築していきます。 + +決定的な方法でハッシュ値を結合する方法が必要になります。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:combineHashes}} +``` + +`combineHashes`関数は2つのハッシュ値を混ぜて結果を0-65535の間に分布します。 + +それでは、`Hashable`制約を使って入力の種類を制限する関数を書いてみましょう。 +ハッシュ関数を必要とするよくある目的としては、2つの値が同じハッシュコードにハッシュ化されるかどうかを判定することです。 +`hashEqual`関係はそのような機能を提供します。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashEqual}} +``` + +この関数はハッシュコードの等値性を利用したハッシュ同値性を定義するために`Data.Function`の +`on`関数を使っていますが、これはハッシュ同値性の宣言的な定義として読めるはずです。 +つまり、それぞれの値が `hash`関数に渡されたあとで2つの値が等しいなら、それらの値は「ハッシュ同値」です。 + +原始型の `Hashable`インスタンスを幾つか書いてみましょう。 +まずは整数のインスタンスです。 +`HashCode`は実際には単なる梱包された整数なので、単純です。 +`hashCode`補助関数を使えます。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashInt}} +``` + +パターン照合を使うと、`Boolean`値の単純なインスタンスも定義できます。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashBoolean}} +``` + +整数のインスタンスでは、`Data.Char`の `toCharCode`関数を使うと`Char`をハッシュ化するインスタンスを作成できます。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashChar}} +``` + +(要素型が `Hashable`のインスタンスでもあるならば)配列の要素に `hash`関数を +`map`してから、`combineHashes`関数を使って結果のハッシュを左側に畳み込むことで、配列のインスタンスを定義します。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashArray}} +``` + +既に書いたものより単純なインスタンスを使用して、新たなインスタンスを構築しているやり方に注目してください。 +`String`を`Char`の配列に変換し、この新たな`Array`インスタンスを使って`String`のインスタンスを定義しましょう。 + +```haskell +{{#include ../exercises/chapter6/src/Data/Hashable.purs:hashString}} +``` + +これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証明するにはどうしたらいいでしょうか。 +同じ値が等しいハッシュコードを持っていることを確認する必要があります。 +`Int`、`Char`、`String`、`Boolean`のような場合は単純です。 +`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しないからです。 + +もっと面白い型についてはどうでしょうか。 +`Array`インスタンスの型クラスの法則を証明するにあたっては、配列の長さに関する帰納を使えます。 +長さゼロの唯一の配列は `[]`です。 +配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じで配列の残りの部分が等しいとき、またその時に限り等しくなります。 +この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし `Hashable +a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を持つことがわかります。 +したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型クラス法則に従います。 + +この章のソースコードには、 `Maybe`と `Tuple`型のインスタンスなど、他にも `Hashable`インスタンスの例が含まれています。 + +## 演習 + + 1. (簡単)PSCiを使って、定義した各インスタンスのハッシュ関数をテストしてください。 + *補足*:この演習には単体試験がありません。 + 1. (普通)関数`arrayHasDuplicates`を書いてください。 + この関数はハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうかを調べます。 + まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対が見付かったら`==`で値の同値性を確認してください。 + *手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるでしょう。 + 1. (普通)型クラスの法則を満たす、次のnewtypeの `Hashable`インスタンスを書いてください。 + + ```haskell + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:Hour}} + + {{#include ../exercises/chapter6/test/no-peeking/Solutions.purs:eqHour}} + ``` + + newtypeの `Hour`とその `Eq`インスタンスは、12を法とする整数の型を表します。 + したがって、例えば1と13は等しいと見なされます。 + そのインスタンスが型クラスの法則を満たしていることを証明してください。 + 1. (難しい)`Maybe`、`Either`そして`Tuple`への`Hashable`インスタンスについて型クラスの法則を証明してください。 + *補足*:この演習にテストはありません。 + +## まとめ + +この章では*型クラス*を導入しました。 +型クラスは型に基づく抽象化で、コードの再利用のために強力な形式化ができます。 +PureScriptの標準ライブラリから標準の型クラスを幾つか見てきました。 +また、ハッシュ値を計算するための型クラスに基づく独自のライブラリを定義しました。 + +この章では型クラス法則も導入しましたが、これは抽象化に型クラスを使うコードについての性質を証明する手法でした。 +型クラス法則は*等式推論*と呼ばれるより大きな分野の一部です。 +そちらではプログラミング言語の性質と型システムがプログラムを論理的に追究するために使われています。 +これは重要な考え方で、本書では今後あらゆる箇所で立ち返る話題となるでしょう。 diff --git a/text-ja/chapter7.md b/text-ja/chapter7.md new file mode 100644 index 00000000..65f6d08e --- /dev/null +++ b/text-ja/chapter7.md @@ -0,0 +1,824 @@ +# アプリカティブによる検証 + +## この章の目標 + +この章では重要な抽象化と新たに出会うことになります。 +`Applicative`型クラスによって表現される*アプリカティブ関手*です。 +名前が難しそうに思えても心配しないでください。 +フォームデータの検証という実用的な例を使ってこの概念の動機付けをします。 +アプリカティブ関手の技法があることにより、通常であれば大量の決まり文句の検証を伴うようなコードを、簡潔で宣言的なフォームの記述へと変えられます。 + +また、*巡回可能関手*を表現する`Traversable`という別の型クラスにも出会います。現実の問題への解決策からこの概念が自然に生じることがわかるでしょう。 + +この章のコードでは第3章に引き続き住所録を例とします。 +今回は住所録のデータ型を拡張し、これらの型の値を検証する関数を書きます。 +これらの関数は、例えばwebユーザインターフェースで使えることが分かります。 +データ入力フォームの一部として、使用者へエラーを表示するのに使われます。 + +## プロジェクトの準備 + +この章のソースコードは、2つのファイル`src/Data/AddressBook.purs`、及び`src/Data/AddressBook/Validation.purs`で定義されています。 + +このプロジェクトには多くの依存関係がありますが、その大半は既に見てきたものです。 +新しい依存関係は2つです。 + +- `control` - `Applicative`のような、型クラスを使用して制御フローを抽象化する関数が定義されています。 +- `validation` - この章の主題である _アプリカティブによる検証_ のための関手が定義されています。 + +`Data.AddressBook`モジュールにはこのプロジェクトのデータ型とそれらの型に対する`Show`インスタンスが定義されています。 +また、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれています。 + +## 関数適用の一般化 + +_アプリカティブ関手_ の概念を理解するために、以前扱った型構築子`Maybe`について考えてみましょう。 + +このモジュールのソースコードでは、次の型を持つ`address`関数が定義されています。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook.purs:address_anno}} +``` + +この関数は、通りの名前、市、州という3つの文字列から型`Address`の値を構築するために使います。 + +この関数は簡単に適用できますので、PSCiでどうなるか見てみましょう。 + +```text +> import Data.AddressBook + +> address "123 Fake St." "Faketown" "CA" +{ street: "123 Fake St.", city: "Faketown", state: "CA" } +``` + +しかし、通り、市、州の3つ全てが必ずしも入力されないものとすると、3つの場合がそれぞれ省略可能であることを示すために`Maybe`型を使用したくなります。 + +考えられる場合としては、市が省略されている場合があるでしょう。 +もし`address`関数を直接適用しようとすると、型検証器からエラーが表示されます。 + +```text +> import Data.Maybe +> address (Just "123 Fake St.") Nothing (Just "CA") + +Could not match type + + Maybe String + +with type + + String +``` + +勿論、これは期待通り型エラーになります。 +`address`は`Maybe String`型の値ではなく、文字列を引数として取るためです。 + +しかし、もし`address`関数を「持ち上げる」ことができれば、`Maybe`型で示される省略可能な値を扱うことができるはずだという予想は理に適っています。実際それは可能で、`Control.Apply`で提供されている関数`lift3`が、まさに求めているものです。 + +```text +> import Control.Apply +> lift3 address (Just "123 Fake St.") Nothing (Just "CA") + +Nothing +``` + +このとき、引数の1つ(市)が欠落していたので、結果は`Nothing`になります。 +もし3つの引数全てに`Just`構築子を使ったものが与えられたら、結果は値を含むことになります。 + +```text +> lift3 address (Just "123 Fake St.") (Just "Faketown") (Just "CA") + +Just ({ street: "123 Fake St.", city: "Faketown", state: "CA" }) +``` + +`lift3`という関数の名前は、3引数の関数を持ち上げるために使えることを示しています。関数を持ち上げる同様の関数で、引数の数が異なるものが`Control.Apply`で定義されています。 + +## 任意個の引数を持つ関数の持ち上げ + +これで、`lift2`や`lift3`のような関数を使えば、引数が2個や3個の関数を持ち上げることができるのはわかりました。 +でも、これを任意個の引数の関数へと一般化できるのでしょうか。 + +`lift3`の型を見てみるとわかりやすいでしょう。 + +```text +> :type lift3 +forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d +``` + +上の`Maybe`の例では型構築子`f`は`Maybe`ですから、`lift3`は次のように特殊化されます。 + +```haskell +forall a b c d. (a -> b -> c -> d) -> Maybe a -> Maybe b -> Maybe c -> Maybe d +``` + +この型で書かれているのは、3引数の任意の関数を取り、その関数を引数と返り値が`Maybe`で包まれた新しい関数へと持ち上げられる、ということです。 + +勿論、どんな型構築子`f`についても持ち上げができるわけではないのですが、それでは`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。 +さて、先ほどの型の特殊化では、`f`に対する型クラス制約から`Apply`型クラスを取り除いていました。 +`Apply`はPreludeで次のように定義されています。 + +```haskell +class Functor f where + map :: forall a b. (a -> b) -> f a -> f b + +class Functor f <= Apply f where + apply :: forall a b. f (a -> b) -> f a -> f b +``` + +`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`の型は`map`の型と実によく似ています。 +`map`と`apply`の違いは、`map`がただの関数を引数に取るのに対し、`apply`の最初の引数は型構築子`f`で包まれているという点です。 +これをどのように使うのかはこれからすぐに見ていきますが、その前にまず`Maybe`型について`Apply`型クラスをどう実装するのかを見ていきましょう。 + +```haskell +instance Functor Maybe where + map f (Just a) = Just (f a) + map f Nothing = Nothing + +instance Apply Maybe where + apply (Just f) (Just x) = Just (f x) + apply _ _ = Nothing +``` + +この型クラスのインスタンスで書かれているのは、任意の省略可能な値に省略可能な関数を適用でき、その両方が定義されている時に限り結果も定義される、ということです。 + +それでは、`map`と`apply`を一緒に使い、引数が任意個の関数を持ち上げる方法を見ていきましょう。 + +1引数の関数については、`map`をそのまま使うだけです。 + +2引数関数については、型`a -> b -> c`のカリー化された関数`g`があるとします。これは型`a -> (b -> c)`と同じですから、`Functor`インスタンス付きのあらゆる型構築子`f`について、`map`を`f`に適用すると型`f a -> f (b -> c)`の新たな関数を得ることになります。持ち上げられた(型`f a`の)最初の引数にその関数を部分適用すると、型`f (b -> c)`の新たな包まれた関数が得られます。`f`に`Apply`インスタンスもあるなら、そこから、2番目の持ち上げられた(型`f b`の)引数へ`apply`を適用でき、型`f c`の最終的な値を得ます。 + +纏めると、`x :: f a`と`y :: f b`があるとき、式`(g <$> x) <*> y`の型は`f c`になります(この式は`apply (map g x) y`と同じ意味だということを思い出しましょう)。Preludeで定義された優先順位の規則に従うと、`g <$> x <*> y`というように括弧を外すことができます。 + +一般的には、最初の引数に`<$>`を使い、残りの引数に対しては`<*>`を使います。`lift3`で説明すると次のようになります。 + +```haskell +lift3 :: forall a b c d f + . Apply f + => (a -> b -> c -> d) + -> f a + -> f b + -> f c + -> f d +lift3 f x y z = f <$> x <*> y <*> z +``` + +> この式に関する型の検証は、読者への演習として残しておきます。 + +例として、`<$>`と`<*>`をそのまま使うと、`Maybe`上に`address`関数を持ち上げることができます。 + +```text +> address <$> Just "123 Fake St." <*> Just "Faketown" <*> Just "CA" +Just ({ street: "123 Fake St.", city: "Faketown", state: "CA" }) + +> address <$> Just "123 Fake St." <*> Nothing <*> Just "CA" +Nothing +``` + +同様にして、引数が異なる他のいろいろな関数を`Maybe`上に持ち上げてみてください。 + +この代わりに、お馴染の*do記法*に似た見た目の*アプリカティブdo記法*が同じ目的で使えます。 +以下では`lift3`に*アプリカティブdo記法*を使っています。 +なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で`in`が使われています。 + +```haskell +lift3 :: forall a b c d f + . Apply f + => (a -> b -> c -> d) + -> f a + -> f b + -> f c + -> f d +lift3 f x y z = ado + a <- x + b <- y + c <- z + in f a b c +``` + +## アプリカティブ型クラス + +関連する`Applicative`という型クラスが存在しており、次のように定義されています。 + +```haskell +class Apply f <= Applicative f where + pure :: forall a. a -> f a +``` + +`Applicative`は`Apply`の下位クラスであり、`pure`関数が定義されています。 +`pure`は値を取り、その型の型構築子`f`で包まれた値を返します。 + +`Maybe`についての`Applicative`インスタンスは次のようになります。 + +```haskell +instance Applicative Maybe where + pure x = Just x +``` + +アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、`pure`は引数のない関数の持ち上げだというように考えられます。 + +## アプリカティブに対する直感的理解 + +PureScriptの関数は純粋であり、副作用は持っていません。Applicative関手は、関手`f`によって表現されるある種の副作用を提供するような、より大きな「プログラミング言語」を扱えるようにします。 + +例えば関手`Maybe`は欠けている可能性がある値の副作用を表現しています。 +その他の例としては、型`err`のエラーの可能性の副作用を表す`Either err`や、大域的な構成を読み取る副作用を表すArrow関手 (arrow functor) `r ->`があります。 +ここでは`Maybe`関手についてのみ考えることにします。 + +もし関手`f`が作用を持つ、より大きなプログラミング言語を表すとすると、`Apply`と`Applicative`インスタンスは小さなプログラミング言語 +(PureScript) から新しい大きな言語へと値や関数を持ち上げることを可能にします。 + +`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数については上で述べた通り`map`と`apply`を使えます。 + +ここで疑問が生まれます。 +もしPureScriptの関数と値を新たな言語へ埋め込むのに`Applicative`が使えるなら、どうやって新たな言語は大きくなっているというのでしょうか。 +この答えは関手`f`に依存します。 +もしなんらかの`x`について`pure x`で表せないような型`f +a`の式を見つけたなら、その式はそのより大きな言語だけに存在する項を表しているということです。 + +`f`が`Maybe`のときは、式`Nothing`がその例になっています。 +どんな`x`があっても`Nothing`を`pure x`というように書くことはできません。 +したがって、PureScriptは値の欠落を表す新しい項`Nothing`を含むように拡大されたと考えることができます。 + +## もっと作用を + +様々な`Applicative`関手へと関数を持ち上げる例をもっと見ていきましょう。 + +以下は、PSCiで定義された3つの名前を結合して完全な名前を作る簡単な関数の例です。 + +```text +> import Prelude + +> fullName first middle last = last <> ", " <> first <> " " <> middle + +> fullName "Phillip" "A" "Freeman" +Freeman, Phillip A +``` + +この関数が、クエリパラメータとして与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装を形成しているとしましょう。 +使用者が3つの各引数を与えたことを確かめたいので、引数が存在するかどうかを表す`Maybe`型を使うことになるでしょう。 +`fullName`を`Maybe`の上へ持ち上げると、欠けている引数を検査するwebサービスの実装を作成できます。 + +```text +> import Data.Maybe + +> fullName <$> Just "Phillip" <*> Just "A" <*> Just "Freeman" +Just ("Freeman, Phillip A") + +> fullName <$> Just "Phillip" <*> Nothing <*> Just "Freeman" +Nothing +``` + +または*アプリカティブdo*で次のようにします。 + +```text +> import Data.Maybe + +> :paste… +… ado +… f <- Just "Phillip" +… m <- Just "A" +… l <- Just "Freeman" +… in fullName f m l +… ^D +(Just "Freeman, Phillip A") + +… ado +… f <- Just "Phillip" +… m <- Nothing +… l <- Just "Freeman" +… in fullName f m l +… ^D +Nothing +``` + +この持ち上げた関数は、引数の何れかが`Nothing`なら`Nothing`を返すことに注意してください。 + +引数が不正のときにwebサービスからエラー応答を送り返せるのは良いことです。 +しかし、どのフィールドが不正確なのかを応答で示せると、もっと良くなるでしょう。 + +`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エラー文言を返せるようになります。 +まずは`Either String`を使い、省略可能な入力からエラーを発信できる計算に変換する演算子を書きましょう。 + +```text +> import Data.Either +> :paste +… withError Nothing err = Left err +… withError (Just a) _ = Right a +… ^D +``` + +*補足*:`Either err`アプリカティブ関手において、`Left`構築子は失敗を表しており、`Right`構築子は成功を表しています。 + +これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー文言を提供できるようになります。 + +```text +> :paste +… fullNameEither first middle last = +… fullName <$> (first `withError` "First name was missing") +… <*> (middle `withError` "Middle name was missing") +… <*> (last `withError` "Last name was missing") +… ^D +``` + +または*アプリカティブdo*で次のようにします。 + +```text +> :paste +… fullNameEither first middle last = ado +… f <- first `withError` "First name was missing" +… m <- middle `withError` "Middle name was missing" +… l <- last `withError` "Last name was missing" +… in fullName f m l +… ^D + +> :type fullNameEither +Maybe String -> Maybe String -> Maybe String -> Either String String +``` + +これでこの関数は`Maybe`を使う3つの省略可能な引数を取り、`String`のエラー文言か`String`の結果のどちらかを返します。 + +いろいろな入力でこの関数を試してみましょう。 + +```text +> fullNameEither (Just "Phillip") (Just "A") (Just "Freeman") +(Right "Freeman, Phillip A") + +> fullNameEither (Just "Phillip") Nothing (Just "Freeman") +(Left "Middle name was missing") + +> fullNameEither (Just "Phillip") (Just "A") Nothing +(Left "Last name was missing") +``` + +このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラー文言が表示されます。 +しかし、もし複数の入力が省略されているとき、最初のエラーしか見れません。 + +```text +> fullNameEither Nothing Nothing Nothing +(Left "First name was missing") +``` + +これでも充分なときもありますが、エラー時に*全ての*省略されたフィールドの一覧がほしいときは、`Either +String`よりも強力なものが必要です。この章の後半で解決策を見ていきます。 + +## 作用の結合 + +抽象的にアプリカティブ関手を扱う例として、この節ではアプリカティブ関手`f`によって表現された副作用を一般的に組み合わせる関数を書く方法を示します。 + +これはどういう意味でしょうか。 +何らかの`a`について型`f a`で包まれた引数のリストがあるとしましょう。 +それは型`List (f a)`のリストがあるということです。 +直感的には、これは`f`によって追跡される副作用を持つ、返り値の型が`a`の計算のリストを表しています。 +これらの計算の全てを順番に実行できれば、`List a`型の結果のリストを得るでしょう。 +しかし、まだ`f`によって追跡される副作用が残ります。 +つまり、元のリストの中の作用を「結合する」ことにより、型`List (f a)`の何かを型`f (List a)`の何かへと変換できると考えられます。 + +任意の固定長リストの長さ`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)`が得られます。 +しかし、いかなる`n`についてもこれが可能なので、いかなる引数の*リスト*についても同じように持ち上げられることが確かめられます。 + +したがって、次のような関数を書くことができるはずです。 + +```haskell +combineList :: forall f a. Applicative f => List (f a) -> f (List a) +``` + +この関数は副作用を持つかもしれない引数のリストを取り、それぞれの副作用を適用することで、`f`に包まれた単一のリストを返します。 + +この関数を書くためには、引数のリストの長さについて考えます。 +リストが空の場合はどんな作用も実行する必要がありませんから、`pure`を使用して単に空のリストを返すことができます。 + +```haskell +combineList Nil = pure Nil +``` + +実際のところこれがたった1つのできることです。 + +入力のリストが空でないならば、型`f a`の包まれた引数である先頭要素と、型`List (f a)`の尾鰭について考えます。 +また、再帰的にリストの残りを結合すると、型`f (List a)`の結果が得られます。 +それから`<$>`と`<*>`を使うと、`Cons`構築子を先頭と新しい尾鰭の上に持ち上げることができます。 + +```haskell +combineList (Cons x xs) = Cons <$> x <*> combineList xs +``` + +繰り返しになりますが、これは与えられた型に基づいている唯一の妥当な実装です。 + +`Maybe`型構築子を例にとって、PSCiでこの関数を試してみましょう。 + +```text +> import Data.List +> import Data.Maybe + +> combineList (fromFoldable [Just 1, Just 2, Just 3]) +(Just (Cons 1 (Cons 2 (Cons 3 Nil)))) + +> combineList (fromFoldable [Just 1, Nothing, Just 2]) +Nothing +``` + +`Meybe`へ特殊化すると、リストの全ての要素が`Just`であるときに限りこの関数は`Just`を返しますし、そうでなければ`Nothing`を返します。 +これは省略可能な値に対応する、より大きな言語に取り組む上での直感と一貫しています。 +省略可能な結果を生む計算のリストは、全ての計算が結果を持っているならばそれ自身の結果のみを持つのです。 + +ところが`combineList`関数はどんな`Applicative`に対しても機能するのです。 +`Either err`を使ってエラーを発信する可能性を持たせたり、`r ->`を使って大域的な構成を読み取る計算を組み合わせるためにも使えます。 + +`combineList`関数については、後ほど`Traversable`関手について考えるときに再訪します。 + +## 演習 + + 1. (普通)数値演算子`+`、`-`、`*`、`/`の別のバージョンを書いてください。 + ただし省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返します。 + これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けてください。 + *手掛かり*:`lift2`を使ってください。 + 1. (普通)上の演習を(`Maybe`だけでなく)全ての`Apply`型で動くように拡張してください。 + これらの新しい関数には`addApply`、`subApply`、`mulApply`、`divApply`と名前を付けます。 + 1. (難しい)型`forall a f. Applicative f => Maybe (f a) -> f (Maybe + a)`を持つ関数`combineMaybe`を書いてください。 + この関数は副作用を持つ省略可能な計算を取り、省略可能な結果を持つ副作用のある計算を返します。 + +## アプリカティブによる検証 + +この章のソースコードでは住所録アプリケーションで使うであろう幾つかのデータ型が定義されています。 +詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされる鍵となる関数は次のような型を持ちます。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook.purs:address_anno}} + +{{#include ../exercises/chapter7/src/Data/AddressBook.purs:phoneNumber_anno}} + +{{#include ../exercises/chapter7/src/Data/AddressBook.purs:person_anno}} +``` + +ここで、`PhoneType`は次のような代数的データ型として定義されています。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook.purs:PhoneType}} +``` + +これらの関数は住所録の項目を表す`Person`を構築できます。 +例えば、`Data.AddressBook`では以下の値が定義されています。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook.purs:examplePerson}} +``` + +PSCiでこれらの値を試してみましょう(結果は整形されています)。 + +```text +> import Data.AddressBook + +> examplePerson +{ firstName: "John" +, lastName: "Smith" +, homeAddress: + { street: "123 Fake St." + , city: "FakeTown" + , state: "CA" + } +, phones: + [ { type: HomePhone + , number: "555-555-5555" + } + , { type: CellPhone + , number: "555-555-0000" + } + ] +} +``` + +前の章では型`Person`のデータ構造を検証する上で`Either +String`関手の使い方を見ました。例えば、データ構造の2つの名前を検証する関数が与えられたとき、データ構造全体を次のように検証できます。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:nonEmpty1}} + +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson1}} +``` + +または*アプリカティブdo*で次のようにします。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson1Ado}} +``` + +最初の2行では`nonEmpty1`関数を使って空文字列でないことを検証しています。 +もし入力が空なら`nonEmpty1`は`Left`構築子で示されるエラーを返します。 +そうでなければ`Right`構築子で包まれた値を返します。 + +最後の2行では何の検証も実行せず、単に`address`フィールドと`phones`フィールドを残りの引数として`person`関数へと提供しています。 + +この関数はPSCiでうまく動作するように見えますが、以前見たような制限があります。 + +```text +> validatePerson $ person "" "" (address "" "" "") [] +(Left "Field cannot be empty") +``` + +`Either String`アプリカティブ関手は最初に遭遇したエラーだけを返します。 +仮にこの入力だったとすると、2つのエラーが分かったほうが良いでしょう。 +1つは名前の不足で、2つ目は姓の不足です。 + +`validation`ライブラリでは別のアプリカティブ関手も提供されています。 +これは`V`という名前で、何らかの*半群*でエラーを返せます。 +例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、`String`の配列をエラーとして返せます。 + +`Data.Validation`モジュールは`Data.AddressBook`モジュールのデータ構造を検証するために`V (Array +String)`アプリカティブ関手を使っています。 + +`Data.AddressBook.Validation`モジュールから取材した検証器の例は次のようになります。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:Errors}} + +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:nonEmpty}} + +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:lengthIs}} + +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validateAddress}} +``` + +または*アプリカティブdo*で次のようにします。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validateAddressAdo}} +``` + +`validateAddress`は`Address`の構造を検証します。 +`street`と`city`が空でないかどうか、`state`の文字列の長さが2であるかどうかを検証します。 + +`nonEmpty`と`lengthIs`の2つの検証関数が何れも、`Data.Validation`モジュールで提供されている`invalid`関数をエラーを示すために使っているところに注目してください。 +`Array String`半群を扱っているので、`invalid`は引数として文字列の配列を取ります。 + +PSCiでこの関数を試しましょう。 + +```text +> import Data.AddressBook +> import Data.AddressBook.Validation + +> validateAddress $ address "" "" "" +(invalid [ "Field 'Street' cannot be empty" + , "Field 'City' cannot be empty" + , "Field 'State' must have length 2" + ]) + +> validateAddress $ address "" "" "CA" +(invalid [ "Field 'Street' cannot be empty" + , "Field 'City' cannot be empty" + ]) +``` + +これで、全ての検証エラーの配列を受け取ることができるようになりました。 + +## 正規表現検証器 + +`validatePhoneNumber`関数では引数の形式を検証するために正規表現を使っています。重要なのは`matches`検証関数で、この関数は`Data.String.Regex`モジュールで定義されている`Regex`を使って入力を検証しています。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:matches}} +``` + +繰り返しになりますが、`pure`は常に成功する検証を表しており、エラーの配列の伝達には`invalid`が使われています。 + +これまでと同様に、`validatePhoneNumber`は`matches`関数から構築されています。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePhoneNumber}} +``` + +または*アプリカティブdo*で次のようにします。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePhoneNumberAdo}} +``` + +また、PSCiでいろいろな有効な入力や無効な入力に対して、この検証器を実行してみてください。 + +```text +> validatePhoneNumber $ phoneNumber HomePhone "555-555-5555" +pure ({ type: HomePhone, number: "555-555-5555" }) + +> validatePhoneNumber $ phoneNumber HomePhone "555.555.5555" +invalid (["Field 'Number' did not match the required format"]) +``` + +## 演習 + + 1. (簡単)正規表現`stateRegex :: Regex`を書いて文字列が2文字のアルファベットであることを確かめてください。 + *手掛かり*:`phoneNumberRegex`のソースコードを参照してみましょう。 + 1. (普通)文字列全体が空白でないことを検査する正規表現`nonEmptyRegex :: Regex`を書いてください。 + *手掛かり*:この正規表現を開発するのに手助けが必要なら、[RegExr](https://regexr.com)をご確認ください。 + 素晴しい早見表と対話的なお試し環境があります。 + 1. (普通)`validateAddress`に似ていますが、上の`stateRegex`を使って`state`フィールドを検証し、`nonEmptyRegex`を使って`street`と`city`フィールドを検証する関数`validateAddressImproved`を書いてください。 + *手掛かり*:`matches`の用例については`validatePhoneNumber`のソースを見てください。 + +## 巡回可能関手 + +残った検証器は`validatePerson`です。 +これはこれまで見てきた検証器と以下の新しい`validatePhoneNumbers`関数を組み合わせて`Person`全体を検証するものです。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePhoneNumbers}} + +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePerson}} +``` + +または*アプリカティブdo*で次のようにします。 + +```haskell +{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:validatePersonAdo}} +``` + +`validatePhoneNumbers`はこれまでに見たことのない新しい関数である`traverse`を使っています。 + +`traverse`は`Data.Traversable`モジュールの`Traversable`型クラスで定義されています。 + +```haskell +class (Functor t, Foldable t) <= Traversable t where + traverse :: forall a b m. Applicative m => (a -> m b) -> t a -> m (t b) + sequence :: forall a m. Applicative m => t (m a) -> m (t a) +``` + +`Traversable`は _巡回可能関手_ +の型クラスを定義します。これらの関数の型は少し難しそうに見えるかもしれませんが、`validatePerson`は良いきっかけとなる例です。 + +全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能関手*は畳み込み操作に対応する型構築子であったことを思い出してください。 +畳み込みとは構造を1つの値へと簡約するものでした)。 +それに加えて、巡回可能関手はその構造に依存した副作用の集まりを組み合わせられます。 + +複雑そうに聞こえるかもしれませんが、配列の場合に特殊化して簡単にした上で考えてみましょう。配列型構築子は`Traversable`であり、つまりは次のような関数が存在するということです。 + +```haskell +traverse :: forall a b m. Applicative m => (a -> m b) -> Array a -> m (Array b) +``` + +直感的にはこうです。 +任意のアプリカティブ関手`m`と、型`a`の値を取って型`b`の値を返す(`f`で追跡される副作用を持つ)関数が与えられたとします。 +このとき、その関数を型`Array a`の配列のそれぞれの要素に適用して型`Array +b`の(`f`で追跡される副作用を持つ)結果を得ることができます。 + +まだよくわからないでしょうか。それでは更に、`f`を上記の`V +Errors`アプリカティブ関手に特殊化して考えてみましょう。これで次の型を持つ関数が得られます。 + +```haskell +traverse :: forall a b. (a -> V Errors b) -> Array a -> V Errors (Array b) +``` + +この型シグネチャでは、型`a`についての検証関数`m`があれば、`traverse m`は型`Array +a`の配列についての検証関数であると書かれています。 +ところがこれは正に`Person`データ構造体の`phones`フィールドを検証できるようにするのに必要なものです。 +各要素が成功するかを検証する検証関数を作るために、`validatePhoneNumber`を`traverse`へ渡しています。 + +一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算し、結果を累算します。 + +`Traversable`のもう1つの関数、`sequence`の型シグネチャには見覚えがあるかもしれません。 + +```haskell +sequence :: forall a m. Applicative m => t (m a) -> m (t a) +``` + +実際、先ほど書いた`combineList`関数は`Traversable`型クラスの`sequence`関数の特別な場合に過ぎません。 +`t`を型構築子`List`だとすると、`combineList`関数の型が復元されます。 + +```haskell +combineList :: forall f a. Applicative f => List (f a) -> f (List a) +``` + +巡回可能関手はデータ構造走査の考え方を見据えたものです。 +これにより作用のある計算の集合を集めてその作用を結合します。 +実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくらい重要です。 +これらはお互いがお互いを利用して実装できます。 +これについては興味ある読者への演習として残しておきます。 + +`Data.List`で与えられているリストの`Traversable`インスタンスは次の通り。 + +```haskell +instance Traversable List where +-- traverse :: forall a b m. Applicative m => (a -> m b) -> List a -> m (List b) +traverse _ Nil = pure Nil +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つの結果を組み合わせられます。 + +巡回可能関手の例はただの配列やリスト以外にもあります。 +以前に見た`Maybe`型構築子も`Traversable`のインスタンスを持っています。 +PSCiで試してみましょう。 + +```text +> import Data.Maybe +> import Data.Traversable +> import Data.AddressBook.Validation + +> traverse (nonEmpty "Example") Nothing +pure (Nothing) + +> traverse (nonEmpty "Example") (Just "") +invalid (["Field 'Example' cannot be empty"]) + +> traverse (nonEmpty "Example") (Just "Testing") +pure ((Just "Testing")) +``` + +これらの例では、`Nothing`の値の走査は検証なしで`Nothing`の値を返し、`Just +x`を走査すると`x`を検証するのに検証関数が使われるということを示しています。 +要は、`traverse`は型`a`についての検証関数を取り、`Maybe +a`についての検証関数、つまり型`a`の省略可能な値についての検証関数を返すのです。 + +他の巡回可能関手には、任意の型`a`についての`Array a`、`Tuple a`、`Either a`が含まれます。 +一般に、「容器」のようなほとんどのデータ型構築子は`Traversable`インスタンスを持っています。 +一例として、演習には二分木の型の`Traversable`インスタンスを書くことが含まれます。 + +## 演習 + + 1. (簡単)`Eq`と`Show`インスタンスを以下の2分木データ構造に対して書いてください。 + + ```haskell + data Tree a = Leaf | Branch (Tree a) a (Tree a) + ``` + + これらのインスタンスを手作業で書くこともできますし、コンパイラに導出してもらうこともできることを前の章から思い起こしてください。 + + `Show`の出力には多くの「正しい」書式の選択肢があります。 + この演習のテストでは以下の空白スタイルを期待しています。 + これは一般化されたshowの既定の書式と合致しているため、このインスタンスを手作業で書くつもりのときだけ、このことを念頭に置いておいてください。 + + ```haskell + (Branch (Branch Leaf 8 Leaf) 42 Leaf) + ``` + + 1. (普通)`Traversable`インスタンスを`Tree a`に対して書いてください。 + これは副作用を左から右に結合するものです。 + *手掛かり*:`Traversable`に定義する必要のある追加のインスタンス依存関係が幾つかあります。 + + 1. (普通)行き掛け順に木を巡回する関数`traversePreOrder :: forall a m b. Applicative m => (a + -> m b) -> Tree a -> m (Tree b)`を書いてください。 + つまり作用の実行は根左右と行われ、以前の通り掛け順の巡回の演習でしたような左根右ではありません。 + *手掛かり*:追加でインスタンスを定義する必要はありませんし、前に定義した関数は何も呼ぶ必要はありません。 + アプリカティブdo記法 (`ado`) はこの関数を書く最も簡単な方法です。 + + 1. (普通)木を帰り掛け順に巡回する関数`traversePostOrder`を書いてください。作用は左右根と実行されます。 + + 1. (普通)`homeAddress`フィールドが省略可能(`Maybe`を使用)な新しい版の`Person`型をつくってください。 + それからこの新しい`Person`を検証する新しい版の`validatePerson`(`validatePersonOptionalAddress`と改名します)を書いてください。 + *手掛かり*:`traverse`を使って型`Maybe a`のフィールドを検証してください。 + + 1. (難しい)`sequence`のように振る舞う関数`sequenceUsingTraverse`を書いてください。 + ただし`traverse`を使ってください。 + + 1. (難しい)`traverse`のように振る舞う関数`traverseUsingSequence`を書いてください。 + ただし`sequence`を使ってください。 + +## アプリカティブ関手による並列処理 + +これまでの議論では、アプリカティブ関手がどのように「副作用を結合」させるかを説明するときに、「結合」(combine) という単語を選びました。 +しかし、これらの全ての例において、アプリカティブ関手は作用を「連鎖」(sequence) させる、というように言っても同じく妥当です。 +巡回可能関手がデータ構造に従って作用を順番に結合させる`sequence`関数を提供していることと、この直感的理解とは一致するでしょう。 + +しかし一般には、アプリカティブ関手はこれよりももっと一般的です。 +アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しません。 +実際、並列に副作用を実行するアプリカティブ関手は妥当でしょう。 + +例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだとしてもやはり正常に動き、このときどんな順序で各検証器を実行しても問題はありません。 +データ構造に対して並列にこれの実行さえできるのです。 + +2つ目の例として、`parallel`パッケージは*並列計算*に対応する`Parallel`型クラスを提供します。 +`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入力の計算の結果を*並列に*計算します。 + +```haskell +f <$> parallel computation1 + <*> parallel computation2 +``` + +この計算は`computation1`と`computation2`を非同期に使って値の計算を始めるでしょう。そして両方の結果の計算が終わった時に、関数`f`を使って1つの結果へと結合するでしょう。 + +この考え方の詳細は、本書の後半で _コールバック地獄_ の問題に対してアプリカティブ関手を応用するときに見ていきます。 + +アプリカティブ関手は並列に結合できる副作用を捉える自然な方法です。 + +## まとめ + +この章では新しい考え方を沢山扱いました。 + +- *アプリカティブ関手*の概念を導入しました。 + これは、関数適用の概念から副作用の観念を捉えた型構築子へと一般化するものです。 +- データ構造の検証という課題をアプリカティブ関手やその切り替えで解く方法を見てきました。 + 単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変更できました。 +- `Traversable`型クラスに出会いました。*巡回可能関手*の考え方を内包するものであり、要素が副作用を持つ値の結合に使うことができる容れ物でした。 + +アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化です。 +本書を通じて何度も見ることになるでしょう。 +今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、これにより検証器が*どうやって*検証を実施するかではなく、*何を*検証すべきなのかを定義できました。 +一般にアプリカティブ関手が*領域特化言語*を設計する上で便利な道具になることを見ていきます。 + +次の章では、これに関連する考え方である*モナド*クラスを見て、アドレス帳の例をブラウザで実行させられるように拡張しましょう。 diff --git a/text-ja/chapter8.md b/text-ja/chapter8.md new file mode 100644 index 00000000..98c02bed --- /dev/null +++ b/text-ja/chapter8.md @@ -0,0 +1,1174 @@ +# 作用モナド + +## この章の目標 + +前章では、*副作用*を扱うのに使う抽象化であるアプリカティブ関手を導入しました。 +副作用とは省略可能な値、エラー文言、検証などです。 +この章では、副作用を扱うためのより表現力の高い別の抽象化である*モナド*を導入します。 + +この章の目的は、なぜモナドが便利な抽象化なのかということと、*do記法*との関係を説明することです。 + +## プロジェクトの準備 + +このプロジェクトでは、以下の依存関係が追加されています。 + +- `effect`: 章の後半の主題である`Effect`モナドを定義しています。 + この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存関係にありました)、明示的にインストールしなければいけないことは稀です。 +- `react-basic-hooks`: アドレス帳アプリに使うwebフレームワークです。 + +## モナドとdo記法 + +do記法は*配列内包表記*を扱うときに初めて導入されました。 +配列内包表記は`Data.Array`モジュールの`concatMap`関数の構文糖として提供されています。 + +次の例を考えてみましょう。2つのサイコロを振って出た目を数え、出た目の合計が +`n`のときそれを得点とすることを考えます。次のような非決定的なアルゴリズムを使うとこれを実現できます。 + +- 最初の投擲で値 `x`を _選択_ します。 +- 2回目の投擲で値 `y`を _選択_ します。 +- もし`x`と`y`の和が`n`なら組`[x, y]`を返し、そうでなければ失敗します。 + +配列内包表記を使うと、この非決定的アルゴリズムを自然に書けます。 + +```hs +import Prelude + +import Control.Plus (empty) +import Data.Array ((..)) + +{{#include ../exercises/chapter8/test/Examples.purs:countThrows}} +``` + +PSCiでこの関数の動作を見てみましょう。 + +```text +> import Test.Examples + +> countThrows 10 +[[4,6],[5,5],[6,4]] + +> countThrows 12 +[[6,6]] +``` + +前の章では、*省略可能な値*に対応したより大きなプログラミング言語へとPureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養いました。 +同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができます。 + +一般に、ある型構築子`m`のモナドは、型`m a`の値を持つdo記法を使う手段を提供します。 +上の配列内包表記に注意すると、何らかの型`a`について全行に型`Array a`の計算が含まれています。 +一般に、do記法ブロックの全行は、何らかの型`a`とモナド`m`について、型`m a`の計算を含みます。 +モナド`m`は全行で同じでなければなりません(つまり副作用は固定)が、型`a`は異なることもあります(つまり個々の計算は異なる型の結果にできる)。 + +以下はdo記法の別の例です。 +今回は型構築子 `Maybe`に適用されています。 +XMLノードを表す型 `XML`と次の関数があるとします。 + +```hs +child :: XML -> String -> Maybe XML +``` + +この関数はノードの子の要素を探し、もしそのような要素が存在しなければ `Nothing`を返します。 + +この場合、do記法を使うと深い入れ子になった要素を検索できます。 +XML文書としてエンコードされた利用者情報から、利用者の住んでいる市町村を読み取りたいとします。 + +```hs +userCity :: XML -> Maybe XML +userCity root = do + prof <- child root "profile" + addr <- child prof "address" + city <- child addr "city" + pure city +``` + +`userCity`関数は子の`profile`要素、`profile`要素の中にある`address`要素、最後に`address`要素の中にある`city`要素を探します。 +これらの要素の何れかが欠落している場合、返り値は`Nothing`になります。 +そうでなければ、返り値は`city`ノードから`Just`を使って構築されます。 + +最後の行にある`pure`関数は、全ての`Applicative`関手について定義されているのでした。 +`Maybe`の`Applicative`関手の`pure`関数は`Just`として定義されており、最後の行を `Just +city`へ変更しても同じように正しく動きます。 + +## モナド型クラス + +`Monad`型クラスは次のように定義されています。 + +```hs +class Apply m <= Bind m where + bind :: forall a b. m a -> (a -> m b) -> m b + +class (Applicative m, Bind m) <= Monad m +``` + +ここで鍵となる関数は `Bind`型クラスで定義されている演算子 `bind`で、`Functor`及び `Apply`型クラスにある `<$>`や `<*>`などの演算子と同様に、`Prelude`では `>>=`として `bind`の中置の別名が定義されています。 + +`Monad`型クラスは、既に見てきた`Applicative`型クラスの操作で`Bind`を拡張します。 + +`Bind`型クラスの例を幾つか見てみるのがわかりやすいでしょう。 +配列についての `Bind`の妥当な定義は次のようになります。 + +```hs +instance Bind Array where + bind xs f = concatMap f xs +``` + +これは以前に仄めかした、配列内包表記と `concatMap`関数の関係を説明しています。 + +`Maybe`型構築子についての `Bind`の実装は次のようになります。 + +```hs +instance Bind Maybe where + bind Nothing _ = Nothing + bind (Just a) f = f a +``` + +この定義は欠落した値がdo記法ブロックを通じて伝播するという直感的理解を裏付けるものです。 + +`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。 +最初に、何らかの計算結果からの値の束縛から始まる、単純なdo記法ブロックについて考えてみましょう。 + +```hs +do value <- someComputation + whatToDoNext +``` + +PureScriptコンパイラはこのようなパターンを見つけるたびにコードを次にように置き換えます。 + +```hs +bind someComputation \value -> whatToDoNext +``` + +あるいは中置で書くと以下です。 + +```hs +someComputation >>= \value -> whatToDoNext +``` + +この計算 `whatToDoNext`は `value`に依存できます。 + +複数の束縛が関係している場合、この規則は先頭のほうから複数回適用されます。例えば、先ほど見た `userCity`の例では次のように脱糖されます。 + +```hs +userCity :: XML -> Maybe XML +userCity root = + child root "profile" >>= \prof -> + child prof "address" >>= \addr -> + child addr "city" >>= \city -> + pure city +``` + +do記法を使って表現されたコードは、`>>=`演算子を使う等価なコードより遥かに読みやすくなることがよくあることも特筆すべき点です。 +しかしながら、明示的に`>>=`を使って束縛を書くと、*ポイントフリー*形式でコードが書けるようになることがよくあります。 +ただし、読みやすさにはやはり注意が要ります。 + +## モナド則 + +`Monad`型クラスは*モナド則*と呼ばれる3つの規則を持っています。これらは +`Monad`型クラスの合理的な実装から何を期待できるかを教えてくれます。 + +do記法を使用してこれらの規則を説明していくのが最も簡単でしょう。 + +### 単位元律 + +*右単位元則* (right-identity law) +が3つの規則の中で最も簡単です。この規則はdo記法ブロックの最後の式であれば、`pure`の呼び出しを排除できると言っています。 + +```hs +do + x <- expr + pure x +``` + +右単位元則は、この式は単なる `expr`と同じだと言っています。 + +*左単位元則* (left-identity law) +は、もしそれがdo記法ブロックの最初の式であれば、`pure`の呼び出しを除去できると述べています。 + +```hs +do + x <- pure y + next +``` + +このコードは`next`の名前`x`を式`y`で置き換えたものと同じです。 + +最後の規則は _結合則_ (associativity law) +です。これは入れ子になったdo記法ブロックをどう扱うのかについて教えてくれます。この規則が述べているのは以下のコード片のことです。 + +```hs +c1 = do + y <- do + x <- m1 + m2 + m3 +``` + +上記のコード片は、次のコードと同じです。 + +```hs +c2 = do + x <- m1 + y <- m2 + m3 +``` + +これらの各計算には3つのモナドの式`m1`、`m2`、`m3`が含まれています。 +どちらの場合でも`m1`の結果は結局は名前`x`に束縛され、`m2`の結果は名前`y`に束縛されます。 + +`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグループ化されています。 + +`c2`では`m1`、`m2`、`m3`の3つ全ての式が同じdo記法ブロックに現れています。 + +結合法則は入れ子になったdo記法ブロックをこのように単純化しても問題ないことを言っています。 + +*補足*:do記法を`bind`の呼び出しへと脱糖する定義により、 `c1`と `c2`は何れも次のコードと同じです。 + +```hs +c3 = do + x <- m1 + do + y <- m2 + m3 +``` + +## モナドで畳み込む + +抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で機能する関数を紹介していきます。 +これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと対応しているという直感的理解を補強しますし、モナドによるプログラミングが齎す一般性も示しています。 + +これから書いていく関数は`foldM`という名前です。 +以前見た`foldl`関数をモナドの文脈へと一般化するものです。 +型シグネチャは以下です。 + +```hs +foldM :: forall m a b. Monad m => (a -> b -> m a) -> a -> List b -> m a +foldl :: forall a b. (a -> b -> a) -> a -> List b -> a +``` + +モナド `m`が現れている点を除いて、 `foldl`の型と同じであることに注意しましょう。 + +直感的には、`foldM`は様々な副作用の組み合わせに対応した文脈で配列を畳み込むものと捉えられます。 + +例として`m`として`Maybe`を選ぶとすると、各段階で`Nothing`を返すことでこの畳み込みを失敗させられます。 +各段階では省略可能な結果を返しますから、それ故畳み込みの結果も省略可能になります。 + +もし`m`として型構築子`Array`を選ぶとすると、畳み込みの各段階で0以上の結果を返せるため、畳み込みは各結果に対して独立に次の手順を継続します。 +最後に、結果の集まりは可能な経路の全ての畳み込みから構成されることになります。 +これはグラフの走査と対応していますね。 + +`foldM`を書くには、単に入力のリストについて場合分けをするだけです。 + +リストが空なら、型 `a`の結果を生成するための選択肢は1つしかありません。第2引数を返します。 + +```hs +foldM _ a Nil = pure a +``` + +なお、`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。 + +リストが空でない場合はどうでしょうか。 +その場合、型 `a`の値、型 `b`の値、型 `a -> b -> m a`の関数があります。 +もしこの関数を適用すると、型 `m a`のモナドの結果を手に入れることになります。 +この計算の結果を逆向きの矢印 `<-`で束縛できます。 + +あとはリストの残りに対して再帰するだけです。実装は簡単です。 + +```hs +foldM f a (b : bs) = do + a' <- f a b + foldM f a' bs +``` + +なお、この実装はリストに対する`foldl`の実装とほとんど同じです。 +ただしdo記法である点を除きます。 + +PSCiでこの関数を定義して試せます。 +以下は一例です。 +整数の「安全な除算」関数を定義するとします。 +0による除算かを確認し、失敗を示すために `Maybe`型構築子を使うのです。 + +```hs +{{#include ../exercises/chapter8/test/Examples.purs:safeDivide}} +``` + +これで、 `foldM`で安全な除算の繰り返しを表現できます。 + +```text +> import Test.Examples +> import Data.List (fromFoldable) + +> foldM safeDivide 100 (fromFoldable [5, 2, 2]) +(Just 5) + +> foldM safeDivide 100 (fromFoldable [2, 0, 4]) +Nothing +``` + +もし何れかの時点で0による除算が試みられたら、`foldM safeDivide`関数は`Nothing`を返します。 +そうでなければ、累算値を繰り返し除算した結果を`Just`構築子に包んで返します。 + +## モナドとアプリカティブ + +クラス間に上位クラス関係の効能があるため、`Monad`型クラスの全てのインスタンスは `Apply`型クラスのインスタンスでもあります。 + +しかし、あらゆる`Monad`のインスタンスに「無料で」ついてくる`Apply`型クラスの実装もあります。これは`ap`関数により与えられます。 + +```hs +ap :: forall m a b. Monad m => m (a -> b) -> m a -> m b +ap mf ma = do + f <- mf + a <- ma + pure (f a) +``` + +もし`m`に`Monad`型クラスの法則の縛りがあれば、`ap`で与えられる`m`について妥当な `Apply`インスタンスが存在します。 + +興味のある読者はこれまで登場したモナドについてこの`ap`が`apply`として充足することを確かめてみてください。 +モナドは`Array`、`Maybe`、`Either e`といったものです。 + +もし全てのモナドがアプリカティブ関手でもあるなら、アプリカティブ関手についての直感的理解を全てのモナドについても適用できるはずです。 +特に、モナドが更なる副作用の組み合わせで増強された「より大きな言語」でのプログラミングといろいろな意味で一致することを予想するのはもっともです。 +`map`と `apply`を使って、引数が任意個の関数をこの新しい言語へと持ち上げることができるはずです。 + +しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法の構文で強調されています。 +`userCity`の例についてもう一度考えてみましょう。 +利用者情報をエンコードしたXML文書から利用者の市町村を検索するものでした。 + +```hs +userCity :: XML -> Maybe XML +userCity root = do + prof <- child root "profile" + addr <- child prof "address" + city <- child addr "city" + pure city +``` + +do記法では2番目の計算が最初の結果 `prof`に依存し、3番目の計算が2番目の計算の結果`addr`に依存するというようなことができます。 +`Applicative`型クラスのインターフェイスだけを使うのでは、このように以前の値へ依存できません。 + +`pure`と `apply`だけを使って `userCity`を書こうとしてみれば、これが不可能であることがわかるでしょう。 +アプリカティブ関手ができるのは関数の互いに独立した引数を持ち上げることだけですが、モナドはもっと興味深いデータの依存関係に関わる計算を書くことを可能にします。 + +前の章では`Applicative`型クラスは並列処理を表現できることを見ました。 +持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りです。 +`Monad`型クラスは計算が前の計算の結果に依存できるようになっており、同じようにはなりません。 +つまりモナドは副作用を順番に組み合わせなければならないのです。 + +## 演習 + + 1. (簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてください。 + 関数は適切な`Maybe`型で返します。 + *手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数の型を見つけ出してください。 + これらの関数を組み合わせるには`Maybe`モナドと共にdo記法を使ってください。 + 1. (普通)一掴みの硬貨を使ってできる可能な全ての合計を決定する関数 `possibleSums`を、 `foldM`を使って書いてみましょう。 + 入力の硬貨は、硬貨の価値の配列として与えられます。この関数は次のような結果にならなくてはいけません。 + + ```text + > possibleSums [] + [0] + + > possibleSums [1, 2, 10] + [0,1,2,3,10,11,12,13] + ``` + + *手掛かり*:`foldM`を使うと1行でこの関数を書けます。 + 重複を取り除いたり、結果を並び替えたりするのに、`nub`関数や`sort`関数を使うことでしょう。 +1. (普通)`ap`関数と`apply`演算子が`Maybe`モナドを充足することを確かめてください。 + *補足*:この演習にはテストがありません。 +1. (普通)`Maybe`型についての`Monad`インスタンスが、モナド則を満たしていることを検証してください。 + このインスタンスは`maybe`パッケージで定義されています。 + *補足*:この演習にはテストがありません。 +1. (普通)リスト上の`filter`の関数を一般化した関数`filterM`を書いてください。 + この関数は次の型シグネチャを持ちます。 + + ```hs + filterM :: forall m a. Monad m => (a -> m Boolean) -> List a -> m (List a) + ``` + + 1. (難しい)全てのモナドには次で与えられるような既定の`Functor`インスタンスがあります。 + + ```hs + map f a = do + x <- a + pure (f x) + ``` + + モナド則を使って、全てのモナドが次を満たすことを証明してください。 + + ```hs + lift2 f (pure a) (pure b) = pure (f a b) + ``` + + ここで、`Applly`インスタンスは上で定義された`ap`関数を使用しています。 + `lift2`が次のように定義されていたことを思い出してください。 + + ```hs + lift2 :: forall f a b c. Apply f => (a -> b -> c) -> f a -> f b -> f c + lift2 f a b = f <$> a <*> b + ``` + + *補足*:この演習にはテストがありません。 + +## ネイティブな作用 + +ここではPureScriptで中心的な重要性のあるモナドの1つ、`Effect`モナドについて見ていきます。 + +`Effect`モナドは `Effect`モジュールで定義されています。かつてはいわゆる _ネイティブ_ +副作用を管理していました。Haskellに馴染みがあれば、これは`IO`モナドと同等のものです。 + +ネイティブな副作用とは何でしょうか。 +この副作用はPureScript特有の式とJavaScriptの式とを2分するものです。 +PureScriptの式は概して副作用とは無縁なのです。 +ネイティブな作用の例を以下に示します。 + +- コンソール入出力 +- 乱数生成 +- 例外 +- 変更可能な状態の読み書き + +また、ブラウザでは次のようなものがあります。 + +- DOM操作 +- XMLHttpRequest / AJAX呼び出し +- WebSocketによる相互作用 +- Local Storageの読み書き + +既に「ネイティブでない」副作用の例については数多く見てきています。 + +- `Maybe`データ型で表現される省略可能な値 +- `Either`データ型で表現されるエラー +- 配列やリストで表現される多値関数 + +これらの区別はわかりにくいので注意してください。 +例えば、エラー文言は例外の形でJavaScriptの式の副作用となることがあると言えます。 +その意味では例外はネイティブな副作用を表していて、`Effect`を使用して表現できます。 +しかし、`Either`を使用して実装されたエラー文言はJavaScript実行時の副作用ではなく、`Effect`を使うスタイルでエラー文言を実装するのは不適切です。 +そのため、ネイティブなのは作用自体というより、実行時にどのように実装されているかです。 + +## 副作用と純粋性 + +PureScriptのような純粋な言語では、ある疑問が浮かんできます。 +副作用がないなら、どうやって役に立つ実際のコードを書くことができるのでしょうか。 + +その答えはPureScriptの目的は副作用を排除することではないということです。 +純粋な計算と副作用のある計算とを、型システムにおいて区別できるような方法で表現します。 +この意味で、言語はあくまで純粋なのです。 + +副作用のある値は、純粋な値とは異なる型を持っています。 +そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起こらなくなります。 + +`Effect`モナドで管理された副作用を現す手段は、型`Effect a`の計算をJavaScriptから実行することです。 + +Spagoビルドツール(や他のツール)は早道を用意しており、アプリケーションの起動時に`main`計算を呼び出すための追加のJavaScriptコードを生成します。 +`main`は`Effect`モナドでの計算であることが要求されます。 + +## 作用モナド + +`Effect`は副作用のある計算を充分に型付けするAPIを提供すると同時に、効率的なJavaScriptを生成します。 + +馴染みのある`log`関数から返る型を見てみましょう。 +`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコンソールIOです。 + +`Unit`はいかなる*意味のある*データも返らないことを示しています。 +`Unit`はC、Javaなど他の言語での`void`キーワードと似たものとして考えられます。 + +```hs +log :: String -> Effect Unit +``` + +> _余談_ :より一般的な(そしてより込み入った型を持つ)`Effect.Class.Console`の`log`関数をIDEから提案されるかもしれません。 +> これは基本的な`Effect`モナドを扱う際は`Effect.Console`からの関数と交換可能です。 +> より一般的なバージョンがあることの理由は「モナドな冒険」章の「モナド変換子」について読んだあとにより明らかになっていることでしょう。 +> 好奇心のある(そしてせっかちな)読者のために言うと、これは`Effect`に`MonadEffect`インスタンスがあるから機能するのです。 +> +> ```hs +> log :: forall m. MonadEffect m => String -> m Unit +> ``` + +それでは意味のあるデータを返す`Effect`を考えましょう。 +`Effect.Random`の`random`関数は乱択された`Number`を生み出します。 + +```hs +random :: Effect Number +``` + +以下は完全なプログラムの例です(この章の演習フォルダの`test/Random.purs`にあります)。 + +```hs +{{#include ../exercises/chapter8/test/Random.purs}} +``` + +`Effect`はモナドなので、do記法を使って含まれるデータを開封し、それからこのデータを作用のある`logShow`関数に渡します。 +気分転換に、以下は`bind`演算子を使って書かれた同等なコードです。 + +```hs +main :: Effect Unit +main = random >>= logShow +``` + +これを手元で走らせてみてください。 + +```shell +spago run --main Test.Random +``` + +コンソールに出力 `0.0`と `1.0`の間で無作為に選ばれた数が表示されるでしょう。 + +> 余談:`spago run`は既定で`main`関数を`Main`モジュールの中から探索します。 +> `--main`フラグで代替のモジュールを入口として指定することも可能で、上の例ではそうしています。 +> この代替のモジュールにも`main`関数が含まれているようにはしてください。 + +なお、不浄な作用付きのコードに訴えることなく、「乱択された」(技術的には疑似乱択された)データも生成できます。 +この技法は「テストを生成する」章で押さえます。 + +以前言及したように`Effect`モナドはPureScriptで核心的な重要さがあります。 +なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りする上での常套手段だからです。 +`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕組みを提供します。 +`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように動作しどう使うのか理解することもまた極めて大事なことですので、実際にPureScriptで何か動かす前にその章を読まれることをお勧めします。 +要は`Effect`モナドは結構単純なのです。 +幾つかの補助関数がありますが、副作用を内包すること以外には大したことはしません。 + +## 例外 + +2つの*ネイティブな*副作用が絡む`node-fs`パッケージの関数を調べましょう。 +ここでの副作用は可変状態の読み取りと例外です。 + +```hs +readTextFile :: Encoding -> String -> Effect String +``` + +もし存在しないファイルを読もうとすると…… + +```hs +import Node.Encoding (Encoding(..)) +import Node.FS.Sync (readTextFile) + +main :: Effect Unit +main = do + lines <- readTextFile UTF8 "iDoNotExist.md" + log lines +``` + +以下の例外に遭遇します。 + +```text + throw err; + ^ +Error: ENOENT: no such file or directory, open 'iDoNotExist.md' +... + errno: -2, + syscall: 'open', + code: 'ENOENT', + path: 'iDoNotExist.md' +``` + +この例外をうまく管理するには、潜在的に問題があるコードを`try`に包めばどのような出力でも制御できます。 + +```hs +main :: Effect Unit +main = do + result <- try $ readTextFile UTF8 "iDoNotExist.md" + case result of + Right lines -> log $ "Contents: \n" <> lines + Left error -> log $ "Couldn't open file. Error was: " <> message error +``` + +`try`は`Effect`を走らせて起こりうる例外を`Left`値として返します。 +もし計算が成功すれば結果は`Right`に包まれます。 + +```hs +try :: forall a. Effect a -> Effect (Either Error a) +``` + +独自の例外も生成できます。 +以下は`Data.List.head`の代替実装で、`Maybe`の値の`Nothing`を返す代わりにリストが空のとき例外を投げます。 + +```hs +exceptionHead :: List Int -> Effect Int +exceptionHead l = case l of + x : _ -> pure x + Nil -> throwException $ error "empty list" +``` + +ただし`exceptionHead`関数はどこかしら非実用的な例です。 +というのも、PureScriptのコードで例外を生成するのは避け、代わりに`Either`や`Maybe`のようなネイティブでない作用でエラーや欠けた値を使うのが一番だからです。 + +## 可変状態 + +中核ライブラリには `ST`作用という、これまた別の作用も定義されています。 + +`ST`作用は変更可能な状態を操作するために使われます。 +純粋関数プログラミングを知っているなら、共有される変更可能な状態は問題を引き起こしやすいということも知っているでしょう。 +しかし、`ST`作用は型システムを使って安全で*局所的な*状態変化を可能にし、状態の共有を制限するのです。 + +`ST`作用は `Control.Monad.ST`モジュールで定義されています。 +この挙動を確認するには、その動作の型を見る必要があります。 + +```hs +new :: forall a r. a -> ST r (STRef r a) + +read :: forall a r. STRef r a -> ST r a + +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`の可変参照領域を新規作成するのに使われます。 +この領域は`read`動作を使って読み取ったり、`write`動作や`modify`動作で状態を変更するのに使えます。 +型`a`は領域に格納された値の型を、型`r`は*メモリ領域*(または*ヒープ*)を、それぞれ型システムで表しています。 + +例を示します。 +重力に従って落下する粒子の落下の動きをシミュレートしたいとしましょう。 +これには小さな時間刻みで簡単な更新関数の実行を何度も繰り返します。 + +粒子の位置と速度を保持する変更可能な参照領域を作成し、領域に格納された値を更新するのにforループを使うことでこれを実現できます。 + +```hs +import Prelude + +import Control.Monad.ST.Ref (modify, new, read) +import Control.Monad.ST (ST, for, run) + +simulate :: forall r. Number -> Number -> Int -> ST r Number +simulate x0 v0 time = do + ref <- new { x: x0, v: v0 } + for 0 (time * 1000) \_ -> + modify + ( \o -> + { v: o.v - 9.81 * 0.001 + , x: o.x + o.v * 0.001 + } + ) + ref + final <- read ref + pure final.x +``` + +計算の最後では、参照領域の最終的な値を読み取り、粒子の位置を返しています。 + +なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの他の部分での使用が許されない限り、これは純粋な関数のままです。 +このことが正に`ST`作用が禁止するものであることを見ていきます。 + +`ST`作用付きで計算するには、`run`関数を使用する必要があります。 + +```hs +run :: forall a. (forall r. ST r a) -> a +``` + +ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化されているということです。 +`run`に渡したどんな動作でも、*任意の領域*`r`が何であれ動作するということを意味しています。 + +しかし、ひとたび参照領域が`new`によって作成されると、その領域の型は既に固定されており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エラーになるでしょう。 +`run`が安全に`ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由なのです。 + +```hs +simulate' :: Number -> Number -> Int -> Number +simulate' x0 v0 time = run (simulate x0 v0 time) +``` + +PSCiでもこの関数を実行してみることができます。 + +```text +> import Main + +> simulate' 100.0 0.0 0 +100.00 + +> simulate' 100.0 0.0 1 +95.10 + +> simulate' 100.0 0.0 2 +80.39 + +> simulate' 100.0 0.0 3 +55.87 + +> simulate' 100.0 0.0 4 +21.54 +``` + +実は、もし `simulate`の定義を `run`の呼び出しのところへ埋め込むとすると、次のようになります。 + +```hs +simulate :: Number -> Number -> Int -> Number +simulate x0 v0 time = + run do + ref <- new { x: x0, v: v0 } + for 0 (time * 1000) \_ -> + modify + ( \o -> + { v: o.v - 9.81 * 0.001 + , x: o.x + o.v * 0.001 + } + ) + ref + final <- read ref + pure final.x +``` + +そうして、参照領域はそのスコープから逃れられないことと、安全に`ref`を`var`に変換できることにコンパイラが気付きます。 +`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになります。 + +```javascript +var simulate = function (x0) { + return function (v0) { + return function (time) { + return (function __do() { + + var ref = { value: { x: x0, v: v0 } }; + + Control_Monad_ST_Internal["for"](0)(time * 1000 | 0)(function (v) { + return Control_Monad_ST_Internal.modify(function (o) { + return { + v: o.v - 9.81 * 1.0e-3, + x: o.x + o.v * 1.0e-3 + }; + })(ref); + })(); + + return ref.value.x; + + })(); + }; + }; +}; +``` + +> なお、この結果として得られたJavaScriptは最適化の余地があります。 +> 詳細は[こちらの課題](https://github.com/purescript-contrib/purescript-book/issues/121)を参照してください。 +> 上記の抜粋はそちらの課題が解決されたら更新されるでしょう。 + +比較としてこちらが埋め込まれていない形式で生成されたJavaScriptです。 + +```js +var simulate = function (x0) { + return function (v0) { + return function (time) { + return function __do() { + + var ref = Control_Monad_ST_Internal["new"]({ x: x0, v: v0 })(); + + Control_Monad_ST_Internal["for"](0)(time * 1000 | 0)(function (v) { + return Control_Monad_ST_Internal.modify(function (o) { + return { + v: o.v - 9.81 * 1.0e-3, + x: o.x + o.v * 1.0e-3 + }; + })(ref); + })(); + + var $$final = Control_Monad_ST_Internal.read(ref)(); + return $$final.x; + }; + }; + }; +}; +``` + +局所的な変更可能状態を扱うとき、`ST`作用は短いJavaScriptを生成する良い方法となります。 +作用を持つ繰り返しを生成する`for`、`foreach`、`while`のような動作を一緒に使うときは特にそうです。 + +## 演習 + +1. (普通)`safeDivide`関数を書き直し、もし分母がゼロなら`throwException`を使って文言`"div + zero"`の例外を投げるようにしたものを`exceptionDivide`としてください。 +1. (普通)関数`estimatePi :: Int -> Number`を書いてください。 + この関数は`n`項[Gregory + Series](https://mathworld.wolfram.com/GregorySeries.html)を使って`pi`の近似を計算するものです。 + *手掛かり*:解答は上記の`simulate`の定義に倣うことができます。 + また`Data.Int`の`toNumber :: Int -> + Number`を使って、`Int`を`Number`に変換する必要があるかもしれません。 +1. (普通)`n`番目のフィボナッチ数を計算する関数`fibonacci :: Int -> + Int`を書いてください。`ST`を使って前の2つのフィボナッチ数の値を把握します。新しい`ST`に基づく実装の実行速度を第4章の再帰実装に対して比較してください。 + +## DOM作用 + +この章の最後の節では、`Effect`モナドでの作用についてこれまで学んだことを、実際のDOM操作の問題に応用します。 + +DOMを直接扱ったり、オープンソースのDOMライブラリを扱ったりするPureScriptパッケージが沢山あります。 +例えば以下です。 + +- [`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ライブラリもあります。 +以下のようなものです。 + +- [`thermite`](https://github.com/paf31/purescript-thermite)は[`react`](https://github.com/purescript-contrib/purescript-react)を土台に構築されています。 +- [`react-basic-hooks`](https://github.com/megamaddu/purescript-react-basic-hooks)は[`react-basic`](https://github.com/lumihq/purescript-react-basic)を土台に構築されています。 +- [`halogen`](https://github.com/purescript-halogen/purescript-halogen)は独自の仮想DOMライブラリを土台とする型安全な一揃いの抽象化を提供します。 + +この章では +`react-basic-hooks`ライブラリを使用し、住所簿アプリケーションにユーザーインターフェイスを追加しますが、興味のあるユーザは異なるアプローチで進めることをお勧めします。 + +## 住所録のユーザーインターフェース + +`react-basic-hooks`ライブラリを使い、アプリケーションをReact*コンポーネント*として定義していきます。ReactコンポーネントはHTML要素を純粋なデータ構造としてコードで記述します。それからこのデータ構造は効率的にDOMへ描画されます。加えてコンポーネントはボタンクリックのようなイベントに応答できます。`react-basic-hooks`ライブラリは`Effect`モナドを使ってこれらのイベントの制御方法を記述します。 + +Reactライブラリの完全な入門はこの章の範囲をはるかに超えていますが、読者は必要に応じて説明書を参照することをお勧めします。 +目的に応じて、Reactは `Effect`モナドの実用的な例を提供してくれます。 + +利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。 +フォームには、様々なフィールド(姓、名、市町村、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。 +テキストボックスに利用者がテキストを入力する度に、検証エラーが更新されます。 + +簡潔さを保つために、フォームは固定の形状とします。電話番号は種類(自宅、携帯電話、仕事、その他)ごとに別々のテキストボックスへ分けることにします。 + +`exercises/chapter8`ディレクトリから以下のコマンドでwebアプリを立ち上げることができます。 + +```shell +$ npm install +$ npx spago build +$ npx parcel src/index.html --open +``` + +もし`spago`や`parcel`のような開発ツールが大域的にインストールされていれば、`npx`の前置は省けるでしょう。 +恐らく既に`spago`を`npm i -g spago`で大域的にインストールしていますし、`parcel`についても同じことができるでしょう。 + +`parcel`は「アドレス帳」アプリのブラウザ窓を立ち上げます。 +`parcel`の端末を開いたままにし、他の端末で`spago`で再構築すると、最新の編集を含むページが自動的に再読み込みされるでしょう。 +また、[`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)を使っていれば、ファイルを保存したときに自動的にページが再構築される(そして自動的にページが再読み込みされる)ように設定できます。 + +このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上で出力された検証エラーが見られます。 + +動作の仕組みを散策しましょう。 + +`src/index.html`ファイルは最小限です。 + +```html +{{#include ../exercises/chapter8/src/index.html}} +``` + +`>= document >>= toNonElementParentNode >>> getElementById "container" +``` + +途中の`w`や`doc`変数が読みやすさの助けになるかは主観的な好みの問題です。 + +AddressBookの`reactComponent`を深堀りしましょう。 +単純化されたコンポーネントから始め、それから`Main.purs`で実際のコードに構築していきます。 + +以下の最小限のコンポーネントをご覧ください。 +遠慮なく全体のコンポーネントをこれに置き換えて実行の様子を見てみましょう。 + +```hs +mkAddressBookApp :: Effect (ReactComponent {}) +mkAddressBookApp = + reactComponent + "AddressBookApp" + (\props -> pure $ D.text "Hi! I'm an address book") +``` + +`reactComponent`にはこのような威圧的なシグネチャがあります。 + +```hs +reactComponent :: + forall hooks props. + Lacks "children" props => + Lacks "key" props => + Lacks "ref" props => + String -> + ({ | props } -> Render Unit hooks JSX) -> + Effect (ReactComponent { | props }) +``` + +重要な注意点は全ての型クラス制約の後の引数にあります。 +`String`(任意のコンポーネント名)、`props`を描画された`JSX`に変換する方法を記述する関数を取り、そして`Effect`に包まれた`ReactComponent`を返します。 + +propsからJSXへの関数は単にこうです。 + +```hs +\props -> pure $ D.text "Hi! I'm an address book" +``` + +`props`は無視されており、`D.text`は`JSX`を返し、そして`pure`は描画されたJSXに持ち上げます。 +これで`component`には`ReactComponent`を生成するのに必要な全てがあります。 + +次に、完全なアドレス帳コンポーネントにある幾つかの複雑な事柄を調べていきます。 + +これらは完全なコンポーネントの最初の数行です。 + +```hs +mkAddressBookApp :: Effect (ReactComponent {}) +mkAddressBookApp = do + reactComponent "AddressBookApp" \props -> R.do + Tuple person setPerson <- useState examplePerson +``` + +`person`を`useState`フックの状態の一部として追跡します。 + +```hs +Tuple person setPerson <- useState examplePerson +``` + +なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部品に分解することが自在にできます。 +例えば`Person`の各レコードフィールドについて分離した状態の部品を使って、このアプリを書き直すことができるでしょう。 +しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいます。 + +他の例では`Tuple`用の`/\`中置演算子に出喰わすかもしれません。 +これは先の行と等しいものです。 + +```hs +firstName /\ setFirstName <- useState p.firstName +``` + +`useState`は、既定の初期値を取って現在の値と値を更新する方法を取ります。 +`useState`の型を確認すれば型`person`と`setPerson`についてより深い洞察が得られます。 + +```hs +useState :: + forall state. + state -> + Hook (UseState state) (Tuple state ((state -> state) -> Effect Unit)) +``` + +結果の値の梱包`Hook (UseState +state)`は取り去ることができますが、それは`useState`が`R.do`ブロックの中で呼ばれているからです。 +`R.do`は後で詳述します。 + +さてこれで以下のシグネチャを観察できます。 + +```hs +person :: state +setPerson :: (state -> state) -> Effect Unit +``` + +`state`の限定された型は初期の既定値によって決定されます。 +これは`examplePerson`の型なのでこの場合は`Person` `Record`です。 + +`person`は各再描画の時点で現在の状態にアクセスする方法です。 + +`setPerson`は状態を更新する方法です。 +単に現在の状態を新しい状態に変形する方法を記述する関数を提供します。 +`state`の型が偶然`Record`のときは、レコード更新構文がこれにぴったり合います。 +例えば以下。 + +```hs +setPerson (\currentPerson -> currentPerson {firstName = "NewName"}) + +``` + +あるいは短かく以下です。 + +```hs +setPerson _ {firstName = "NewName"} +``` + +`Record`でない状態もまた、この更新パターンに従います。 +ベストプラクティスについて、より詳しいことは[この手引き](https://github.com/megamaddu/purescript-react-basic-hooks/pull/24#issuecomment-620300541)を参照してください。 + +`useState`が`R.do`ブロックの中で使われていることを思い出しましょう。 +`R.do`は`do`の特別なreactフックの派生です。 +`R.`の前置はこれが`React.Basic.Hooks`から来たものとして「限定する」もので、`R.do`ブロックの中でフック互換版の`bind`を使うことを意味しています。 +これは「限定されたdo」として知られています。 +`Hook (UseState state)`の梱包を無視し、内部の値の`Tuple`と変数に束縛してくれます。 + +他の状態管理戦略として挙げられるのは`useReducer`ですが、それはこの章の範疇外です。 + +以下では`JSX`の描画が行われています。 + +```hs +pure + $ D.div + { className: "container" + , children: + renderValidationErrors errors + <> [ D.div + { className: "row" + , children: + [ D.form_ + $ [ D.h3_ [ D.text "Basic Information" ] + , formField "First Name" "First Name" person.firstName \s -> + setPerson _ { firstName = s } + , formField "Last Name" "Last Name" person.lastName \s -> + setPerson _ { lastName = s } + , D.h3_ [ D.text "Address" ] + , formField "Street" "Street" person.homeAddress.street \s -> + setPerson _ { homeAddress { street = s } } + , formField "City" "City" person.homeAddress.city \s -> + setPerson _ { homeAddress { city = s } } + , formField "State" "State" person.homeAddress.state \s -> + setPerson _ { homeAddress { state = s } } + , D.h3_ [ D.text "Contact Information" ] + ] + <> renderPhoneNumbers + ] + } + ] + } +``` + +ここでDOMの意図した状態を表現する`JSX`を生成しています。 +このJSXは単一のHTML要素を作るHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、`label`、`input`)に対応する関数を適用することで作られるのが普通です。 +これらのHTML要素はそれ自体がReactコンポーネントであり、JSXに変換されます。 +通常これらの関数にはそれぞれ3つの種類があります。 + +- `div_`: 子要素の配列を受け付けます。 + 既定の属性を使います。 +- `div`: 属性の`Record`を受け付けます。 + 子要素の配列をこのレコードの`children`フィールドに渡すことができます。 +- `div'`: `div`と同じですが、`JSX`に変換する前に`ReactComponent`を返します。 + +検証エラーをフォームの一番上に(もしあれば)表示するため、`Errors`構造体をJSXの配列に変える`renderValidationErrors`補助関数を作ります。この配列はフォームの残り部分の手前に付けます。 + +```hs +{{#include ../exercises/chapter8/src/Main.purs:renderValidationErrors}} +``` + +なお、ここでは単に通常のデータ構造体を操作しているので、`map`のような関数を使ってもっと面白い要素を構築できます。 + +```hs +children: [ D.ul_ (map renderError xs)] +``` + +`className`プロパティを使ってCSSスタイルのクラスを定義します。 +このプロジェクトでは[Bootstrap](https://getbootstrap.com/)の`stylesheet`を使っており、これは`index.html`でインポートされています。 +例えばフォーム中のアイテムは`row`として配置されてほしいですし、検証エラーは`alert-danger`の装飾で強調されていてほしいです。 + +```hs +className: "alert alert-danger row" +``` + +2番目の補助関数は `formField`です。 +これは、単一フォームフィールドのテキスト入力を作ります。 + +```hs +{{#include ../exercises/chapter8/src/Main.purs:formField}} +``` + +`input`を置いて`label`の中に`text`を表示すると、スクリーンリーダーのアクセシビリティの助けになります。 + +`onChange`属性があれば利用者の入力に応答する方法を記述できます。`handler`関数を使いますが、これは以下の型を持ちます。 + +```hs +handler :: forall a. EventFn SyntheticEvent a -> (a -> Effect Unit) -> EventHandler +``` + +`handler`への最初の引数には`targetValue`を使いますが、これはHTMLの`input`要素中のテキストの値を提供します。 +この場合は型変数`a`が`Maybe String`で、`handler`が期待するシグネチャに合致しています。 + +```hs +targetValue :: EventFn SyntheticEvent (Maybe String) +``` + +JavaScriptでは`input`要素の`onChange`イベントには`String`値が伴います。 +しかし、JavaScriptの文字列はnullになり得るので、安全のために`Maybe`が使われています。 + +したがって`(a -> Effect Unit)`の`handler`への2つ目の引数は、このシグネチャを持ちます。 + +```hs +Maybe String -> Effect Unit +``` + +この関数は`Maybe String`値を求める作用に変換する方法を記述します。 +この目的のために以下のように独自の`handleValue`関数を定義して`handler`を渡します。 + +```hs +onChange: + let + handleValue :: Maybe String -> Effect Unit + handleValue (Just v) = setValue v + handleValue Nothing = pure unit + in + handler targetValue handleValue +``` + +`setValue`は`formField`の各呼び出しに与えた関数で、文字列を取り`setPerson`フックに適切なレコード更新呼び出しを実施します。 + +なお、`handleValue`は以下のようにも置き換えられます。 + +```hs +onChange: handler targetValue $ traverse_ setValue +``` + +`traverse_`の定義を調査して、両方の形式が確かに等価であることをご確認ください。 + +これでコンポーネント実装の基本を押さえました。 +しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随するソースをお読みください。 + +明らかに、このユーザーインターフェースには改善すべき点が沢山あります。 +演習ではアプリケーションがより使いやすくなるような方法を追究していきます。 + +## 演習 + +以下の演習では`src/Main.purs`を変更してください。 +これらの演習には単体試験はありません。 + +1. (簡単)このアプリケーションを変更し、職場の電話番号を入力できるテキストボックスを追加してください。 +1. (普通)現時点でアプリケーションは検証エラーを単一の「pink-alert」背景に集めて表示させています。 + 空行で分離することにより、各検証エラーにpink-alert背景を持たせるように変更してください。 + + *手掛かり*:リスト中の検証エラーを表示するのに`ul`要素を使う代わりに、コードを変更し、各エラーに`alert`と`alert-danger`装飾を持つ`div`を作ってください。 +1. (難しい、発展)このユーザーインターフェイスの問題の1つは、検証エラーがその発生源であるフォームフィールドの隣に表示されていないことです。 + コードを変更してこの問題を解決してください。 + + *手掛かり*:検証器によって返されるエラーの型を、エラーの原因となっているフィールドを示すために拡張するべきです。 + 以下の変更されたエラー型を使うと良いでしょう。 + + ```hs + data Field = FirstNameField + | LastNameField + | StreetField + | CityField + | StateField + | PhoneField PhoneType + + data ValidationError = ValidationError String Field + + type Errors = Array ValidationError + ``` + + `Error`構造体から特定の`Field`のための検証エラーを取り出す関数を書く必要があるでしょう。 + +## まとめ + +この章ではPureScriptでの副作用の扱いについての多くの考え方を導入しました。 + +- `Monad`型クラスとdo記法との関係性を見ました。 +- モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。 +- 異なる副作用を扱うコードを書く上で、モナドを抽象的に使う方法を見ました。 +- モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算を可能にするのかということ、そして2つの手法の違いを説明しました。 +- ネイティブな作用の概念を定義し、`Effect`モナドを見ました。 + これはネイティブな副作用を扱うものでした。 +- 乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作といった、様々な作用を扱うために + `Effect`モナドを使いました。 + +`Effect`モナドは実際のPureScriptコードにおける基本的なツールです。本書ではこのあとも、多くの場面で副作用を処理するために使っていきます。 diff --git a/text-ja/chapter9.md b/text-ja/chapter9.md index 5fc817fd..ae76c574 100644 --- a/text-ja/chapter9.md +++ b/text-ja/chapter9.md @@ -2,11 +2,10 @@ ## この章の目標 -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 managing sequential and parallel execution of -asynchronous effects. +この章では`Aff`モナドに集中します。 +これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。 +非同期にファイルシステムとやり取りしたりHTTPリクエストしたりする例を実演していきます。 +また非同期作用の直列ないし並列な実行の管理方法も押さえます。 ## プロジェクトの準備 @@ -17,9 +16,9 @@ asynchronous effects. - `affjax` - AJAXと`Aff`を使ったHTTPリクエスト。 - `parallel` - `Aff`の並列実行。 -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 a -dependency in the `package.json` of this chapter. Install that by running: +(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリには`xhr2`NPMモジュールが必要です。 +このモジュールはこの章の`package.json`中の依存関係に挙げられています。 +以下を走らせてインストールします。 ```shell $ npm install @@ -46,8 +45,7 @@ copyFile('file1.txt', 'file2.txt') }); ``` -It is also possible to use callbacks or synchronous functions, but those are -less desirable because: +コールバックや同期関数を使うことも可能ですが、以下の理由から望ましくありません。 - コールバックは過剰な入れ子に繋がります。これは「コールバック地獄」や「悪夢のピラミッド」として知られています。 - 同期関数はアプリ中の他のコードの実行を堰き止めてしまいます。 @@ -63,14 +61,11 @@ PureScriptでの`Aff`モナドはJavaScriptの`async`/`await`構文に似た人 なお、`main`は`Effect Unit`でなければならないので、`launchAff_`を使って`Aff`から`Effect`へと変換せねばなりません。 -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`, -respectively), but those share the same downsides as discussed earlier with -JavaScript, so that coding style is not recommended. +上のコード片をコールバックや同期関数を使って書き換えることも可能です(例えば`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)。 +しかし、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それらのコーディング形式は推奨されません。 -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. +`Aff`を扱う文法は`Effect`を扱うものと大変似ています。 +どちらもモナドですし、したがってdo記法で書けます。 例えば`readTextFile`のシグネチャを見れば、これがファイルの内容を`String`とし、`Aff`に包んで返していることがわかります。 @@ -100,23 +95,19 @@ attempt :: forall a. Aff a -> Aff (Either Error a) ## 演習 - 1. (Easy) Write a `concatenateFiles` function that concatenates two text - files. + 1. (簡単)2つのテキストファイルを連結する関数`concatenateFiles`を書いてください。 - 1. (Medium) Write a function `concatenateMany` to concatenate multiple text - files, given an array of input and output file names. _Hint_: use - `traverse`. + 1. (普通)複数のテキストファイルを連結する関数`concatenateMany`を書いてください。 + 入力ファイル名の配列と出力ファイル名が与えられます。 + *手掛かり*:`traverse`を使ってください。 1. (普通)ファイル中の文字数を返すか、エラーがあればそれを返す関数`countCharacters :: FilePath -> Aff (Either Error Int)`を書いてください。 ## 更なる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 -some functions on Pursuit. +もしまだ[公式のAffの手引き](https://pursuit.purescript.org/packages/purescript-aff/)を見ていなければ、今ざっと目を通してください。 +この章の残りの演習を完了する上で事前に直接必要なことではありませんが、Pursuitで何らかの関数を見付けだす助けになるかもしれません。 以下の補足資料についてもあたってみるとよいでしょう。しかし繰り返しになりますがこの章の演習はこれらの内容に依りません。 @@ -125,19 +116,12 @@ some functions on Pursuit. ## HTTPクライアント -The `affjax` library offers a convenient way to make asynchronous AJAX HTTP -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. +`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)のどちらかのライブラリを使う必要があります。 -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: +この章の以降ではnodeを対象としていくので、`purescript-affjax-node`を使います。 +より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript.org/packages/purescript-affjax)にあたってください。 +以下は与えられたURLに向けてHTTPのGET要求をして、応答本文ないしエラー文言を返す例です。 ```hs {{#include ../exercises/chapter9/test/HTTP.purs:getUrl}} @@ -172,12 +156,9 @@ unit 非同期計算を*並列にも*合成できたら便利でしょう。 `Aff`があれば2つの計算を次々に開始するだけで並列に計算できます。 -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` that can be used to combine computations in parallel: +`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義しており、並列実行に対応しています。 +以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリカティブ関手がどれほど便利なのかを見ました。 +実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を組み合わせるために使えるアプリカティブ関手`f`との対応関係を定義しているのです。 ```hs class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where @@ -190,19 +171,16 @@ class (Monad m, Applicative f) <= Parallel f m | m -> f, f -> m where - `parallel`:モナド`m`中の計算を取り、アプリカティブ関手`f`中の計算に変えます。 - `sequential`:反対方向に変換します。 -The `aff` library provides a `Parallel` instance for the `Aff` monad. It -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. +`aff`ライブラリは`Aff`モナドの`Parallel`インスタンスを提供します。 +これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に`Aff`動作を組み合わせます。 +両方の結果が返されたら、最終結果を計算してメインの継続に渡せます。 アプリカティブ関手では任意個の引数の関数の持ち上げができるので、このアプリカティブコンビネータを使ってより多くの計算を並列に実行できます。 `traverse`や`sequence`といった、アプリカティブ関手を扱う全ての標準ライブラリ関数から恩恵を受けることもできます。 -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. +直列的なコードの一部と並列計算を組み合わせることもできます。 +それにはdo記法ブロック中でアプリカティブコンビネータを使います。 +その逆も然りで、必要に応じて`parralel`と`sequential`を使って型構築子を変更すれば良いのです。 直列実行と並列実行の間の違いを実演するために、100個の10ミリ秒の遅延からなる配列をつくり、それからその遅延を両方の手法で実行します。REPLで試すと`seqDelay`が`parDelay`より遥かに遅いことに気付くでしょう。並列実行が`sequence_`を`parSequence_`で置き換えるだけで有効になるところに注目です。 @@ -247,20 +225,18 @@ unit ## 演習 -1. (Easy) Write a `concatenateManyParallel` function with the same signature - as the earlier `concatenateMany` function but reads all input files in - parallel. +1. (簡単)前の`concatenateMany`関数と同じシグネチャを持つ`concatenateManyParallel`関数を書いてください。 + ただし全ての入力ファイルを並列に読むようにしてください。 1. (普通)与えられたURLへHTTP `GET`を要求して以下の何れかを返す`getWithTimeout :: Number -> String -> Aff (Maybe String)`関数を書いてください。 - `Nothing`: 要求してから与えられた時間制限(ミリ秒単位)より長く掛かった場合。 - 文字列の応答:時間制限を越える前に要求が成功した場合。 -1. (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 some helpful functions for negotiating directories. +1. (難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてください。 + 一覧にあるファイルを並列に読んでください。 + パスはそのファイルが現れたディレクトリから相対的なものです。 + *手掛かり*:`node-path`モジュールにはディレクトリを扱う上で便利な関数があります。 例えば次のような`root.txt`ファイルから始まるとします。 @@ -291,7 +267,7 @@ $ cat c/a/a.txt ## まとめ -In this chapter, we covered asynchronous effects and learned how to: +この章では非同期作用と以下の方法を押さえました。 - `aff`ライブラリを使って`Aff`モナド中で非同期コードを走らせる。 - `affjax`ライブラリを使って非同期にHTTPリクエストする。 diff --git a/text-ja/index.md b/text-ja/index.md index 73f5b14d..cba01101 100644 --- a/text-ja/index.md +++ b/text-ja/index.md @@ -13,7 +13,7 @@ PureScriptのエコシステムの最新の機能を紹介すべく書き直さ 本書は言語の進化に伴って継続的に更新されているため、内容に関して発見したどんな[問題](https://github.com/purescript-contrib/purescript-book/issues)でもご報告ください。 より初心者にやさしくできそうな分かりづらい節を指摘するような単純なものであれ、共有いただいたどんなフィードバックにも感謝します。 -それぞれの章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確かめることができます。 +各章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確かめることができます。 テストの最新の状態については[#79](https://github.com/purescript-contrib/purescript-book/issues/79)を見てください。 ## 本書について @@ -27,7 +27,7 @@ PureScriptは、強力に型付けされた関数型プログラミングの力 本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。 -それぞれの章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。 +各章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。 以下は本書で解いていく課題の幾つかの例です。 - マップと畳み込みを使ったデータ構造の変換 diff --git a/translation/ja.po b/translation/ja.po index 3b95d552..464b3dce 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-15 06:48+0900\n" +"PO-Revision-Date: 2023-08-19 19:52+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -578,7 +578,7 @@ msgstr "" #: text/chapter1.md:66 #, no-wrap msgid "Polyglot Web Programming" -msgstr "多言語Webプログラミング" +msgstr "多言語webプログラミング" #. type: Plain text #: text/chapter1.md:69 @@ -953,7 +953,7 @@ msgid "" "several learning resources, including code samples, videos, and other " "resources for beginners." msgstr "" -"[PureScriptのWebサイト](https://www.purescript.org)には幾つかの学習資料へのリンクがあります。\n" +"[PureScriptのwebサイト](https://www.purescript.org)には幾つかの学習資料へのリンクがあります。\n" "コード例、映像、他の初心者向け資料などです。" #. type: Bullet: '- ' @@ -963,7 +963,7 @@ msgid "" "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 @@ -1082,21 +1082,14 @@ msgstr "この章の目標" #. type: Plain text #: text/chapter10.md:6 -#, fuzzy -#| msgid "" -#| "This chapter will introduce PureScript's _foreign function interface_ (or " -#| "_FFI_), which enables communication from PureScript code to JavaScript " -#| "code, and vice versa. We will cover how to:" msgid "" "This chapter will introduce PureScript's _foreign function interface_ (or " "_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コードからJavaScriptコードへの呼び出し、及びその逆が可能" -"になります。\n" -"これから扱うのは次のようなものです。" +"本章ではPureScriptの*外部関数インターフェース* (foreign function interface; *FFI*) を紹介します。\n" +"これによりPureScriptコードからJavaScriptコードへの呼び出し、及びその逆が可能になります。\n" +"以下の方法を押さえていきます。" #. type: Bullet: '- ' #: text/chapter10.md:10 @@ -1140,16 +1133,20 @@ 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 -#, fuzzy msgid "" "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: '- ' @@ -1173,19 +1170,13 @@ msgstr "プロジェクトの準備" #. type: Plain text #: text/chapter10.md:24 -#, fuzzy -#| 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 " -#| "source files from those chapters." 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 " "source files from those chapters." msgstr "" -"このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。そうし" -"たわけでソースツリーにはこれらの章からの適切なソースファイルが含まれていま" -"す。" +"このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。\n" +"そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれています。" #. type: Plain text #: text/chapter10.md:26 @@ -1226,15 +1217,6 @@ msgstr "免責事項" #. type: Plain text #: text/chapter10.md:34 -#, fuzzy -#| 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." msgid "" "PureScript provides a straightforward foreign function interface to make " "working with JavaScript as simple as possible. However, it should be noted " @@ -1243,24 +1225,13 @@ msgid "" "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" -"この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝" -"授することを目指します。" +"JavaScriptの扱いをできる限り単純にするため、PureScriptは直感的な外部関数インターフェースを提供しています。\n" +"しかし、FFIはこの言語の*応用的な*機能であることには心に留めておかれると良いでしょう。\n" +"安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現について理解していなければなりません。\n" +"この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝授することを目指します。" #. type: Plain text #: text/chapter10.md:36 -#, fuzzy -#| 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 of foreign code. Code in the standard libraries tends to favor " -#| "the latter approach." 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 " @@ -1269,10 +1240,8 @@ msgid "" "approach." msgstr "" "PureScriptのFFIはとても柔軟に設計されています。\n" -"実際には、外部関数に最低限の型だけを与えるか、それとも型システムを利用して外" -"部のコードの誤った使い方を防ぐようにするか、開発者が選べるということを意味し" -"ています。\n" -"標準ライブラリのコードは、後者の手法を好む傾向にあります。" +"実際には、外部関数にとても単純な型を与えるか、型システムを利用して外部のコードの誤った使い方を防ぐようにするか、開発者が選べるようになっています。\n" +"標準ライブラリのコードは、後者の手法を採る傾向にあります。" #. type: Plain text #: text/chapter10.md:38 @@ -1337,10 +1306,11 @@ msgstr "" #. type: Plain text #: text/chapter10.md:53 -#, fuzzy, 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" +#, 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" +msgstr "" +"この関数は関数の型`String -> String`について適切な実行時表現を持っています。\n" +"`null`でない文字列を取って`null`でない文字列にするもので、副作用を持たないからです。\n" #. type: Plain text #: text/chapter10.md:55 @@ -1359,14 +1329,6 @@ msgstr "{{#include ../exercises/chapter10/test/URI.purs}}\n" #. type: Plain text #: text/chapter10.md:62 -#, fuzzy -#| 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 " -#| "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 `_encodeURIComponent`:" 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 the " @@ -1511,18 +1473,13 @@ msgstr "{{#include ../exercises/chapter10/test/Examples.purs:diagonal}}\n" #. type: Plain text #: text/chapter10.md:114 -#, fuzzy -#| 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 returns a `Number`." 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 " "returns a `Number`." msgstr "" -"PureScriptの関数は _カリー化_ されていることを思い出してください。\n" -"`diagonal`は`Number`を取って _関数_ を返す関数です。\n" +"PureScriptの関数は*カリー化*されていることを思い出してください。\n" +"`diagonal`は`Number`を取って*関数*を返す関数です。\n" "そして返された関数は`Number`を取って`Number`を返します。" #. type: Fenced code block (js) @@ -1644,14 +1601,12 @@ msgstr "" #. type: Plain text #: text/chapter10.md:166 -#, fuzzy -#| msgid "" -#| "We can then call it with `runFn2` which takes the uncurried function then " -#| "the arguments." msgid "" "We can then call it with `runFn2`, which takes the uncurried function and " "then the arguments." -msgstr "カリー化されていない関数と引数を取る`runFn2`で呼び出すことができます。" +msgstr "" +"そうして`runFn2`を使って呼び出せます。\n" +"これはカリー化されていない関数と引数を取るものです。" #. type: Fenced code block (text) #: text/chapter10.md:167 @@ -1688,7 +1643,6 @@ msgstr "カリー化されていない関数についての補足" #. type: Plain text #: text/chapter10.md:181 -#, fuzzy msgid "" "PureScript's curried functions have certain advantages. It allows us to " "partially apply functions, and to give type class instances for function " @@ -1699,7 +1653,7 @@ msgstr "" "PureScriptのカリー化された関数には勿論利点があります。\n" "部分的に関数を適用でき、関数型に型クラスインスタンスを与えられるのです。\n" "しかし効率上の代償も付いてきます。\n" -"効率性が決定的に重要なコードでは多変数を受け付けるカリー化されていないJavaScript関数を定義する必要が時々あります。" +"効率性が決定的に重要なコードでは時々、多変数を受け付けるカリー化されていないJavaScript関数を定義する必要があります。" #. type: Plain text #: text/chapter10.md:183 @@ -1771,10 +1725,6 @@ msgstr "{{#include ../exercises/chapter10/test/Examples.purs:curried_add}}\n" #. type: Plain text #: text/chapter10.md:211 -#, fuzzy -#| msgid "" -#| "and the resulting generated code, which is less compact due to the nested " -#| "functions:" msgid "" "And the resulting generated code, which is less compact due to the nested " "functions:" @@ -1810,13 +1760,6 @@ msgstr "現代的なJavaScriptの構文についての補足" #. type: Plain text #: text/chapter10.md:225 -#, fuzzy -#| msgid "" -#| "The arrow function syntax we saw earlier is an ES6 feature, and so it 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 browser." msgid "" "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 " @@ -1824,19 +1767,11 @@ msgid "" "caniuse.com/#feat=arrow-functions) who have not yet updated their web " "browser." msgstr "" -"前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しす" -"ればIE11)と互換性がありません。\n" -"執筆時点でWebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことがで" -"きないと推計](https://caniuse.com/#feat=arrow-functions)されています。" +"前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しすればIE11)と互換性がありません。\n" +"執筆時点でwebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことができないと推計](https://caniuse.com/#feat=arrow-functions)されています。" #. type: Plain text #: text/chapter10.md:227 -#, fuzzy -#| 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." msgid "" "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 " @@ -1849,20 +1784,11 @@ msgstr "" #. type: Plain text #: text/chapter10.md:229 -#, fuzzy -#| msgid "" -#| "You may still use arrow functions in your own FFI code, but then 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." msgid "" "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)などのツールを含めるべきです。" +msgstr "それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程でES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/babel#intro)などのツールを含めると良いでしょう。" #. type: Plain text #: text/chapter10.md:231 @@ -1987,23 +1913,14 @@ msgstr "" #. type: Plain text #: text/chapter10.md:266 -#, fuzzy -#| 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." msgid "" "To demonstrate passing `Array`s, here's how to call a JavaScript function " "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 @@ -2053,22 +1970,14 @@ msgstr "" #. type: Plain text #: text/chapter10.md:292 -#, fuzzy -#| 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:" msgid "" "To demonstrate passing `Records`, here's how to call a JavaScript function " "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" -"PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意して" -"ください。" +"`Record`を渡すところを実演するために、以下に2つの`Complex`な数をレコードとして取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。\n" +"PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意してください。" #. type: Fenced code block (hs) #: text/chapter10.md:293 @@ -2124,13 +2033,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:320 -#, fuzzy -#| 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." msgid "" "Note that the above techniques require trusting that JavaScript will return " "the expected types, as PureScript cannot apply type checking to JavaScript " @@ -2138,10 +2040,10 @@ msgid "" "the JSON section, as well as cover techniques to protect against type " "mismatches." msgstr "" -"なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要がありま" -"す。PureScriptはJavaScriptのコードに型検査を適用できないからです。この型安全" -"性の配慮について後のJSONの節でより詳しく記述していきます。型の不整合から身を" -"守る手法についても押さえます。" +"なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要があります。\n" +"PureScriptはJavaScriptのコードに型検査を適用できないからです。\n" +"この型安全性の配慮について後のJSONの節でより詳しく解説していきます。\n" +"型の不整合から身を守る手法についても押さえます。" #. type: Bullet: '1. ' #: text/chapter10.md:324 @@ -2316,32 +2218,21 @@ msgstr "forall a. (forall x. x -> Maybe x) -> (forall x. Maybe x) -> Array a -> #. type: Plain text #: text/chapter10.md:387 -#, fuzzy -#| msgid "and not:" msgid "And not:" msgstr "以下ではないことに注意です。" #. type: Fenced code block (hs) #: text/chapter10.md:388 -#, fuzzy, no-wrap -#| msgid "forall a. ( a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" +#, 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" +msgstr "forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" #. type: Plain text #: text/chapter10.md:393 -#, fuzzy -#| 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:" msgid "" "While both forms work, the latter is more vulnerable to unwanted inputs in " "place of `Just` and `Nothing`." -msgstr "" -"どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に" -"侵されやすくなります。例えばより脆弱な場合では以下のようにして呼ぶことができ" -"ます。" +msgstr "どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に対してより脆弱です。" #. type: Plain text #: text/chapter10.md:395 @@ -2361,14 +2252,9 @@ msgstr "これは如何なる配列の入力に対しても`Just 1000`を返し #. type: Plain text #: text/chapter10.md:403 -#, fuzzy, 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" +#, no-wrap 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 "" -"これはいかなる配列についても`Just 1000`を返します。\n" -"この脆弱性は`a`が`Int`のときに(これは入力の配列に基づきます)`(\\_ -> Just 1000)`と`Just 1000`がシグネチャ`(a -> Maybe a)`と`Maybe a`にそれぞれ合致しているために許されているのです。\n" +msgstr "この脆弱性では、`a`が`Int`のときに(これは入力の配列に基づきます)`(\\_ -> Just 1000)`と`Just 1000`がシグネチャ`(a -> Maybe a)`と`Maybe a`にそれぞれ照合するために許容されてしまっています。\n" #. type: Plain text #: text/chapter10.md:406 @@ -2386,20 +2272,13 @@ msgstr "外部型の定義" #. type: Plain text #: text/chapter10.md:410 -#, fuzzy -#| 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`." msgid "" "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" -"型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する" -"型がほしいです。\n" +"`Maybe a`を返す代わりに`arr[0]`を返したいのだとしましょう。\n" +"型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する型がほしいです。\n" "この型を`Undefined a`と呼びましょう。" #. type: Plain text @@ -2430,10 +2309,8 @@ msgstr "" #. type: Plain text #: text/chapter10.md:420 -#, fuzzy -#| msgid "We can now simply reuse our original definition for `head`:" msgid "We can now reuse our original definition for `head`:" -msgstr "これで元の`head`の定義を単に再利用できます。" +msgstr "これで元の`head`の定義を再利用できます。" #. type: Fenced code block (javascript) #: text/chapter10.md:421 @@ -2458,10 +2335,6 @@ msgstr "foreign import undefinedHead :: forall a. Array a -> Undefined a\n" #. type: Plain text #: text/chapter10.md:433 -#, fuzzy -#| msgid "" -#| "The body of the `undefinedHead` function returns `arr[0]` which may be " -#| "`undefined`, and the type signature correctly reflects that fact." msgid "" "The body of the `undefinedHead` function returns `arr[0]`, which may be " "`undefined`, and the type signature correctly reflects that fact." @@ -2471,18 +2344,12 @@ msgstr "" #. type: Plain text #: text/chapter10.md:435 -#, fuzzy -#| msgid "" -#| "This function has the correct runtime representation for its type, but is " -#| "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!" msgid "" "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でこの型を使えますからね。" @@ -2535,23 +2402,15 @@ msgstr "" #. type: Plain text #: text/chapter10.md:457 -#, fuzzy -#| 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 possible, and application logic moved into PureScript code " -#| "wherever possible." msgid "" "Here, the foreign function we defined is very simple, which means we can " "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コードへ移動しておくことをお勧めします。" +"一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理はPureScriptコードへ移動しておくことをお勧めします。" #. type: Title ## #: text/chapter10.md:458 text/chapter8.md:365 text/chapter8.md:444 @@ -2687,12 +2546,6 @@ msgstr "型クラスメンバー関数を使う" #. type: Plain text #: text/chapter10.md:506 -#, fuzzy -#| 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." msgid "" "Like our earlier guide on passing the `Maybe` constructor over FFI, this is " "another case of writing PureScript that calls JavaScript, which calls " @@ -2706,10 +2559,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:508 -#, fuzzy -#| msgid "" -#| "We start with writing a foreign JavaScript function which expects the " -#| "appropriate instance of `show` to match the type of `x`." msgid "" "We start with writing a foreign JavaScript function that expects the " "appropriate instance of `show` to match the type of `x`." @@ -2740,8 +2589,6 @@ msgstr "foreign import boldImpl :: forall a. (a -> String) -> a -> String\n" #. type: Plain text #: text/chapter10.md:521 -#, fuzzy -#| 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 "そして`show`の正しいインスタンスを渡す梱包関数も書きます。" @@ -2757,10 +2604,8 @@ msgstr "" #. type: Plain text #: text/chapter10.md:528 -#, fuzzy -#| msgid "Alternatively in point-free form:" msgid "Alternatively, in point-free form:" -msgstr "代わりにポイントフリー形式だとこうです。" +msgstr "代えてポイントフリー形式だとこうです。" #. type: Fenced code block (hs) #: text/chapter10.md:529 @@ -2909,10 +2754,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:592 -#, fuzzy -#| 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." 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." @@ -2955,14 +2796,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:606 -#, fuzzy -#| 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. 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 wouldn't find that in the existing JavaScript " -#| "ecosystem." 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. " @@ -3144,20 +2977,13 @@ msgstr "" #. type: Plain text #: text/chapter10.md:678 -#, fuzzy -#| 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." msgid "" "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`で走らせた場合、印字の _合間に_ 僅かな遅延があり、よ" -"り予測に近い挙動をします。" +"REPLでの非同期ログ出力はブロック全体が実行を終了するまで印字を待機する点に注意しましょう。\n" +"このコードを`spago test`で走らせた場合、印字の*合間に*僅かな遅延があり、より予測に近い挙動をします。" #. type: Plain text #: text/chapter10.md:680 @@ -3260,12 +3086,6 @@ msgstr "JSON" #. type: Plain text #: text/chapter10.md:723 -#, fuzzy -#| msgid "" -#| "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 passing structural data over the FFI." msgid "" "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 " @@ -3273,9 +3093,9 @@ msgid "" "passing structural data over the FFI." msgstr "" "アプリケーションでJSONを使うことには多くの理由があります。\n" -"例えばWebのAPIと疎通するよくある手段であるためです。\n" +"例えばwebのAPIと疎通するよくある手段であるためです。\n" "この節では他の用例についてもお話ししましょう。\n" -"構造的なデータをFFI越しに渡すことで型安全性を向上させる手法から始めます。" +"構造的なデータをFFI越しに渡す場合に型安全性を向上させる手法から始めます。" #. type: Plain text #: text/chapter10.md:725 @@ -3328,10 +3148,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:747 -#, fuzzy -#| msgid "" -#| "We can use the original type signatures, and the code will still compile, " -#| "despite the fact that the return types are incorrect." msgid "" "We can use the original type signatures, and the code will still compile, " "despite the incorrect return types." @@ -3461,9 +3277,7 @@ msgstr "" msgid "" "If we create an alternate foreign import that defines the return type as " "`Json`:" -msgstr "" -"返る型を`Json`として定義するようにして、代わりとなる外部インポートをつくると" -"こうなります。" +msgstr "返る型を`Json`として定義するようにして、代わりとなる外部インポートを作るとこうなります。" #. type: Fenced code block (hs) #: text/chapter10.md:789 @@ -3744,36 +3558,24 @@ msgstr "" #. type: Bullet: '1. ' #: text/chapter10.md:902 -#, fuzzy -#| msgid "" -#| "(Medium) Rewrite the earlier `quadraticRoots` function as " -#| "`quadraticRootsSet` which returns the `Complex` roots as a `Set` via JSON " -#| "(instead of as a `Pair`)." msgid "" "(Medium) Rewrite the earlier `quadraticRoots` function as " "`quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON " "(instead of as a `Pair`)." msgstr "" -"(普通)少し前の`quadraticRoots`を書き換えて`quadraticRootSet`としてくださ" -"い。\n" -"この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返しま" -"す。" +"(普通)少し前の`quadraticRoots`関数を書き換えて`quadraticRootSet`としてください。\n" +"この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返します。" #. type: Plain text #: text/chapter10.md:902 -#, fuzzy, 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" -#| "_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" +#, no-wrap msgid "" "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" @@ -3849,11 +3651,6 @@ msgstr "住所録" #. type: Plain text #: text/chapter10.md:925 -#, fuzzy -#| 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 features:" 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 " @@ -3893,9 +3690,7 @@ msgstr "" 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の梱包をつくるこ" -"とから始めていきます。" +msgstr "`Effect.Storage`モジュールに以下のwebストレージAPIのためのFFIの梱包を作ることから始めていきます。" #. type: Bullet: '- ' #: text/chapter10.md:934 @@ -4040,23 +3835,15 @@ msgstr "" #. type: Plain text #: text/chapter10.md:989 -#, fuzzy -#| 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 argonaut docs:" msgid "" "This is because `PhoneType` in the `Person` record needs an `EncodeJson` " "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のドキュメントで見られます。" +"これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンスを必要としているからです。\n" +"また、ついでに汎用のエンコードインスタンスとデコードインスタンスを導出していきます。\n" +"この仕組みについての詳細情報はargonautのドキュメントにあります。" #. type: Fenced code block (hs) #: text/chapter10.md:990 @@ -4093,7 +3880,6 @@ msgstr "item <- getItem \"person\"\n" #. type: Plain text #: text/chapter10.md:1005 -#, fuzzy msgid "" "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 " @@ -4102,10 +3888,10 @@ msgid "" "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:1006 @@ -4125,11 +3911,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1015 -#, fuzzy -#| 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 person retrieved from local storage." msgid "" "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 " @@ -4217,7 +3998,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1051 -#, fuzzy msgid "" "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 " @@ -4226,13 +4006,12 @@ msgid "" "triggered. See if you can trigger each of them." msgstr "" "最初のエラーのみがこのアプリの通常の操作内で起こります。\n" -"他のエラーはWebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。\n" -"どのようにJSON文字列を変更したかが、どのエラーの引き金になるかを決定します。\n" -"各エラーを引き起こせるかどうかやってみてください。" +"他のエラーはwebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。\n" +"どのようにJSON文字列を変更したかが、どのエラーを引き起こすかを決定します。\n" +"各エラーを引き起こせるかご確認ください。" #. type: Plain text #: text/chapter10.md:1053 -#, fuzzy msgid "" "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 " @@ -4242,10 +4021,10 @@ msgid "" msgstr "" "これでローカルストレージについては押さえました。\n" "次に`alert`動作を実装していきます。\n" -"この動作は`Effect.Console`モジュールの`log`動作によく似ています。\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:1054 @@ -4345,18 +4124,13 @@ msgstr "まとめ" #. type: Plain text #: text/chapter10.md:1086 -#, fuzzy -#| 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 using the FFI:" 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 " "using the FFI:" msgstr "" -"この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。ま" -"た、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。" +"この章では、PureScriptから外部のJavaScriptコードを扱う方法を学びました。\n" +"また、FFIを使用して信頼できるコードを書く時に生じる問題について見てきました。" #. type: Bullet: '- ' #: text/chapter10.md:1090 @@ -4367,10 +4141,6 @@ msgstr "外部関数が正しい表現を持っていることを確かめる重 #. type: Bullet: '- ' #: text/chapter10.md:1090 -#, fuzzy -#| 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." 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." @@ -4385,22 +4155,14 @@ msgstr "安全にJSONデータを直列化・直列化復元する方法を見 #. type: Plain text #: text/chapter10.md:1092 -#, fuzzy -#| msgid "" -#| "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 these " -#| "libraries put to use to solve real-world problems in a type-safe way." msgid "" "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:1093 @@ -4430,16 +4192,7 @@ msgstr "例として以下のような簡単なモジュールを見てみまし #. type: Fenced code block (haskell) #: text/chapter10.md:1101 -#, fuzzy, no-wrap -#| msgid "" -#| "module Test where\n" -#| "\n" -#| "gcd :: Int -> Int -> Int\n" -#| "gcd 0 m = m\n" -#| "gcd n 0 = n\n" -#| "gcd n m\n" -#| " | n > m = gcd (n - m) m\n" -#| " | otherwise = gcd (m - n) n\n" +#, no-wrap msgid "" "module Test where\n" "\n" @@ -4457,7 +4210,7 @@ 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:1113 @@ -4499,22 +4252,15 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1122 -#, fuzzy -#| 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`." msgid "" "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:1124 @@ -4537,21 +4283,15 @@ msgstr "名前の生成を理解する" #. type: Plain text #: text/chapter10.md:1128 -#, fuzzy -#| msgid "" -#| "PureScript aims to preserve names during code generation as much as " -#| "possible. In particular, most identifiers which are neither PureScript " -#| "nor JavaScript keywords can be expected to be preserved, at least for " -#| "names of top-level declarations." msgid "" "PureScript aims to preserve names during code generation as much as " "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:1130 @@ -4571,8 +4311,6 @@ msgstr "null = []\n" #. type: Plain text #: text/chapter10.md:1136 text/chapter10.md:1148 -#, fuzzy -#| msgid "generates the following JavaScript:" msgid "Generates the following JavaScript:" msgstr "これは以下のJavaScriptを生成します。" @@ -4606,13 +4344,6 @@ msgstr "var example$prime = 100;\n" #. type: Plain text #: text/chapter10.md:1154 -#, fuzzy -#| msgid "" -#| "Where compiled PureScript code is intended to be called from JavaScript, " -#| "it 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." msgid "" "Where compiled PureScript code is intended to be called from JavaScript, it " "is recommended that identifiers only use alphanumeric characters and avoid " @@ -4620,12 +4351,8 @@ msgid "" "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から使うための英数字の名前を持つ代替関数を提供しておくことをお勧め" -"します。" +"コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めします。\n" +"ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" #. type: Title ### #: text/chapter10.md:1155 @@ -4635,24 +4362,16 @@ msgstr "実行時のデータ表現" #. type: Plain text #: text/chapter10.md:1158 -#, fuzzy -#| 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 mean? In PureScript, it means that the type of an " -#| "expression should be compatible with its representation at runtime." 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 " "mean? In PureScript, it means that the type of an expression should be " "compatible with its representation at runtime." msgstr "" -"型はプログラムがある意味で「正しい」ことをコンパイル時に判断できるようにしま" -"す。\n" +"型はプログラムがある意味で「正しい」ことをコンパイル時に論証できるようにします。\n" "つまり、その点については壊れることがありません。\n" "しかし、これは何を意味するのでしょうか。\n" -"PureScriptでは式の型は実行時の表現と互換性がなければならないことを意味しま" -"す。" +"PureScriptでは、式の型は実行時の表現と互換性があることを意味します。" #. type: Plain text #: text/chapter10.md:1160 @@ -4697,14 +4416,6 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1166 -#, fuzzy -#| msgid "" -#| "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`." msgid "" "A similar law holds for expressions of type `Int`, `Number`, and `String` – " "expressions of type `Int` or `Number` evaluate to non-null JavaScript " @@ -4713,23 +4424,12 @@ msgid "" "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" -"`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式" -"は実行時に整数に評価されます。" +"`Int`や`Number`や`String`の型の式についても似た法則が成り立ちます。\n" +"`Int`や`Number`型の式はnullでないJavaScriptの数へと評価されますし、`String`型の式はnullでないJavaScriptの文字列へと評価されます。\n" +"`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式は実行時に整数に評価されます。" #. type: Plain text #: text/chapter10.md:1168 -#, fuzzy -#| 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`)." msgid "" "What about `Unit`? Well, since `Unit` has only one inhabitant (`unit`) and " "its value is not observable, it doesn't matter what it's represented with at " @@ -4739,13 +4439,10 @@ msgid "" "anything from a function also returns `undefined`)." msgstr "" "`Unit`についてはどうでしょうか。\n" -"`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何" -"で表現されるかは重要ではありません。\n" +"`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何で表現されるかは重要ではありません。\n" "古いコードは`{}`を使って表現する傾向がありました。\n" "しかし比較的新しいコードでは`undefined`を使う傾向にあります。\n" -"なので、`Unit`を表現するのに使うものは本当に何でも問題にならないのですが、" -"`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を" -"返します)。" +"なので、`Unit`を表現するのに使うものは何であれ差し支えありませんが、`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を返します)。" #. type: Plain text #: text/chapter10.md:1170 @@ -4754,26 +4451,17 @@ msgstr "もっと複雑な型についてはどうでしょうか。" #. type: Plain text #: text/chapter10.md:1172 -#, fuzzy, 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" +#, 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 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:1174 -#, fuzzy -#| msgid "" -#| "As you might expect, PureScript's arrays correspond to JavaScript 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 " -#| "type `a`." msgid "" "As you might expect, PureScript's arrays correspond to JavaScript arrays. " "But remember – PureScript arrays are homogeneous, so every element has the " @@ -4782,15 +4470,12 @@ msgid "" "whose elements have the correct runtime representation for type `a`." msgstr "" "ご想像の通り、PureScriptの配列はJavaScriptの配列に対応しています。\n" -"しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っているこ" -"とは覚えておいてください。\n" -"具体的には、もしPureScriptの式 `e`が何らかの型 `a`について型 `Array a`を持つ" -"なら、 `e`は全ての要素が(`null`でない)型 `a`の適切な実行時表現を持った" -"JavaScript配列へと評価されます。" +"しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っていることは覚えておいてください。\n" +"具体的には、もしPureScriptの式`e`が何らかの型`a`について型`Array a`を持つなら、`e`は(nullでない)JavaScript配列へと評価されます。\n" +"この配列の全ての要素は型`a`の適切な実行時表現を持ちます。" #. type: Plain text #: text/chapter10.md:1176 -#, fuzzy msgid "" "We've already seen that PureScript's records evaluate to JavaScript objects. " "As for functions and arrays, we can reason about the runtime representation " @@ -4799,8 +4484,8 @@ msgid "" "type." msgstr "" "PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てきました。\n" -"ちょうど関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールドのデータの実行時の表現についても推論できます。\n" -"勿論、レコードの各フィールドは、同じ型である必要はありません。" +"関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールド中のデータの実行時の表現について論証できます。\n" +"勿論、レコードのフィールドは、同じ型である必要はありません。" #. type: Title ### #: text/chapter10.md:1177 @@ -4810,7 +4495,6 @@ msgstr "ADTの表現" #. type: Plain text #: text/chapter10.md:1180 -#, fuzzy msgid "" "For every constructor of an algebraic data type, the PureScript compiler " "creates a new JavaScript object type by defining a function. Its " @@ -4818,7 +4502,7 @@ msgid "" "based on those prototypes." msgstr "" "代数的データ型の全ての構築子について、PureScriptコンパイラは関数を定義することで新たなJavaScriptオブジェクト型を作成します。\n" -"これらの構築子は雛形に基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。" +"これらの構築子はプロトタイプに基づいて新しいJavaScriptオブジェクトを作成する関数に対応しています。" #. type: Plain text #: text/chapter10.md:1182 @@ -4896,22 +4580,15 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1209 -#, fuzzy -#| 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:" 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 a curried function of two " "arguments. For example, this algebraic data type:" msgstr "" -"2引数以上の構築子についてはどうでしょうか。\n" -"その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成しま" -"す。\n" -"ここでは補助関数は2引数のカリー化された関数なのです。\n" +"1引数より多く取る構築子についてはどうでしょうか。\n" +"その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成します。\n" +"ただしこの場合、補助関数は2引数のカリー化された関数です。\n" "例えば次のような代数的データ型を考えます。" #. type: Fenced code block (haskell) @@ -4922,8 +4599,6 @@ msgstr "data Two a b = Two a b\n" #. type: Plain text #: text/chapter10.md:1215 -#, fuzzy -#| msgid "generates this JavaScript code:" msgid "Generates this JavaScript code:" msgstr "このコードからは、次のようなJavaScriptコードが生成されます。" @@ -4955,25 +4630,13 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1230 -#, fuzzy -#| msgid "" -#| "Here, values of the object type `Two` can be created using the `new` " -#| "keyword, or by using the `Two.create` function." msgid "" "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`関数を使" -"用すると作成できます。" +msgstr "ここで、オブジェクト型`Two`の値はキーワード`new`または`Two.create`関数を使用すると作成できます。" #. type: Plain text #: text/chapter10.md:1232 -#, fuzzy -#| 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." 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 " @@ -4981,18 +4644,15 @@ msgid "" "the same as its argument type." msgstr "" "newtypeの場合はまた少し異なります。\n" -"newtypeは単一の引数を取る単一の構築子を持つよう制限された代数的データ型である" -"ことを思い出してください。\n" -"この場合、実際のnewtypeの実行時表現は、その引数の型と同じになります。" +"newtypeは代数的データ型のようなもので、単一の引数を取る単一の構築子を持つよう制限されていたことを思い出してください。\n" +"この場合、newtypeの実行時表現は、その引数の型と同じになります。" #. type: Plain text #: text/chapter10.md:1234 -#, fuzzy -#| 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 "例えば、電話番号を表す次のようなnewtypeを考えます。" +msgstr "例えば、以下の電話番号を表すnewtypeは実行時にJavaScriptの文字列として表現されます。" #. type: Fenced code block (haskell) #: text/chapter10.md:1235 @@ -5002,18 +4662,10 @@ msgstr "newtype PhoneNumber = PhoneNumber String\n" #. type: Plain text #: text/chapter10.md:1240 -#, fuzzy -#| 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." msgid "" "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は更なる型安全性のための層を提供しますが、実行時の関数呼び出しのオー" -"バーヘッドがないので、ライブラリを設計するのに役に立ちます。" +msgstr "newtypeは、関数呼び出しによる実行時のオーバーヘッドなく更なる型安全性のための層を提供するため、ライブラリを設計するのに便利です。" #. type: Title ### #: text/chapter10.md:1241 @@ -5091,14 +4743,6 @@ msgstr "量化された型 `forall a. t`の実行時表現はどうなってい #. type: Plain text #: text/chapter10.md:1265 -#, fuzzy -#| msgid "" -#| "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 argument in its implementation. This additional condition prevents " -#| "problematic implementations such as the following JavaScript function " -#| "from inhabiting a polymorphic type:" msgid "" "But that is not enough – the runtime representation of a quantified type is " "more strict than this. We require any expression to be _parametrically " @@ -5108,12 +4752,10 @@ msgid "" "inhabiting a polymorphic type:" msgstr "" "しかし、それだけでは充分ではありません。\n" -"量化された型の実行時表現は、これよりも更に厳しくなります。\n" -"任意の式が*パラメトリック多相的*でなければなりません。\n" -"つまり、その実装において、引数の型についてのどんな情報も使うことができないの" -"です。\n" -"この追加の条件は、考えられる多相型のうち、以下のJavaScriptの関数のような問題" -"のある実装を防止します。" +"量化された型の実行時表現は、これよりも更に厳しいものです。\n" +"任意の式が*パラメトリック多相的*であることを要求しています。\n" +"つまり、その実装において、引数の型についてのどんな情報も使うことができないのです。\n" +"この追加の条件は、以下のJavaScriptの関数のような問題のある実装が多相型に現住することを防止します。" #. type: Fenced code block (javascript) #: text/chapter10.md:1266 @@ -5137,30 +4779,23 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1277 -#, fuzzy, 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" +#, 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" msgstr "" -"確かにこの関数は文字列から文字列、数から数へというような関数ではありますが、追加条件を満たしていません。\n" -"引数の実行時の型を調べており、したがって、この関数は型 `forall a. a -> a`の正しい実装だとはいえないのです。\n" +"確かにこの関数は文字列を取って文字列を返し、数を取って数を返す、といったものです。\n" +"しかしこの関数は追加条件を満たしていません。\n" +"引数の実行時の型を調べており、型`forall a. a -> a`の正しい現住にはならないからです。\n" #. type: Plain text #: text/chapter10.md:1279 -#, fuzzy, 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" +#, no-wrap 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 "関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけであり、したがって `id`はたしかに `forall a. a -> a`の唯一の実装なのです。\n" +msgstr "" +"関数の引数の実行時の型を検査できなければ、唯一の選択肢は引数をそのまま返すことだけです。\n" +"したがって`id`は確かに`forall a. a -> a`の唯一の現住なのです。\n" #. type: Plain text #: text/chapter10.md:1281 -#, fuzzy -#| msgid "" -#| "A full discussion of _parametric polymorphism_ and _parametricity_ is " -#| "beyond 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." msgid "" "A full discussion of _parametric polymorphism_ and _parametricity_ is beyond " "the scope of this book. Note, however, that since PureScript's types are " @@ -5182,14 +4817,6 @@ msgstr "制約のある型の表現" #. type: Plain text #: text/chapter10.md:1285 -#, fuzzy -#| 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 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." msgid "" "Functions with a type class constraint have an interesting representation at " "runtime. Because the function's behavior might depend on the type class " @@ -5205,16 +4832,10 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1287 -#, fuzzy -#| msgid "" -#| "For example, here is a simple PureScript function with a constrained type " -#| "which uses the `Show` type class:" msgid "" "For example, here is a simple PureScript function with a constrained type " "that uses the `Show` type class:" -msgstr "" -"例えば、 `Show`型クラスを使った制約のある型を持つ、次のような単純なPureScript" -"関数について考えます。" +msgstr "例えば以下は、`Show`型クラスを使う制約付きの型を持つ、単純なPureScript関数です。" #. type: Fenced code block (haskell) #: text/chapter10.md:1288 @@ -5320,13 +4941,6 @@ msgstr "副作用の表現" #. type: Plain text #: text/chapter10.md:1329 -#, fuzzy -#| msgid "" -#| "The `Effect` monad is also defined as a foreign type. Its runtime " -#| "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`." msgid "" "The `Effect` monad is also defined as a foreign type. Its runtime " "representation is quite simple – an expression of type `Effect a` should " @@ -5335,9 +4949,9 @@ msgid "" "type `a`." msgstr "" "`Effect`モナドも外部型として定義されています。\n" -"その実行時表現はとても簡単です。\n" -"型 `Effect a`の式は**引数なしの**JavaScript関数へと評価されます。\n" -"この関数はあらゆる副作用を実行し型 `a`の適切な実行時表現で値を返します。" +"その実行時表現はとても単純です。\n" +"型`Effect a`の式は**引数なしの**JavaScript関数へと評価されます。\n" +"この関数はあらゆる副作用を実行し、型`a`の適切な実行時表現を持つ値を返します。" #. type: Plain text #: text/chapter10.md:1331 @@ -5381,23 +4995,15 @@ msgstr "export const random = Math.random;\n" #. type: Plain text #: text/chapter10.md:1349 -#, fuzzy -#| 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 returns it, and the return value matches the runtime " -#| "representation of the `Number` type: it is a non-null JavaScript number." 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, " "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`型の実行" -"時表現と一致します。\n" -"`Number`型は`null`でないJavaScriptの数です。" +"`random`関数は実行時には引数なしの関数として表現されていることに注目してください。\n" +"この関数は乱数生成という副作用を実行して返しますが、返り値は`Number`型の実行時表現と一致します。\n" +"`Number`型はnullでないJavaScriptの数です。" #. type: Plain text #: text/chapter10.md:1351 @@ -5471,16 +5077,10 @@ msgstr "" #. type: Plain text #: text/chapter10.md:1376 -#, fuzzy -#| msgid "" -#| "When using `spago bundle-app --to` or `spago run`, this call to `main` is " -#| "generated automatically, whenever the `Main` module is defined." msgid "" "When using `spago bundle-app --to` or `spago run`, this call to `main` is " "generated automatically whenever the `Main` module is defined." -msgstr "" -"`spago bundle-app --to`または `spago run`を使用するときは、`Main`モジュールが" -"定義されている場合は常に、この `main`の呼び出しを自動的に生成できます。" +msgstr "`spago bundle-app --to`または`spago run`を使用する場合、`Main`モジュールが定義されている場合は常に、この`main`の呼び出しを自動的に生成できます。" #. type: Title # #: text/chapter11.md:1 @@ -6379,15 +5979,10 @@ msgstr "" #. type: Plain text #: text/chapter11.md:282 #, fuzzy -#| msgid "" -#| "The `Writer` type constructor takes two type arguments: a type `w` which " -#| "should be an instance of the `Monoid` type class, and the return type `a`." msgid "" "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つの型引数を取ります。" +msgstr "`Writer`型の構築子は、`Monoid`型クラスのインスタンスである型`w`、及び返り値の型`a`という2つの型引数を取ります。" #. type: Plain text #: text/chapter11.md:284 @@ -15571,9 +15166,7 @@ msgstr "" msgid "" "Functions can be defined at the top-level of a file by specifying arguments " "before the equals sign:" -msgstr "" -"ファイルのトップレベルでは、等号の直前に引数を指定することで関数を定義できま" -"す。" +msgstr "ファイルの最上位では、等号の直前に引数を指定することで関数を定義できます。" #. type: Fenced code block (haskell) #: text/chapter3.md:118 @@ -16091,10 +15684,8 @@ msgid "" msgstr "" "それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。\n" "まずは関数に型を与えることから始めます。\n" -"型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくように" -"すると良いでしょう。\n" -"実際、トップレベルの宣言に型註釈が含まれていないと、PureScriptコンパイラが警" -"告を出します。\n" +"型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくようにすると良いでしょう。\n" +"実際、最上位の宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。\n" "型宣言は関数の名前とその型を `::`記号で区切るようにして書きます。" #. type: Fenced code block (haskell) @@ -19854,7 +19445,7 @@ msgstr "" "数式\\\\( n! / k! (n - k)! \\\\)を使ってください。\n" "ここで \\\\( ! \\\\) は前に書いた階乗関数です。\n" "*手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。\n" -"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、コーナーケースを更に追加してみてください。" +"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、特殊な場合を更に追加してみてください。" #. type: Bullet: '1. ' #: text/chapter5.md:104 @@ -22348,11 +21939,9 @@ 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`を使ってより簡潔な解答をつくることができます。" -"もしそうするのでしたら、`Data.Newtype`から`class Newtype`をインポートしたり、" -"`Newtype`インスタンスを`Complex`に導出したりする必要も出てくるでしょう。" +"(普通)`Semiring`インタンスを`Complex`に定義してください。\n" +"*補足*:[`Data.Newtype`](https://pursuit.purescript.org/packages/purescript-newtype/docs/Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答を作れます。\n" +"もしそうするのでしたら、`Data.Newtype`から`class Newtype`をインポートしたり、`Newtype`インスタンスを`Complex`に導出したりする必要も出てくるでしょう。" #. type: Bullet: '4. ' #: text/chapter6.md:336 @@ -24617,7 +24206,7 @@ msgid "" "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 @@ -28184,9 +27773,7 @@ msgstr "" msgid "" "You can launch the web app from the `exercises/chapter8` directory with the " "following commands:" -msgstr "" -"`exercises/chapter8`ディレクトリから以下のコマンドでWebアプリを立ち上げること" -"ができます。" +msgstr "`exercises/chapter8`ディレクトリから以下のコマンドでwebアプリを立ち上げることができます。" #. type: Fenced code block (shell) #: text/chapter8.md:703 diff --git a/translation/terms.txt b/translation/terms.txt index 768c646e..818395f1 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -9,3 +9,6 @@ context: 文脈。一般には単に「コンテキスト」とされるよう synonym: 同義語。 canvas: 固有名詞、HTML 5で導入された機能としてのCanvasは英単語として、一般名詞としては「キャンバス」と片仮名にします。 pair: 組 +corner case: 特殊な場合 +top level: 最上位 +inhabitant: 現住 From fb082675869ad4e684b7dc05fbbca302a5f71e1c Mon Sep 17 00:00:00 2001 From: gemmaro Date: Sun, 20 Aug 2023 06:59:58 +0900 Subject: [PATCH 16/29] [ update ] chapter 11 translation --- translation/ja.po | 766 ++++++++++-------------------------------- translation/terms.txt | 24 +- 2 files changed, 198 insertions(+), 592 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index 464b3dce..74cdc441 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-19 19:52+0900\n" +"PO-Revision-Date: 2023-08-20 08:59+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -5090,14 +5090,6 @@ msgstr "モナドな冒険" #. type: Plain text #: text/chapter11.md:6 -#, fuzzy -#| 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 console in NodeJS. The various side-effects of the game (logging, " -#| "state, and configuration) will all be provided by a monad transformer " -#| "stack." 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 " @@ -5107,10 +5099,8 @@ msgid "" msgstr "" "この章の目標は*モナド変換子*について学ぶことです。\n" "モナド変換子は異なるモナドから提供された副作用を合成する方法を提供します。\n" -"NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームを題材とし" -"て扱います。\n" -"ゲームの様々な副作用(ロギング、状態、及び設定)が全てモナド変換子スタックに" -"よって提供されます。" +"動機付けとする例は、NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームです。\n" +"ゲームの様々な副作用(ロギング、状態、及び構成)が全てモナド変換子スタックによって提供されます。" #. type: Plain text #: text/chapter11.md:10 text/chapter12.md:10 @@ -5140,15 +5130,10 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter11.md:15 -#, fuzzy -#| msgid "" -#| "`optparse`, which provides applicative parsers for processing command " -#| "line arguments" msgid "" "`optparse`, which provides applicative parsers for processing command-line " "arguments" -msgstr "" -"`optparse` はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" +msgstr "`optparse`はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" #. type: Title ## #: text/chapter11.md:16 @@ -5163,10 +5148,8 @@ msgstr "プロジェクトを走らせるには`spago run`を使います。" #. type: Plain text #: text/chapter11.md:21 -#, fuzzy -#| msgid "By default you will see a usage message:" msgid "By default, you will see a usage message:" -msgstr "既定では使い方が表示されます。" +msgstr "既定では使い方の文言が表示されます。" #. type: Fenced code block (text) #: text/chapter11.md:22 @@ -5196,22 +5179,14 @@ msgstr "" #. type: Plain text #: text/chapter11.md:36 -#, fuzzy -#| 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" 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:38 @@ -5242,32 +5217,17 @@ msgstr "" #. type: Plain text #: text/chapter11.md:51 -#, fuzzy -#| 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." 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 print the game state when the `--debug` command line " "option is provided." msgstr "" -"プロンプトからは、 `look`、 `inventory`、 `take`、 `use`、 `north`、" -"`south`、 `east`、 `west`などのコマンドを入力できます。\n" -"`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合" -"に、ゲームの状態を出力するのに使えます。" +"プロンプトからは、`look`、`inventory`、`take`、`use`、`north`、`south`、`east`、`west`などのコマンドを入力できます。\n" +"`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合に、ゲームの状態を出力できます。" #. type: Plain text #: text/chapter11.md:53 -#, fuzzy -#| 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." 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 " @@ -5275,12 +5235,9 @@ msgid "" "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`コマンドを使うと、プレイヤーの位置にあるアイテムを拾い上げることができ" -"ます。" +"ゲームは2次元の碁盤の目の上が舞台で、コマンド`north`、`south`、`east`、`west`を発行することによってプレイヤーが移動します。\n" +"ゲームにはアイテムの集まりがあり、プレイヤーの所有物であったり、ゲームの盤上の特定の位置にあったりします。\n" +"`take`コマンドを使うと、プレイヤーはアイテムを拾い上げられます。" #. type: Plain text #: text/chapter11.md:55 @@ -5349,18 +5306,11 @@ msgstr "" #. type: Plain text #: text/chapter11.md:87 -#, fuzzy -#| 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." msgid "" "The game is very simple, but the aim of the chapter is to use the " "`transformers` package to build a library that will enable rapid development " "of this type of game." -msgstr "" -"このゲームはとても単純ですが、この章の目的は `transformers`パッケージを使用し" -"てこのようなゲームを素早く開発できるようにするライブラリを構築することです。" +msgstr "このゲームはとても単純ですが、この章の目的は`transformers`パッケージを使用してこのような種類のゲームを素早く開発できるようにするライブラリを構築することです。" #. type: Title ## #: text/chapter11.md:88 @@ -5379,11 +5329,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:93 -#, fuzzy -#| 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 " -#| "state provided by the `Effect` monad. `State` provides an alternative." 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 a mutable " @@ -5397,22 +5342,14 @@ msgstr "" #. type: Plain text #: text/chapter11.md:95 -#, fuzzy -#| 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` " -#| "monad\", the instance of the `Monad` type class is actually provided for " -#| "the `State s` type constructor, for any type `s`." 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` " "monad\", the instance of the `Monad` type class is actually provided for the " "`State s` type constructor for any type `s`." msgstr "" -"`State`型構築子は、状態の型 `s`、及び返り値の型 `a`という2種類の引数を取りま" -"す。\n" -"「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのイ" -"ンスタンスが任意の型`s`についての `State s`型構築子に対して提供されています。" +"`State`型構築子は、状態の型`s`、及び返り値の型`a`という2種類の引数を取ります。\n" +"「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのインスタンスが任意の型`s`についての`State s`型構築子に対して提供されています。" #. type: Plain text #: text/chapter11.md:97 @@ -5437,7 +5374,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:107 -#, fuzzy msgid "" "Note that these API signatures are presented in a simplified form using the " "`State` type constructor for now. The actual API involves `MonadState`, " @@ -5451,7 +5387,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:109 -#, fuzzy 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 " @@ -5459,8 +5394,8 @@ msgid "" "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:110 @@ -5503,7 +5438,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:128 -#, fuzzy msgid "" "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 " @@ -5553,21 +5487,11 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter11.md:145 -#, fuzzy -#| 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" msgid "" "(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" +msgstr "(普通)括弧からなる文字列が*平衡している*のは、0個以上のより短い平衡した文字列を連結したものか、より短い平衡した文字列を一対の括弧で囲んだものかの何れかです。" #. type: Plain text #: text/chapter11.md:147 @@ -5589,15 +5513,11 @@ msgstr "" #. type: Plain text #: text/chapter11.md:153 -#, fuzzy, 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" +#, no-wrap 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:157 @@ -5824,16 +5744,12 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter11.md:234 -#, fuzzy -#| msgid "" -#| "(Easy) Write a function `line` which renders a function at the current " -#| "indentation level. Your function should have the following type:" msgid "" "(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:238 @@ -5922,10 +5838,9 @@ msgstr " この関数は文書を文字列として出力します。\n" #. type: Plain text #: text/chapter11.md:263 -#, fuzzy, no-wrap -#| msgid " You should now be able to use your library to write simple documents, as follows:\n" +#, no-wrap msgid " You should now be able to use your library to write simple documents as follows:\n" -msgstr " これで、このライブラリを次のように使うと、簡単な文書を書くことができるでしょう。\n" +msgstr " これでライブラリを使って以下のような単純な文書を書けるようになりました。\n" #. type: Fenced code block (haskell) #: text/chapter11.md:264 @@ -5957,15 +5872,13 @@ msgstr "Writerモナド" #. type: Plain text #: text/chapter11.md:278 -#, fuzzy msgid "" "The `Writer` monad allows accumulating a secondary value in addition to the " "return value of a computation." -msgstr "`Writer`モナドは、計算の返り値に加えて、もう1つの値を累算していく機能を提供します。" +msgstr "`Writer`モナドでは、計算の返り値に加えてもう1つの値を累算できます。" #. type: Plain text #: text/chapter11.md:280 -#, fuzzy 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 accumulate a value " @@ -5973,16 +5886,17 @@ msgid "" "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`値の何れかが真であるかどうかを追跡するのに使うことができます。" +"よくある使い方としては型`String`もしくは`Array String`でログを累算していくというものなどがありますが、`Writer`モナドはこれよりもっと一般的なものです。\n" +"累算するのに任意のモノイドの値を使うことができるので、`Additive Int`モノイドを使って整数の合計を追跡するのに使ったり、`Disj Boolean`モノイドを使って途中の`Boolean`値の何れかが真であるかどうかを追跡するのに使えます。" #. type: Plain text #: text/chapter11.md:282 -#, fuzzy msgid "" "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つの型引数を取ります。" +msgstr "" +"`Writer`型構築子は2つの型引数を取ります。\n" +"`Monoid`型クラスのインスタンスである型`w`と返り値の型`a`です。" #. type: Plain text #: text/chapter11.md:284 @@ -6004,18 +5918,13 @@ msgstr "`tell`動作は与えられた値を現在の累算結果に付け加え #. type: Plain text #: text/chapter11.md:292 -#, fuzzy -#| msgid "" -#| "As an example, let's add a log to an existing function by using the " -#| "`Array String` monoid. Consider our previous implementation of the " -#| "_greatest common divisor_ function:" msgid "" "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:293 @@ -6144,19 +6053,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter11.md:346 -#, fuzzy -#| 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 Collatz sequence starting at `10` is as follows:" 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 " "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:350 @@ -6178,10 +6081,9 @@ msgstr " コラッツ関数の有限回の適用を繰り返すと、コラ #. type: Plain text #: text/chapter11.md:354 -#, fuzzy, 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" +#, no-wrap 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" +msgstr " 再帰を使い、数列が`1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する関数を書いてください。\n" #. type: Plain text #: text/chapter11.md:356 @@ -6197,14 +6099,13 @@ msgstr "モナド変換子" #. type: Plain text #: text/chapter11.md:360 -#, fuzzy msgid "" "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." msgstr "" "上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*の例となっています。\n" -"対応する各モナド変換子は`StateT`、`ReaderT`、`WriterT`と呼ばれています。" +"対応する各モナド変換子はそれぞれ`StateT`、`ReaderT`、`WriterT`という名前です。" #. type: Plain text #: text/chapter11.md:362 @@ -6235,30 +6136,23 @@ msgstr "" #. type: Plain text #: text/chapter11.md:364 -#, fuzzy msgid "" "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:366 -#, fuzzy -#| 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." msgid "" "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:368 @@ -6351,34 +6245,22 @@ msgstr "" #. type: Plain text #: text/chapter11.md:399 -#, fuzzy -#| msgid "" -#| "Finally we are left with something of kind `Type`, which means we can try " -#| "to find values of this type." msgid "" "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:401 -#, fuzzy -#| msgid "" -#| "The monad we have constructed - `StateT String (Either String)` - " -#| "represents computations which can fail with an error, and which can use " -#| "mutable state." msgid "" "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)`は、エラーで失敗する可能性があ" -"り、変更可能な状態を使える計算を表しています。" +msgstr "構築したモナド`StateT String (Either String)`は、エラーで失敗する可能性があり、変更可能な状態を使える計算を表しています。" #. type: Plain text #: text/chapter11.md:403 -#, fuzzy msgid "" "We can use the actions of the outer `StateT String` monad (`get`, `put`, and " "`modify`) directly, but to use the effects of the wrapped monad (`Either " @@ -6386,8 +6268,9 @@ msgid "" "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:404 @@ -6401,7 +6284,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:410 -#, fuzzy 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 " @@ -6412,22 +6294,17 @@ msgid "" "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:412 -#, fuzzy -#| msgid "" -#| "For example, the following computation reads the underlying state, and " -#| "then throws an error if the state is the empty string:" msgid "" "For example, the following computation reads the underlying state and then " "throws an error if the state is the empty string:" -msgstr "" -"例えば、次の計算は `StateT`モナド変換子で導入されている状態を読み込み、状態が" -"空の文字列である場合はエラーを投げます。" +msgstr "例えば、次の計算は通底する状態を読み、状態が空文字列であればエラーを投げます。" #. type: Fenced code block (haskell) #: text/chapter11.md:413 @@ -6457,18 +6334,11 @@ msgstr "" #. type: Plain text #: text/chapter11.md:427 -#, fuzzy -#| 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`)." 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`)." -msgstr "" -"状態が空でなければ、この計算は `put`を使って状態を `drop 1 s`(最初の文字を取" -"り除いた `s`)へと更新し、 `take 1 s`(`s`の最初の文字)を返します。" +msgstr "状態が空でなければ、この計算は`put`を使って状態を`drop 1 s`(つまり`s`から最初の文字を取り除いたもの)へと更新し、`take 1 s`(`s`の最初の文字)を返します。" #. type: Plain text #: text/chapter11.md:429 @@ -6493,13 +6363,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:439 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 " @@ -6507,11 +6370,9 @@ msgid "" "For example, we can apply `split` twice to read the first two characters " "from a string:" msgstr "" -"これは `StateT`を使わなくても実装できるので、さほど驚くようなことはありませ" -"ん。\n" -"しかし、モナドとして扱っているので、do記法やアプリカティブコンビネータを使っ" -"て、小さな計算から大きな計算を構築していくことができます。\n" -"例えば、2回 `split`を適用すると、文字列から最初の2文字を読むことができます。" +"これは`StateT`を使わなくても実装できるので、さほど驚くようなことはありません。\n" +"しかし、モナドの中で扱っているので、do記法やアプリカティブコンビネータを使って、小さな計算から大きな計算を構築できます。\n" +"例えば、2回`split`を適用すると、文字列から最初の2文字を読めます。" #. type: Fenced code block (text) #: text/chapter11.md:440 @@ -6525,7 +6386,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:446 -#, fuzzy 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` " @@ -6533,10 +6393,10 @@ msgid "" "built monads for various problems, choose the side-effects we need, and keep " "the expressiveness of do notation and applicative combinators." msgstr "" -"他にも動作を沢山用意すれば、`split`関数を使って、基本的な構文解析ライブラリを構築できます。\n" -"これは実際に`parsing`ライブラリで採用されている手法です。\n" +"`split`関数とその他沢山の動作を使えば基本的な構文解析ライブラリを構築できます。\n" +"実際、これは`parsing`ライブラリで採用されている手法です。\n" "これがモナド変換子の力なのです。\n" -"必要な副作用を選択して、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。" +"必要な副作用を選択し、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。" #. type: Title ## #: text/chapter11.md:447 @@ -6546,18 +6406,12 @@ msgstr "ExceptTモナド変換子" #. type: Plain text #: text/chapter11.md:450 -#, fuzzy -#| 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:" msgid "" "The `transformers` package also defines the `ExceptT e` monad transformer, " "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:451 @@ -6581,7 +6435,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:462 -#, fuzzy msgid "" "The `MonadError` class captures those monads that support throwing and " "catching errors of some type `e`, and an instance is provided for the " @@ -6589,9 +6442,9 @@ msgid "" "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:464 @@ -6691,11 +6544,10 @@ msgstr "" #. type: Plain text #: text/chapter11.md:492 -#, fuzzy msgid "" "Note that only those log messages that were written before the error was " "thrown get appended to the log." -msgstr "実際に追加されるログは、エラーが投げられる前に書かれたログ文言だけであることにも注目してください。" +msgstr "なお、エラーが投げられる前に書き出されるログ文言だけがログに追記されます。" #. type: Title ## #: text/chapter11.md:493 @@ -6705,15 +6557,6 @@ msgstr "モナド変換子スタック" #. type: Plain text #: text/chapter11.md:496 -#, fuzzy -#| 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." 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 " @@ -6722,26 +6565,14 @@ msgid "" "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" -"このように、構成するモナドによって提供された副作用を組み合わせる、モナド変換" -"子の*スタック*を構築できます。" +"これまで見てきたように、モナド変換子を使って既存のモナドを土台に新しいモナドを構築できます。\n" +"何かのモナド変換子`t1`とモナド`m`について、その適用`t1 m`もまたモナドになります。\n" +"つまり、*2つめの*モナド変換子`t2`を結果`t1 m`に適用すると、3つ目のモナド`t2 (t1 m)`を作れます。\n" +"このようにしてモナド変換子の*スタック*を構築できます。\n" +"これは構成されるモナドによって提供される副作用を組み合わせるものです。" #. type: Plain text #: text/chapter11.md:498 -#, fuzzy -#| 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." 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 " @@ -6751,34 +6582,21 @@ msgid "" "transforming the `Identity` monad with `StateT`, `ReaderT`, and `WriterT`, " "respectively." msgstr "" -"実際には、基本となるモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、" -"さもなくば `Data.Identity`モジュールで定義されている`Identity`モナドになりま" -"す。\n" -"`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換" -"はモナド変換子の作用だけを提供します。\n" -"実際に、`State`モナドと`Reader`モナドと`Writer`モナドは、`Identity`モナドをそ" -"れぞれ`StateT`と`ReaderT`と`WriterT`で変換することによって実装されています。" +"実際には、通底するモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さもなくば`Data.Identity`モジュールで定義されている`Identity`モナドになります。\n" +"`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換はモナド変換子の作用だけを提供します。\n" +"`State`、`Reader`、`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`、`ReaderT`、`WriterT`で変換することによって実装されています。" #. type: Plain text #: text/chapter11.md:500 -#, fuzzy -#| 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 bottom of the stack. This monad transformer stack will " -#| "provide the side effects of mutable state, accumulating a log, and pure " -#| "errors." 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 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:502 @@ -6836,23 +6654,15 @@ msgstr "" #. type: Plain text #: text/chapter11.md:524 -#, fuzzy -#| 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 " -#| "the `StateT` type constructor, then `runWriterT`, then `runExceptT`. " -#| "Finally, we run the computation in the `Identity` monad by using `unwrap`." 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 " "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:525 @@ -6895,7 +6705,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:543 -#, fuzzy msgid "" "This is because of how the side-effects provided by the `ExceptT` monad " "transformer interact with the side-effects provided by the `WriterT` monad " @@ -6905,19 +6714,12 @@ msgid "" "the first error, as we saw earlier when we transformed `Writer` with " "`ExceptT`." msgstr "" -"これは、 `ExceptT`モナド変換子が提供する副作用が、 `WriterT`モナド変換子が提供する副作用と干渉するためです。\n" -"これはモナド変換子スタックが構成されている順序を変更することで解決できます。\n" -"スタックの最上部に `ExceptT`変換子を移動すると、先ほど `Writer`を `ExceptT`に変換したときと同じように、最初のエラーまでに書かれた全ての文言が含まれるようになります。" +"これは、`ExceptT`モナド変換子が提供する副作用と`WriterT`モナド変換子が提供する副作用との関係によるものです。\n" +"これはモナド変換子スタックが構成されている順序を変更することで対処できます。\n" +"スタックの最上部に`ExceptT`変換子を移動すると、先ほど`Writer`を`ExceptT`に変換したときに見たように、最初のエラーまでに書かれた全ての文言がログに含まれるようになります。" #. type: Plain text #: text/chapter11.md:545 -#, fuzzy -#| 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 " -#| "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." 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 " @@ -6925,12 +6727,9 @@ msgid "" "`WriterT` and a second time over `StateT`. This is fine for small monad " "transformer stacks but quickly becomes inconvenient." msgstr "" -"このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、 " -"`lift`関数を複数回使わなければならないということです。\n" -"例えば`throwError`の呼び出しは、1回目は `WriteT`へ、2回目は `StateT`へと、2回" -"持ちあげなければなりません。\n" -"小さなモナド変換子スタックならなんとかなりますが、そのうち不便だと感じるよう" -"になるでしょう。" +"このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、`lift`関数を複数回使わなければならないということです。\n" +"例えば`throwError`の呼び出しは、1回目は`WriteT`へ、2回目は`StateT`へ、と2回持ちあげなければなりません。\n" +"小さなモナド変換子スタックならなんとかなりますが、そのうちすぐに不便になるでしょう。" #. type: Plain text #: text/chapter11.md:547 @@ -6971,7 +6770,7 @@ msgstr "" #. type: Plain text #: text/chapter11.md:558 -#, fuzzy, no-wrap +#, no-wrap msgid " which matches a string as a prefix of the current state or fails with an error message.\n" msgstr " これは現在の状態が接頭辞に照合するか、もしくはエラー文言とともに失敗します。\n" @@ -6997,17 +6796,15 @@ msgstr "" #. type: Plain text #: text/chapter11.md:568 -#, fuzzy, 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" +#, 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" 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:570 @@ -7082,16 +6879,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:592 -#, fuzzy -#| 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`." msgid "" "In particular, there are instances of `MonadState` for the `WriterT`, " "`ReaderT`, and `ExceptT` monad transformers provided in the `transformers` " @@ -7101,30 +6888,24 @@ msgid "" "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:594 -#, fuzzy 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 that " "support their operations." msgstr "" -"当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが成り立っています。\n" -"`transformers`では主な変換子について各々型クラスが定義されています。\n" +"当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが言えます。\n" +"`transformers`では主な各変換子について型クラスが定義されています。\n" "これによりそれらの操作に対応するモナドの上に抽象化できるのです。" #. type: Plain text #: text/chapter11.md:596 -#, fuzzy 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` " @@ -7132,8 +6913,8 @@ msgid "" "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" +"上の`split`関数の場合、構築したモナドスタックは各型クラス`MonadState`、`MonadWriter`、`MonadError`のインスタンスです。\n" +"つまり`lift`は全く呼び出す必要がないのです。\n" "まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、`tell`、`throwError`をそのまま使用できます。" #. type: Fenced code block (haskell) @@ -7144,22 +6925,14 @@ msgstr "{{#include ../exercises/chapter11/src/Split.purs:split}}\n" #. type: Plain text #: text/chapter11.md:602 -#, fuzzy -#| 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 handling. However, everything is still implemented using pure " -#| "functions and immutable data under the hood." msgid "" "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:603 @@ -7169,17 +6942,12 @@ msgstr "代替" #. type: Plain text #: text/chapter11.md:606 -#, fuzzy -#| msgid "" -#| "The `control` package defines a number of abstractions for working with " -#| "computations which can fail. One of these is the `Alternative` type class:" msgid "" "The `control` package defines a number of abstractions for working with " "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:607 @@ -7203,8 +6971,7 @@ msgstr "" #. type: Plain text #: text/chapter11.md:618 -#, fuzzy, 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" +#, 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" msgstr "" "`Alternative`は2つの新しいコンビネータを提供しています。\n" @@ -7236,19 +7003,13 @@ msgstr "`Data.List`にも等価な`many`と`some`があります。" #. type: Plain text #: text/chapter11.md:629 -#, fuzzy -#| msgid "" -#| "The `many` combinator uses the `Alternative` type class to repeatedly run " -#| "a computation _zero-or-more_ times. The `some` combinator is similar, but " -#| "requires at least the first computation to succeed." msgid "" "The `many` combinator uses the `Alternative` type class to repeatedly run a " "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:631 @@ -7334,22 +7095,15 @@ msgstr "実際、`Parser`モナドは `MonadPlus`のインスタンスです。" #. type: Plain text #: text/chapter11.md:657 -#, fuzzy -#| 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 which is an instance of `MonadPlus`:" 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, " "which is an instance of `MonadPlus`:" msgstr "" -"以前本書中で配列内包表記を扱ったとき、不要な結果を除いて絞り込むために使われ" -"る`guard`関数を導入しました。\n" -"実際には`guard`関数はもっと一般的で、 `MonadPlus`のインスタンスである全てのモ" -"ナドに対して使うことができます。" +"以前本書中で配列内包表記を押さえたとき、`guard`関数を導入しました。\n" +"これは欲しくない結果を取り除けるのに使えました。\n" +"実際には`guard`関数はもっと一般的で、`MonadPlus`のインスタンスである任意のモナドに対して使えます。" #. type: Fenced code block (haskell) #: text/chapter11.md:658 @@ -7373,22 +7127,15 @@ msgstr "{{#include ../exercises/chapter11/src/Split.purs:upper}}\n" #. type: Plain text #: text/chapter11.md:669 -#, fuzzy -#| 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 - " -#| "using `MonadPlus` in this way, we sometimes refer to constructing _monad " -#| "comprehensions_." 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 – " "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:670 @@ -7488,7 +7235,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:714 -#, fuzzy msgid "" "Again, this illustrates the power of reusability that monad transformers " "bring – we were able to write a backtracking parser in a declarative style " @@ -7499,50 +7245,32 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter11.md:721 -#, fuzzy -#| 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." 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 it should." msgstr "" -"(簡単)`string`構文解析器の実装から `lift`関数の呼び出しを取り除いてくださ" -"い。\n" -"新しい実装の型が整合していることを確認し、なぜそのようになるのかをよく納得し" -"ておきましょう。" +"(簡単)`string`構文解析器の実装から`lift`関数の呼び出しを取り除いてください。\n" +"新しい実装の型検査が通ることを確認し、そうなることを納得するまで確かめましょう。" #. type: Bullet: ' 1. ' #: text/chapter11.md:721 -#, fuzzy -#| 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\"`." msgid "" "(Medium) Use your `string` parser with the `some` combinator to write a " "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:721 -#, fuzzy -#| msgid "" -#| "(Medium) Use the `<|>` operator to write a parser `asOrBs` which " -#| "recognizes strings of the letters `a` or `b` in any order." msgid "" "(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:721 @@ -7575,13 +7303,6 @@ msgstr "RWSモナド" #. type: Plain text #: text/chapter11.md:731 -#, fuzzy -#| 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." msgid "" "One particular combination of monad transformers is so common that it is " "provided as a single monad transformer in the `transformers` package. The " @@ -7589,12 +7310,9 @@ msgid "" "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*モナドに組み合わ" -"さり、より単純に`RWS`モナドともされます。\n" -"このモナドは `RWST`モナド変換子と呼ばれる、対応するモナド変換子を持っていま" -"す。" +"モナド変換子のとある特定の組み合わせは頻出なので、`transformers`パッケージ内の単一のモナド変換子として提供されています。\n" +"`Reader`、`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わさり、より単純に`RWS`モナドともされます。\n" +"このモナドは`RWST`モナド変換子という名前の、対応するモナド変換子を持ちます。" #. type: Plain text #: text/chapter11.md:733 @@ -7621,33 +7339,23 @@ msgstr "type RWS r w s = RWST r w s Identity\n" #. type: Plain text #: text/chapter11.md:741 -#, fuzzy -#| 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." msgid "" "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:743 -#, fuzzy -#| 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." 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." msgstr "" -"第1型引数 `r`は大域的な設定の型を表します。\n" -"第2型引数 `w`はログを蓄積するために使用するモノイド、第3型引数 `s`は可変状態" -"の型を表しています。" +"最初の型引数`r`は大域的な構成の型を表します。\n" +"2つ目の`w`はログを蓄積するために使用するモノイドを表します。\n" +"3つ目の`s`は可変状態の型です。" #. type: Plain text #: text/chapter11.md:745 @@ -7666,20 +7374,13 @@ msgstr "{{#include ../exercises/chapter11/src/Data/GameEnvironment.purs:env}}\n" #. type: Plain text #: text/chapter11.md:751 -#, fuzzy -#| 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." msgid "" "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" -"これらのオプションは、モナド変換子を実行するときにコマンドラインから設定され" -"ます。" +"プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義されています。\n" +"モナド変換子を実行するとなると、これらのオプションがコマンドラインから設定されます。" #. type: Plain text #: text/chapter11.md:753 @@ -7719,14 +7420,6 @@ msgstr "{{#include ../exercises/chapter11/src/Data/GameItem.purs:GameItem}}\n" #. type: Plain text #: text/chapter11.md:767 -#, fuzzy -#| msgid "" -#| "The `GameState` type uses two new data structures: `Map` and `Set`, which " -#| "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 held by the player." msgid "" "The `GameState` type uses two new data structures: `Map` and `Set`, which " "represent sorted maps and sorted sets, respectively. The `items` property is " @@ -7737,26 +7430,18 @@ msgid "" msgstr "" "`GameState`型は2つの新しいデータ構造を使っています。\n" "`Map`と`Set`はそれぞれ整列されたマップと整列された集合を表します。\n" -"`items`属性は、そのゲーム平面上の座標からゲームアイテムの集合への対応付けに" -"なっています。\n" -"`player`属性はプレイヤーの現在の座標を格納しており、 `inventory`属性は現在プ" -"レイヤーが保有するゲームアイテムの集合です。" +"`items`属性は、ゲーム平面上の座標からその位置にあるゲームアイテムの集合への対応付けです。\n" +"`player`属性はプレイヤーの現在の座標を格納し、`inventory`属性は現在プレイヤーが保有するゲームアイテムの集合を格納します。" #. type: Plain text #: text/chapter11.md:769 -#, fuzzy -#| 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." msgid "" "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:771 @@ -7788,7 +7473,6 @@ msgstr "ゲームロジックの実装" #. type: Plain text #: text/chapter11.md:781 -#, fuzzy msgid "" "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 " @@ -7796,8 +7480,8 @@ msgid "" "`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" -"このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドはコンソールにテキストを出力するような観測可能な副作用へと結果を変換するために使っています。" +"`Reader`、`Writer`、`State`モナドの動作を再利用することで、`Game`モナドで定義されている単純な動作を組み合わせてゲームを構築していきます。\n" +"このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドは結果からコンソールにテキストを出力するような観測可能な副作用へと変換するために使っています。" #. type: Plain text #: text/chapter11.md:783 @@ -7818,15 +7502,14 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:has}}\n" #. type: Plain text #: text/chapter11.md:789 -#, fuzzy 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 " "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:791 @@ -7864,15 +7547,15 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_case}}\n" #. type: Plain text #: text/chapter11.md:803 -#, fuzzy 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 " "the `Just` constructor." msgstr "" -"`lookup`関数は `Maybe`型構築子で示された省略可能な結果を返します。\n" -"`lookup`関数は、キーがマップにない場合は `Nothing`を返し、それ以外の場合は `Just`構築子で対応する値を返します。" +"`lookup`関数は`Maybe`型構築子で示される省略可能な結果を返します。\n" +"`lookup`関数は、キーがマップにない場合は`Nothing`を返します。\n" +"それ以外の場合は`Just`構築子で対応する値を返します。" #. type: Plain text #: text/chapter11.md:805 @@ -7892,11 +7575,10 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}}\n" #. type: Plain text #: text/chapter11.md:811 -#, fuzzy msgid "" "In this case, we can use `put` to update the game state and `tell` to add a " "message to the log:" -msgstr "この場合、 `put`を使ってゲームの状態を更新し、 `tell`を使ってログに文言を追加できます。" +msgstr "この場合、`put`を使ってゲームの状態を更新し、`tell`を使ってログに文言を追加できます。" #. type: Fenced code block (haskell) #: text/chapter11.md:812 @@ -7906,30 +7588,16 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_body}}\n" #. type: Plain text #: text/chapter11.md:817 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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:819 -#, fuzzy -#| 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." 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." @@ -7938,26 +7606,17 @@ msgid "" "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`" -"フィールドを変更しています。\n" -"また、特定のキーの値を変更する`Data.Map`の `update`関数を使っています。\n" -"このとき、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`" -"関数を使って指定したアイテムを集合から取り除いています。\n" -"`insert`を使って新しいアイテムをプレイヤーの持ち物集合に加えるときにも、" -"`inventory`は更新されます。" +"`put`への引数では、レコード更新を使ってゲームの状態の`items`及び`inventory`フィールドを変更しています。\n" +"また、特定のキーの値を変更する`Data.Map`の`update`関数を使っています。\n" +"今回の場合、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`関数を使って指定したアイテムを集合から取り除いています。\n" +"`insert`を使って新しいアイテムをプレイヤーの持ち物の集合に加えるときにも、`inventory`は更新されます。" #. type: Plain text #: text/chapter11.md:821 -#, fuzzy -#| msgid "" -#| "Finally, the `pickUp` function handles the remaining cases, by notifying " -#| "the user using `tell`:" msgid "" "Finally, the `pickUp` function handles the remaining cases by notifying the " "user using `tell`:" -msgstr "" -"最後に、`pickUp`関数は `tell`を使ってユーザに次のように通知することにより、残" -"りの場合を処理します。" +msgstr "最後に、`pickUp`関数は`tell`を使ってユーザに通知することにより、残りの場合を処理します。" #. type: Fenced code block (haskell) #: text/chapter11.md:822 @@ -7984,34 +7643,33 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:debug}}\n" #. type: Plain text #: text/chapter11.md:833 -#, fuzzy 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 " "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:835 -#, fuzzy msgid "" "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:837 -#, fuzzy msgid "" "The remainder of the `Game` module defines a set of similar actions, each " "using only the actions defined by the `MonadState`, `MonadReader`, and " "`MonadWriter` type classes." -msgstr "`Game.purs`モジュールの残りの部分では、`MonadState`型クラスと`MonadReader`型クラスと`MonadWriter`型クラスでそれぞれ定義された動作だけを使い、同様の動作が定義されています。" +msgstr "" +"`Game`モジュールの残りの部分では同様の動作の集合が定義されています。\n" +"各動作は`MonadState`、`MonadReader`、`MonadWriter`型クラスにより定義された動作のみを使っています。" #. type: Title ## #: text/chapter11.md:838 @@ -8021,16 +7679,10 @@ msgstr "計算の実行" #. type: Plain text #: text/chapter11.md:841 -#, fuzzy -#| 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." msgid "" "Since our game logic runs in the `RWS` monad, it is necessary to run the " "computation to respond to the user's commands." -msgstr "" -"このゲームロジックは `RWS`モナドで動くため、ユーザのコマンドに応答するために" -"は計算する必要があります。" +msgstr "このゲームロジックは`RWS`モナドで動くため、ユーザのコマンドに応答するために計算する必要があります。" #. type: Plain text #: text/chapter11.md:843 @@ -8062,17 +7714,10 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:game_sig}}\n" #. type: Plain text #: text/chapter11.md:851 -#, fuzzy -#| 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`:" 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`:" -msgstr "" -"これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してか" -"ら、 `runRWS`を使って `RWS`の計算結果を実行します。" +msgstr "これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してから、`runRWS`を使って結果の`RWS`を計算します。" #. type: Fenced code block (haskell) #: text/chapter11.md:852 @@ -8088,15 +7733,14 @@ msgstr "" #. type: Plain text #: text/chapter11.md:859 -#, fuzzy msgid "" "`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 " "the final state." msgstr "" -"`runRWS`は `runReader`、 `runWriter`、 `runState`を組み合わせたように見えます。\n" -"これは、引数として大域的な設定及び初期状態を取り、ログ、結果、最的な終状態を含むデータ構造を返します。" +"`runRWS`は`runReader`、`runWriter`、`runState`を組み合わせたように見えます。\n" +"引数として大域的な構成及び初期状態を取り、ログ、結果、最終的な状態を含むデータ構造を返します。" #. type: Plain text #: text/chapter11.md:861 @@ -8126,14 +7770,13 @@ msgstr "" #. type: Plain text #: text/chapter11.md:869 -#, fuzzy msgid "" "The `node-readline` package provides the `LineHandler` type, which " "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) @@ -8158,19 +7801,13 @@ msgstr "" #. type: Plain text #: text/chapter11.md:881 -#, fuzzy -#| 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 created using the `createConsoleInterface` function:" 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 " "created using the `createConsoleInterface` function:" msgstr "" -"`Interface`型はコンソールの制御対象を表しており、コンソールとやり取りする関数" -"への引数として渡されます。\n" -"`createConsoleInterface`関数を使用すると `Interface`を作成できます。" +"`Interface`型はコンソールの制御子を表しており、コンソールとやり取りする関数への引数として渡されます。\n" +"`createConsoleInterface`関数を使用すると`Interface`を作成できます。" #. type: Fenced code block (haskell) #: text/chapter11.md:882 @@ -8262,16 +7899,10 @@ msgstr "" #. type: Plain text #: text/chapter11.md:909 -#, fuzzy -#| msgid "" -#| "The `runGame` function finally attaches the initial line handler to the " -#| "console interface, and displays the initial prompt:" msgid "" "The `runGame` function finally attaches the initial line handler to the " "console interface and displays the initial prompt:" -msgstr "" -"`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付け" -"て、最初のプロンプトを表示します。" +msgstr "`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付けて、初期プロンプトを表示します。" #. type: Fenced code block (haskell) #: text/chapter11.md:910 @@ -8303,11 +7934,12 @@ msgstr "" #. type: Plain text #: text/chapter11.md:920 -#, fuzzy, no-wrap +#, 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" msgstr "" -" エラー文言を扱うのに `ExceptT`モナド変換子を使うようにし、お知らせ文言を扱うのに`RWS`を使うようにするよう、コードをリファクタリングしてください。\n" -" *補足*:この演習にはテストはありません。\n" +" コードをリファクタリングしてください。\n" +" エラー文言を扱うのに`ExceptT`モナド変換子を使い、お知らせ文言を扱うのに`RWS`を使います。\n" +" *補足*:この演習にはテストがありません。\n" #. type: Title ## #: text/chapter11.md:921 @@ -8402,12 +8034,12 @@ msgstr "" #. type: Plain text #: text/chapter11.md:948 -#, fuzzy, no-wrap +#, 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 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:950 @@ -8423,62 +8055,44 @@ msgstr "{{#include ../exercises/chapter11/src/Main.purs:env}}\n" #. type: Plain text #: text/chapter11.md:956 -#, fuzzy, 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" +#, 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" 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:958 -#, fuzzy, 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" +#, no-wrap 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:962 -#, fuzzy -#| 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." msgid "" "(Medium) Add a new Boolean-valued property `cheatMode` to the " "`GameEnvironment` record. Add a new command line flag `-c` to the `optparse` " "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`設定に、チートモードを有効にする新しいコマンドラインフラグ " -"`-c`を追加してください。\n" -"チートモードが有効になっていない場合、 `cheat`コマンドは禁止されなければなり" -"ません。" +"(普通)`GameEnvironment`レコードに新しい真偽値のプロパティ`cheatMode`を追加してください。\n" +"また、`optparse`の構成に、チートモードを有効にする新しいコマンドラインフラグ`-c`を追加してください。\n" +"チートモードが有効になっていない場合、前の演習の`cheat`コマンドは禁止されます。" #. type: Plain text #: text/chapter11.md:966 -#, fuzzy -#| 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, and the `Effect` monad to build a front-end using the console." 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 " "and the `Effect` monad to build a front-end using the console." msgstr "" "この章ではこれまで学んできた技術を実践的に実演しました。\n" -"モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロント" -"エンドを構築するための `Effect`モナドがそれです。" +"モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロントエンドを構築するための`Effect`モナドがそれです。" #. type: Plain text #: text/chapter11.md:968 @@ -8495,7 +8109,6 @@ msgstr "" #. type: Plain text #: text/chapter11.md:970 -#, fuzzy msgid "" "We have seen how monad transformers allow us to write safe code in an " "imperative style, where the type system tracks effects. In addition, type " @@ -8504,27 +8117,20 @@ msgid "" "and `MonadPlus` to build useful monads by combining standard monad " "transformers." msgstr "" -"モナド変換子によって命令型のスタイルで安全なコードを書くことができることを見てきました。\n" +"モナド変換子によって命令型のスタイルで安全なコードを書けることが分かりました。\n" "このスタイルでは型システムによって作用が追跡されています。\n" -"また、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供します。\n" -"このモナドのお陰でコードの再利用が可能になりました。\n" +"加えて、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供し、これによりコードの再利用が可能になりました。\n" "標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のような標準的な抽象化を使用して、役に立つモナドを構築できました。" #. type: Plain text #: text/chapter11.md:971 -#, fuzzy -#| 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." msgid "" "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 @@ -13592,9 +13198,7 @@ msgid "" "Our new `render` method starts by delegating to a helper function, " "`renderElement`, and using `execWriter` to run our computation in the " "`Writer` monad:" -msgstr "" -"新しい`render`メソッドが開始すると、補助関数 `renderElement`に移譲し、" -"`execWriter`を使って`Writer`モナドで計算を走らせます。" +msgstr "新しい`render`メソッドが開始すると、補助関数 `renderElement`に移譲し、`execWriter`を使って`Writer`モナドで計算します。" #. type: Fenced code block (haskell) #: text/chapter14.md:484 @@ -21004,9 +20608,7 @@ msgstr "" msgid "" "This code declares a new _type class_ called `Show`, which is parameterized " "by the type variable `a`." -msgstr "" -"このコードでは、型変数 `a`でパラメータ化された、`Show`という新しい _型クラス" -"_ (type class) を宣言しています。" +msgstr "このコードでは、型変数`a`を引数に取る`Show`という新しい*型クラス*を宣言しています。" #. type: Plain text #: text/chapter6.md:41 @@ -24118,7 +23720,7 @@ msgid "" "lift `fullName` over `Maybe` to create an implementation of the web service " "which checks for missing parameters:" msgstr "" -"この関数が、クエリパラメータとして与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装を形成しているとしましょう。\n" +"この関数が、クエリ引数として与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装を形成しているとしましょう。\n" "使用者が3つの各引数を与えたことを確かめたいので、引数が存在するかどうかを表す`Maybe`型を使うことになるでしょう。\n" "`fullName`を`Maybe`の上へ持ち上げると、欠けている引数を検査するwebサービスの実装を作成できます。" diff --git a/translation/terms.txt b/translation/terms.txt index 818395f1..1ad5b633 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -1,14 +1,18 @@ -primitive type: 原始型 -type synonym: 型同義語 -optional: 省略可能な -accumulator: 累算器。一般には「累積」とされることもあるようです。 -pattern match: パターン照合 JavaScript runtime: 実行器 -hash code: ハッシュコード。「ハッシュ値」とされていました。 -context: 文脈。一般には単に「コンテキスト」とされるようです。 -synonym: 同義語。 +accumulator: 累算器。一般には「累積」とされることもあるようです。 canvas: 固有名詞、HTML 5で導入された機能としてのCanvasは英単語として、一般名詞としては「キャンバス」と片仮名にします。 -pair: 組 +context: 文脈。一般には単に「コンテキスト」とされるようです。 corner case: 特殊な場合 -top level: 最上位 +hash code: ハッシュコード。「ハッシュ値」とされていました。 inhabitant: 現住 +optional: 省略可能な +pair: 組 +pattern match: パターン照合 +primitive type: 原始型 +run the computation: 計算する。計算を走らせる、が直訳ですが単純にします。 +synonym: 同義語。 +top level: 最上位 +type synonym: 型同義語 +configure: 構成。設定はsettingで一応区別したいです。 +handle: 制御対象 +help message: ヘルプ文言。「使用方法の文言」と噛み砕くのもありそうですが、ややまどろっこしい感じがします。 From 0ffcffe262ed19e95f31687d3aa62189c8a10785 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Sun, 20 Aug 2023 17:59:01 +0900 Subject: [PATCH 17/29] [ update ] chapter 12 translation --- translation/ja.po | 360 ++++++++++------------------------------------ 1 file changed, 77 insertions(+), 283 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index 74cdc441..82946aa5 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-20 08:59+0900\n" +"PO-Revision-Date: 2023-08-22 08:54+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -8175,13 +8175,6 @@ msgstr "" #. type: Plain text #: text/chapter12.md:17 -#, fuzzy -#| 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." 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 " @@ -8189,10 +8182,9 @@ msgid "" "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" +"ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありません。" #. type: Title ## #: text/chapter12.md:18 @@ -8215,21 +8207,14 @@ msgstr "" #. type: Plain text #: text/chapter12.md:23 -#, fuzzy msgid "" "The `main` action starts, like in the other modules, by using the " "`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`動作を使ってキャンバスオブジェクトへの参照を取得します。\n" -"また、`getContext2D`動作を使ってキャンバスの2D描画文脈を参照します。" +msgstr "他のモジュールでも同様ですが、`main`動作は最初に`getCanvasElementById`動作を使ってキャンバスオブジェクトへの参照を取得し、`getContext2D`動作を使ってキャンバスの2D描画文脈にアクセスします。" #. type: Plain text #: text/chapter12.md:25 -#, fuzzy -#| 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." 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." @@ -8289,12 +8274,11 @@ msgstr "" #. type: Plain text #: text/chapter12.md:43 -#, fuzzy msgid "" "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`はキャンバスの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用するためのメソッドを提供します。" +msgstr "グラフィックス文脈`ctx`はキャンバスの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用したりするための手段を提供します。" #. type: Plain text #: text/chapter12.md:45 @@ -8338,16 +8322,15 @@ msgstr "fillPath :: forall a. Context2D -> Effect a -> Effect a\n" #. type: Plain text #: text/chapter12.md:59 -#, fuzzy msgid "" "`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 that provides the position and size of the " "rectangle:" msgstr "" -"`fillPath`はグラフィックスの文脈と描画するパスを構築する別の動作を引数に取ります。\n" +"`fillPath`はグラフィックスの文脈と描画するパスを構築する他の動作を引数に取ります。\n" "`rect`動作を使うとパスを構築できます。\n" -"`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを引数に取ります。" +"`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを取ります。" #. type: Fenced code block (haskell) #: text/chapter12.md:60 @@ -8385,26 +8368,17 @@ msgstr "行多相を利用する" #. type: Plain text #: text/chapter12.md:75 -#, fuzzy -#| 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." msgid "" "There are other ways to render paths. The `arc` function renders an arc " "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 -#, fuzzy -#| msgid "" -#| "The `Shapes.purs` file renders three shapes: a rectangle, an arc segment " -#| "and a triangle." msgid "" "The `Shapes.purs` file renders three shapes: a rectangle, an arc segment, " "and a triangle." @@ -8441,18 +8415,11 @@ msgstr "" # FIXME: w, hとなっていますが、上のコードではwidthとheightになっています。 #. type: Plain text #: text/chapter12.md:90 -#, fuzzy -#| 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." 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." -msgstr "" -"`x`と `y`プロパティは左上隅の位置を表しており、 `w`と `h`のプロパティはそれぞ" -"れ幅と高さを表しています。" +msgstr "`x`と`y`プロパティは左上隅の位置を表しており、`w`と`h`のプロパティはそれぞれ幅と高さを表しています。" #. type: Plain text #: text/chapter12.md:92 @@ -8486,21 +8453,13 @@ msgstr "" # FIXME: これも半径がrとradiusで違います。 #. type: Plain text #: text/chapter12.md:104 -#, fuzzy -#| 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." msgid "" "Here, the `x` and `y` properties represent the center point, `r` is the " "radius, `start` and `end` represent the endpoints of the arc in radians." -msgstr "" -"ここで、 `x`と `y`プロパティは弧の中心、 `r`は半径、 `start`と `end`は弧の両" -"端の角度を弧度法で表しています。" +msgstr "ここで、`x`と`y`プロパティは弧の中心、`r`は半径、`start`と`end`は弧の両端の角度を弧度法で表しています。" #. type: Plain text #: text/chapter12.md:106 -#, fuzzy 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 " @@ -8534,36 +8493,22 @@ msgstr "" #. type: Plain text #: text/chapter12.md:118 -#, fuzzy -#| 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." 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 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 -#, fuzzy -#| msgid "" -#| "For example, the `Shapes` module defines a `translate` function which " -#| "translates a shape by modifying its `x` and `y` properties:" msgid "" "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`関数を定義されています。" +msgstr "例えば`Shapes`モジュールでは`x`と`y`のプロパティを変更し図形を並行移動する`translate`関数が定義されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:121 @@ -8602,16 +8547,10 @@ msgstr "" #. type: Plain text #: text/chapter12.md:130 -#, fuzzy -#| msgid "" -#| "The `translate` function can be used with both the `Rectangle` and `Arc` " -#| "records, as can be seen in the `Shapes` example." msgid "" "The `translate` function can be used with both the `Rectangle` and `Arc` " "records, as seen in the `Shapes` example." -msgstr "" -"`Shapes`の例からわかるように、 `translate`関数は `Rectangle`レコードと`Arc`レ" -"コード双方に対して使うことができます。" +msgstr "`Shapes`の例からわかるように、`translate`関数は`Rectangle`レコードと`Arc`レコード双方に対して使えます。" #. type: Plain text #: text/chapter12.md:132 @@ -8682,7 +8621,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 -#, fuzzy msgid "" "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " "each example so far." @@ -8690,14 +8628,6 @@ msgstr "(簡単)これまでの各例について、`strokePath`関数や`se #. type: Bullet: ' 1. ' #: text/chapter12.md:158 -#, fuzzy -#| 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." msgid "" "(Easy) The `fillPath` and `strokePath` functions can render complex paths " "with a common style using a do notation block inside the function argument. " @@ -8705,11 +8635,9 @@ msgid "" "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 @@ -8774,12 +8702,12 @@ msgstr "" #. type: Plain text #: text/chapter12.md:179 -#, fuzzy, no-wrap +#, no-wrap 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 @@ -8795,24 +8723,22 @@ msgstr "無作為に円を描く" #. type: Plain text #: text/chapter12.md:185 -#, fuzzy msgid "" "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つはキャンバスの操作です。\n" +"`Example/Random.purs`ファイルには、`Effect`モナドを使って2種類の副作用を綴じ合わせる例が含まれています。\n" +"1つの副作用は乱数生成で、もう1つはキャンバスの操作です。\n" "この例では無作為に生成された円をキャンバスに100個描画します。" #. type: Plain text #: text/chapter12.md:187 -#, fuzzy msgid "" "The `main` action obtains a reference to the graphics context as before and " "then sets the stroke and fill styles:" -msgstr "`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗り潰しスタイルを設定します。" +msgstr "`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗り潰しのスタイルを設定します。" #. type: Fenced code block (haskell) #: text/chapter12.md:188 @@ -8835,14 +8761,13 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:for}}\n" #. type: Plain text #: text/chapter12.md:199 -#, fuzzy 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:" 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 @@ -8890,19 +8815,13 @@ msgstr "座標変換" #. type: Plain text #: text/chapter12.md:221 -#, fuzzy -#| msgid "" -#| "There is more to the canvas than just rendering simple shapes. Every " -#| "canvas maintains a transformation which is used to transform shapes " -#| "before rendering. Shapes can be translated, rotated, scaled, and skewed." msgid "" "There is more to the canvas than just rendering simple shapes. Every canvas " "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 @@ -8957,11 +8876,10 @@ msgstr "`translate`動作は`TranslateTransform`レコードのプロパティ #. type: Plain text #: text/chapter12.md:245 -#, fuzzy msgid "" "The `rotate` action rotates around the origin through some number of radians " "specified by the first argument." -msgstr "`rotate`動作は最初の引数で指定されたラジアンの値に応じて、原点を中心として回転します。" +msgstr "`rotate`動作は最初の引数で指定されたラジアンの数値に応じて、原点を中心として回転します。" #. type: Plain text #: text/chapter12.md:247 @@ -9033,16 +8951,10 @@ msgstr "文脈の保存" #. type: Plain text #: text/chapter12.md:268 -#, fuzzy -#| msgid "" -#| "A common use case is to render some subset of the scene using a " -#| "transformation, and then to reset the transformation afterwards." msgid "" "A common use case is to render some subset of the scene using a " "transformation and then reset the transformation." -msgstr "" -"変換を適用してシーンの一部を描画し、それからその変換を元に戻す、という使い方" -"はよくあります。" +msgstr "座標変換を使ってシーンの一部を描画し、それからその変換を元に戻す、という使い方はよくあります。" #. type: Plain text #: text/chapter12.md:270 @@ -9085,7 +8997,6 @@ msgstr "`save`動作は現在の文脈の状態(現在の変換行列や描画 #. type: Plain text #: text/chapter12.md:284 -#, fuzzy msgid "" "This allows us to save the current state, apply some styles and " "transformations, render some primitives, and finally restore the original " @@ -9094,7 +9005,7 @@ msgid "" "transformation afterwards:" msgstr "" "これらの動作により、現在の状態を保存し、いろいろなスタイルや変換を適用してから原始的な図形を描画し、最後に元の変換と状態を復元できます。\n" -"例えば、次の関数は回転を適用してから幾つかのキャンバス動作を実行し、そのあとに変換を復元します。" +"例えば次の関数は幾つかのキャンバス動作を実行しますが、その前に回転を適用し、その後に変換を復元します。" #. type: Fenced code block (haskell) #: text/chapter12.md:285 @@ -9173,16 +9084,10 @@ msgstr "" #. type: Plain text #: text/chapter12.md:316 -#, fuzzy -#| msgid "" -#| "The `Effect.Ref` module provides a type constructor for global mutable " -#| "references, and an associated effect:" msgid "" "The `Effect.Ref` module provides a type constructor for global mutable " "references and an associated effect:" -msgstr "" -"`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及び関連" -"する作用を提供します。" +msgstr "`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及びそれに紐付く作用を提供します。" #. type: Fenced code block (text) #: text/chapter12.md:317 @@ -9211,20 +9116,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:327 -#, fuzzy -#| msgid "" -#| "The `Example/Refs.purs` file contains an example which uses a `Ref` to " -#| "track mouse clicks on the `canvas` element." msgid "" "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`作用を使用する例が含まれています。" +msgstr "`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに `Ref`を使う例が含まれます。" #. type: Plain text #: text/chapter12.md:329 -#, fuzzy msgid "" "The code starts by creating a new reference containing the value `0` by " "using the `new` action:" @@ -9264,19 +9162,14 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}}\n" #. type: Plain text #: text/chapter12.md:347 -#, fuzzy msgid "" "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`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。" +msgstr "この動作では元の変換を保存するために`withContext`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。" #. type: Bullet: '- ' #: text/chapter12.md:352 -#, fuzzy -#| msgid "" -#| "The rectangle is translated through `(-100, -100)` so that its center " -#| "lies at the origin." msgid "" "The rectangle is translated through `(-100, -100)`, so its center lies at " "the origin." @@ -9296,7 +9189,6 @@ msgstr "矩形が原点を中心に`10`の倍数分の角度で回転します #. type: Bullet: '- ' #: text/chapter12.md:352 -#, fuzzy msgid "" "The rectangle is translated through `(300, 300)`, so its center lies at the " "center of the canvas." @@ -9325,47 +9217,30 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 -#, fuzzy -#| msgid "" -#| "(Easy) Write a higher-order function which strokes and fills a path " -#| "simultaneously. Rewrite the `Random.purs` example using your function." msgid "" "(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 -#, fuzzy -#| 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 is clicked." msgid "" "(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`作用を使用して、マウスがクリックされたときに、" -"キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してく" -"ださい。" +msgstr "(普通)`Random`作用と`Dom`作用を使用して、マウスがクリックされたときに、キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してください。" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 -#, fuzzy -#| msgid "" -#| "(Medium) Write a function which transforms the scene by rotating it " -#| "around a point with specified coordinates. _Hint_: use a translation to " -#| "first translate the scene to the origin." msgid "" "(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 @@ -9384,7 +9259,6 @@ msgstr "" #. type: Plain text #: text/chapter12.md:372 -#, fuzzy 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 " @@ -9392,9 +9266,9 @@ msgid "" "process is iterated some number of times, starting with the initial sequence " "of letters." msgstr "" -"L-Systemは*アルファベット*、つまり初期状態となるアルファベットの文字列と、*生成規則*の集合で定義されています。\n" -"各生成規則は、アルファベットの文字を取り、それを置き換える文字の配列を返します。\n" -"この処理は文字の初期配列から始まり、複数回繰り返されます。" +"1つのL-Systemは*アルファベット*、つまりアルファベット由来の文字の初期の並びと、*生成規則*の集合で定義されます。\n" +"各生成規則は、アルファベットの文字を取り、それを置き換える文字の並びを返します。\n" +"この処理は文字の初期の並びから始まり、複数回繰り返されます。" #. type: Plain text #: text/chapter12.md:374 @@ -9406,19 +9280,13 @@ msgstr "もしアルファベットの各文字がキャンバス上で実行さ #. type: Plain text #: text/chapter12.md:376 -#, fuzzy -#| 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 production rules:" 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 " "production rules:" msgstr "" -"例えばアルファベットが文字 `L`(左回転)、 `R`(右回転)、 `F`(前進)で構成" -"されているとします。\n" -"また、次のような生成規則を定義します。" +"例えばアルファベットが文字`L`(左回転)、`R`(右回転)、`F`(前進)で構成されているとします。\n" +"次のような生成規則を定義できます。" #. type: Fenced code block (text) #: text/chapter12.md:377 @@ -9454,18 +9322,13 @@ msgstr "" #. type: Plain text #: text/chapter12.md:392 -#, fuzzy -#| 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." msgid "" "and so on. Plotting a piecewise-linear path corresponding to this set of " "instructions approximates the _Koch curve_. Increasing the number of " "iterations increases the resolution of the curve." msgstr "" -"この命令群に対応する線分パスをプロットすると、*コッホ曲線*と呼ばれる曲線に近" -"似されます。\n" +"というように続きます。\n" +"この命令群に対応する線分パスをプロットすると、*コッホ曲線*に近似されます。\n" "反復回数を増やすと、曲線の解像度が増していきます。" #. type: Plain text @@ -9536,16 +9399,15 @@ msgstr "これはまさに上記の仕様をそのまま書き写したもので #. type: Plain text #: text/chapter12.md:420 -#, fuzzy msgid "" "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 that can render a letter of the alphabet to the canvas." msgstr "" -"これで、この形式の仕様を受け取ってキャンバスに描画する関数 `lsystem`を実装できます。\n" +"これで、この形式の仕様を受け取ってキャンバスに描画する関数`lsystem`を実装できます。\n" "`lsystem`はどのような型を持っているべきでしょうか。\n" -"この関数は初期状態 `initial`や生成規則 `productions`のような値だけでなく、アルファベットの文字をキャンバスに描画する関数を引数に取る必要があります。" +"`initial`や`productions`のような値だけでなく、アルファベットの文字をキャンバスに描画できる関数を引数に取る必要があります。" #. type: Plain text #: text/chapter12.md:422 @@ -9577,7 +9439,6 @@ msgstr "最初の2つの引数の型は、値 `initial`と `productions`に対 #. type: Plain text #: text/chapter12.md:434 -#, fuzzy msgid "" "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 " @@ -9586,7 +9447,7 @@ msgid "" "letter `F`." msgstr "" "3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行することによって*解釈*する関数を表します。\n" -"この例では、文字`L`は左回転、文字 `R`で右回転、文字 `F`は前進を意味します。" +"この例では、文字`L`は左回転、文字`R`で右回転、文字`F`は前進を意味します。" #. type: Plain text #: text/chapter12.md:436 @@ -9627,14 +9488,6 @@ msgstr "" #. type: Plain text #: text/chapter12.md:448 -#, fuzzy -#| 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`." msgid "" "The second observation is that, to implement instructions like \"turn left\" " "and \"turn right\", we will need to maintain some state, namely the " @@ -9643,13 +9496,10 @@ msgid "" "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" +"具体的に言えば、その時点でパスが動いている方向を状態として持たなければなりません。\n" +"計算を通じて状態を渡すように関数を変更する必要があります。\n" +"ここでも`lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数`s`を使用してそれを表しています。" #. type: Plain text #: text/chapter12.md:450 @@ -9778,26 +9628,21 @@ msgstr "" #. type: Plain text #: text/chapter12.md:494 -#, fuzzy -#| 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." msgid "" "The `go` function works by recursion on its second argument. There are two " "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 -#, fuzzy, 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" +#, no-wrap 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) @@ -9825,17 +9670,12 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_ #. type: Plain text #: text/chapter12.md:508 -#, fuzzy -#| msgid "" -#| "That's it! Note how the use of higher order functions like `foldM` and " -#| "`concatMap` allowed us to communicate our ideas concisely." msgid "" "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 @@ -9868,13 +9708,6 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_anno} #. type: Plain text #: text/chapter12.md:518 -#, fuzzy -#| 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." 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 " @@ -9882,24 +9715,12 @@ msgid "" "or multiple return values. The reader is encouraged to try writing L-systems " "that use these various types of side-effect." msgstr "" -"この型で書かれていることは、この解釈関数はモナド `m`が持つ任意の副作用を完全" -"に自由に持つことができる、ということだと理解できます。\n" -"キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれません" -"し、失敗や複数の戻り値に対応しているかもしれません。\n" -"こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めし" -"ます。" +"この型で書かれていることは、この解釈関数はモナド`m`が持つ任意の副作用を完全に自由に持つことができる、ということだと理解できます。\n" +"キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれませんし、失敗や複数の戻り値に対応しているかもしれません。\n" +"こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めします。" #. type: Plain text #: text/chapter12.md:520 -#, fuzzy -#| 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." msgid "" "This function is a good example of the power of separating data from " "implementation. The advantage of this approach is that we can interpret our " @@ -9909,11 +9730,9 @@ msgid "" "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 @@ -9952,17 +9771,10 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} #. type: Plain text #: text/chapter12.md:534 -#, fuzzy -#| 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:" 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:" -msgstr "" -"文字 `F`(前進)を解釈するには、パスの新しい位置を計算し、線分を描画し、状態" -"を次のように更新します。" +msgstr "文字`F`(前進)を解釈するには、次のようにパスの新しい位置を計算し、線分を描画し、状態を更新します。" #. type: Fenced code block (haskell) #: text/chapter12.md:535 @@ -10027,10 +9839,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 -#, fuzzy -#| msgid "" -#| "(Easy) Try changing the various numerical constants in the code, to " -#| "understand their effect on the rendered system." msgid "" "(Easy) Try changing the various numerical constants in the code to " "understand their effect on the rendered system." @@ -10051,13 +9859,12 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter12.md:562 -#, fuzzy msgid "" "(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. ' @@ -10093,16 +9900,14 @@ msgstr "" #. type: Plain text #: text/chapter12.md:571 -#, fuzzy, 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" +#, 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" 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 @@ -10136,8 +9941,7 @@ msgstr "" #. type: Plain text #: text/chapter12.md:584 -#, fuzzy, 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" +#, 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" msgstr "" " このL-Systemを描画してください。\n" @@ -10173,24 +9977,15 @@ msgstr "" #. type: Plain text #: text/chapter12.md:597 -#, fuzzy -#| 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 polymorphism, and the `Effect` monad for handling " -#| "side-effects." 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 " "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 APIを使う方法について学びました。\n" -"また、これまで学んできた手法の多くを利用した実用的な例について見ました。\n" -"マップや畳み込み、レコードと行多相、副作用を扱うための `Effect`モナドなどで" -"す。" +"この章では、`canvas`ライブラリを使用することにより、PureScriptからHTML5 Canvas APIを使う方法について学びました。\n" +"また、これまで学んできた多くの手法からなる実用的な実演を見ました。\n" +"マップや畳み込み、レコードと行多相、副作用を扱うための`Effect`モナドです。" #. type: Plain text #: text/chapter12.md:599 @@ -10226,12 +10021,11 @@ msgstr "" #. type: Plain text #: text/chapter12.md:611 -#, fuzzy msgid "" "This approach is taken in the `drawing` package, and it brings the " "flexibility of manipulating the scene as data in various ways before " "rendering." -msgstr "この手法は `drawing`パッケージでも採用されており、描画前に様々な方法でデータとしてシーンを操作できる柔軟性を齎しています。" +msgstr "この手法は`drawing`パッケージで取られており、描画前に様々な方法でシーンをデータとして操作できる柔軟性を齎しています。" #. type: Plain text #: text/chapter12.md:612 From 805721d75b434f375e588e0d38366d1f13a8e322 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Wed, 23 Aug 2023 07:58:56 +0900 Subject: [PATCH 18/29] [ update ] chapter 13 translation * [ generate ] translations --- text-ja/chapter11.md | 1164 ++++++++++++++++++++++++++++++++++++++++++ text-ja/chapter12.md | 715 ++++++++++++++++++++++++++ text-ja/chapter13.md | 476 +++++++++++++++++ text-ja/chapter6.md | 2 +- text-ja/chapter7.md | 2 +- translation/ja.po | 321 +++--------- 6 files changed, 2415 insertions(+), 265 deletions(-) create mode 100644 text-ja/chapter11.md create mode 100644 text-ja/chapter12.md create mode 100644 text-ja/chapter13.md diff --git a/text-ja/chapter11.md b/text-ja/chapter11.md new file mode 100644 index 00000000..1c1b1ecf --- /dev/null +++ b/text-ja/chapter11.md @@ -0,0 +1,1164 @@ +# モナドな冒険 + +## この章の目標 + +この章の目標は*モナド変換子*について学ぶことです。 +モナド変換子は異なるモナドから提供された副作用を合成する方法を提供します。 +動機付けとする例は、NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームです。 +ゲームの様々な副作用(ロギング、状態、及び構成)が全てモナド変換子スタックによって提供されます。 + +## プロジェクトの準備 + +このモジュールのプロジェクトでは以下の新しい依存関係が導入されます。 + +- `ordered-collections` は不変のマップと集合のためのデータ型を提供します +- `transformers` は標準的なモナド変換子の実装を提供します +- `node-readline`はNodeJSが提供する[`readline`](http://nodejs.org/api/readline.html)インターフェイスへのFFIバインディングを提供します +- `optparse`はコマンドライン引数を処理するアプリカティブ構文解析器を提供します + +## ゲームの遊びかた + +プロジェクトを走らせるには`spago run`を使います。 + +既定では使い方の文言が表示されます。 + +```text +Monadic Adventures! A game to learn monad transformers + +Usage: run.js (-p|--player ) [-d|--debug] + Play the game as + +Available options: + -p,--player + The player's name + -d,--debug Use debug mode + -h,--help Show this help text +``` + +コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-a`オプション付きで`spago run`を呼び出すか、`spago +bundle-app`とすればよいです。 +2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。 + +例えば`-p`オプションを使ってプレイヤー名を与えるには次のようにします。 + +```text +$ spago run -a "-p Phil" +> +``` + +```text +$ spago bundle-app +$ node index.js -p Phil +> +``` + +プロンプトからは、`look`、`inventory`、`take`、`use`、`north`、`south`、`east`、`west`などのコマンドを入力できます。 +`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合に、ゲームの状態を出力できます。 + +ゲームは2次元の碁盤の目の上が舞台で、コマンド`north`、`south`、`east`、`west`を発行することによってプレイヤーが移動します。 +ゲームにはアイテムの集まりがあり、プレイヤーの所有物であったり、ゲームの盤上の特定の位置にあったりします。 +`take`コマンドを使うと、プレイヤーはアイテムを拾い上げられます。 + +参考までに、このゲームのひと通りの流れは次のようになります。 + +```text +$ spago run -a "-p Phil" + +> look +You are at (0, 0) +You are in a dark forest. You see a path to the north. +You can see the Matches. + +> take Matches +You now have the Matches + +> north +> look +You are at (0, 1) +You are in a clearing. +You can see the Candle. + +> take Candle +You now have the Candle + +> inventory +You have the Candle. +You have the Matches. + +> use Matches +You light the candle. +Congratulations, Phil! +You win! +``` + +このゲームはとても単純ですが、この章の目的は`transformers`パッケージを使用してこのような種類のゲームを素早く開発できるようにするライブラリを構築することです。 + +## Stateモナド + +`transformers`パッケージで提供されている幾つかのモナドを眺めることから始めましょう。 + +最初の例は`State`モナドです。 +これは純粋なコードで*変更可能状態*をモデル化する手段を提供します。 +既に`Effect`モナドによって提供される変更可能状態の手法について見てきました。 +`State`はその代替を提供します。 + +`State`型構築子は、状態の型`s`、及び返り値の型`a`という2種類の引数を取ります。 +「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのインスタンスが任意の型`s`についての`State +s`型構築子に対して提供されています。 + +`Control.Monad.State`モジュールは以下のAPIを提供しています。 + +```haskell +get :: forall s. State s s +gets :: forall s. (s -> a) -> State s a +put :: forall s. s -> State s Unit +modify :: forall s. (s -> s) -> State s s +modify_ :: forall s. (s -> s) -> State s Unit +``` + +なお、ここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式で表されています。 +実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきます。 +ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないでください。 + +例を見てみましょう。 +`State`モナドの使い方の1つとしては、整数の配列中の値を現在の状態に加えるものが考えられます。 +状態の型`s`として`Int`を選択し、配列の走査に`traverse_`を使い、配列の各要素について`modify`を呼び出すと、これを実現できます。 + +```haskell +import Data.Foldable (traverse_) +import Control.Monad.State +import Control.Monad.State.Class + +sumArray :: Array Int -> State Int Unit +sumArray = traverse_ \n -> modify \sum -> sum + n +``` + +`Control.Monad.State`モジュールは、`State`モナドで計算するための次の3つの関数を提供します。 + +```haskell +evalState :: forall s a. State s a -> s -> a +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 +s`型の値として表現された両方を返します。 + +先ほどの `sumArray`関数が与えられているとき、PSCiで `execState`を使うと次のように複数の配列内の数字を合計できます。 + +```text +> :paste +… execState (do +… sumArray [1, 2, 3] +… sumArray [4, 5] +… sumArray [6]) 0 +… ^D +21 +``` + +## 演習 + + 1. (簡単)上の例で、`execState`を`runState`や`evalState`で置き換えると結果はどうなるでしょうか。 + 1. (普通)括弧からなる文字列が*平衡している*のは、0個以上のより短い平衡した文字列を連結したものか、より短い平衡した文字列を一対の括弧で囲んだものかの何れかです。 + + `State`モナドと `traverse_`関数を使用して、次のような関数を書いてください。 + + ```haskell + testParens :: String -> Boolean + ``` + + これは、まだ閉じられていない開括弧の数を把握することで、括弧の`String`が平衡しているかどうかを調べる関数です。 + この関数は次のように動作します。 + + ```text + > testParens "" + true + + > testParens "(()(())())" + true + + > testParens ")" + false + + > testParens "(()()" + false + ``` + + *手掛かり*:入力の文字列を文字の配列に変換するのに、`Data.String.CodeUnits`モジュールの `toCharArray`関数を使うと良いでしょう。 + +## Readerモナド + +`transformers`パッケージでは `Reader`というモナドも提供されています。 +このモナドは大域的な設定を読み取る機能を提供します。 +`State`モナドが1つの可変状態を読み書きする機能を提供するのに対し、 `Reader`モナドは1つのデータの読み取り機能だけを提供します。 + +`Reader`型構築子は、設定の型を表す型 `r`、及び戻り値の型 `a`の2つの型引数を取ります。 + +`Control.Monad.Reader`モジュールは以下のAPIを提供します。 + +```haskell +ask :: forall r. Reader r r +local :: forall r a. (r -> r) -> Reader r a -> Reader r a +``` + +`ask`動作は現在の設定を読み取るために使い、`local`動作は変更された設定で計算するために使います。 + +例えば、権限で制御するアプリケーションを開発しており、現在の利用者の権限オブジェクトを保持するのに `Reader`モナドを使いたいとしましょう。 +型 `r`を次のようなAPIを備えた型 `Permission`として選択できます。 + +```haskell +hasPermission :: String -> Permissions -> Boolean +addPermission :: String -> Permissions -> Permissions +``` + +利用者が特定の権限を持っているかどうかを確認したいときは、 `ask`を使って現在の権限オブジェクトを取得すればいつでも調べることができます。 +例えば管理者だけが新しい利用者の作成を許可されているとしましょう。 + +```haskell +createUser :: Reader Permissions (Maybe User) +createUser = do + permissions <- ask + if hasPermission "admin" permissions + then map Just newUser + else pure Nothing +``` + +`local`動作を使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユーザーの権限を昇格させることもできます。 + +```haskell +runAsAdmin :: forall a. Reader Permissions a -> Reader Permissions a +runAsAdmin = local (addPermission "admin") +``` + +こうすると、利用者が `admin`権限を持っていなかった場合であっても新しい利用者を作成できるような関数を書くことができます。 + +```haskell +createUserAsAdmin :: Reader Permissions (Maybe User) +createUserAsAdmin = runAsAdmin createUser +``` + +`Reader`モナドを計算するには、大域的な設定を与える`runReader`関数を使います。 + +```haskell +runReader :: forall r a. Reader r a -> r -> a +``` + +## 演習 + +以下の演習では、 `Reader`モナドを使って、字下げのついた文書を出力するための小さなライブラリを作っていきます。 +「大域的な設定」は、現在の字下げの深さを示す数になります。 + +```haskell +type Level = Int + +type Doc = Reader Level String +``` + + 1. (簡単)現在の字下げの深さで関数を書き出す関数`line`を書いてください。 + 関数は以下の型を持ちます。 + + ```haskell + line :: String -> Doc + ``` + + *手掛かり*:現在の字下げの深さを読み取るためには `ask`関数を使用します。 + `Data.Monoid`の`power`関数も役に立つかもしれません。 +1. (普通)`local`関数を使用して次の関数を書いてください。 + + ```haskell + indent :: Doc -> Doc + ``` + + この関数はコードブロックの字下げを深くします。 +1. (普通)`Data.Traversable`で定義された `sequence`関数を使用して、次の関数を書いてください。 + + ```haskell + cat :: Array Doc -> Doc + ``` + + この関数は文書の集まりを改行で区切って連結します。 +1. (普通)`runReader`関数を使用して次の関数を書いてください。 + + ```haskell + render :: Doc -> String + ``` + + この関数は文書を文字列として出力します。 + + これでライブラリを使って以下のような単純な文書を書けるようになりました。 + + ```haskell + render $ cat + [ line "Here is some indented text:" + , indent $ cat + [ line "I am indented" + , line "So am I" + , indent $ line "I am even more indented" + ] + ] + ``` + +## Writerモナド + +`Writer`モナドでは、計算の返り値に加えてもう1つの値を累算できます。 + +よくある使い方としては型`String`もしくは`Array +String`でログを累算していくというものなどがありますが、`Writer`モナドはこれよりもっと一般的なものです。 +累算するのに任意のモノイドの値を使うことができるので、`Additive Int`モノイドを使って整数の合計を追跡するのに使ったり、`Disj +Boolean`モノイドを使って途中の`Boolean`値の何れかが真であるかどうかを追跡するのに使えます。 + +`Writer`型構築子は2つの型引数を取ります。 +`Monoid`型クラスのインスタンスである型`w`と返り値の型`a`です。 + +`Writer`のAPIで重要なのは `tell`関数です。 + +```haskell +tell :: forall w a. Monoid w => w -> Writer w Unit +``` + +`tell`動作は与えられた値を現在の累算結果に付け加えます。 + +例として、`Array String`モノイドを使用して、既存の関数にログを追加してみましょう。 +*最大公約数*関数の以前の実装を考えてみます。 + +```haskell +gcd :: Int -> Int -> Int +gcd n 0 = n +gcd 0 m = m +gcd n m = if n > m + then gcd (n - m) m + else gcd n (m - n) +``` + +`Writer (Array String) Int`へと返り値の型を変更することで、この関数にログ機能を追加できます。 + +```haskell +import Control.Monad.Writer +import Control.Monad.Writer.Class + +gcdLog :: Int -> Int -> Writer (Array String) Int +``` + +各手順での2つの入力を記録するためには、少し関数を変更する必要があります。 + +```haskell + gcdLog n 0 = pure n + gcdLog 0 m = pure m + gcdLog n m = do + tell ["gcdLog " <> show n <> " " <> show m] + if n > m + then gcdLog (n - m) m + else gcdLog n (m - n) +``` + +`Writer`モナドを計算するには、`execWriter`関数または`runWriter`関数の何れかを使います。 + +```haskell +execWriter :: forall w a. Writer w a -> w +runWriter :: forall w a. Writer w a -> Tuple a w +``` + +ちょうど `State`モナドの場合と同じように、 `execWriter`が累算されたログだけを返すのに対して、 +`runWriter`は累算されたログと結果の両方を返します。 + +PSCiで改変した関数を試してみましょう。 + +```text +> import Control.Monad.Writer +> import Control.Monad.Writer.Class + +> runWriter (gcdLog 21 15) +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`が偶数なら`n / 2`、`n`が奇数なら`3 * n + 1`です。 + 例えば`10`で始まるコラッツ数列は以下です。 + + ```text + 10, 5, 16, 8, 4, 2, 1, ... + ``` + + コラッツ関数の有限回の適用を繰り返すと、コラッツ数列は必ず最終的に `1`になるということが予想されています。 + + 再帰を使い、数列が`1`に到達するまでに何回のコラッツ関数の適用が必要かを計算する関数を書いてください。 + + `Writer`モナドを使用してコラッツ関数の各適用の経過を記録するように、関数を変更してください。 + +## モナド変換子 + +上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*の例となっています。 +対応する各モナド変換子はそれぞれ`StateT`、`ReaderT`、`WriterT`という名前です。 + +モナド変換子とは何でしょうか。 +さて、これまで見てきたように、モナドはPureScriptのコードを何らかの種類の副作用で拡張するものでした。 +このモナドはPureScriptで適切な制御子(`runState`、 `runReader`、`runWriter`など)を使って解釈できます。 +使用する必要がある副作用が*1つだけ*なら、これで問題ありません。 +しかし、同時に複数の副作用を使用できると便利なことがよくあります。 +例えば、 `Maybe`と`Reader`を一緒に使用すると、ある大域的な設定の文脈で*省略可能な結果*を表現できます。 +もしくは、 `Either`モナドの純粋なエラー追跡機能と、 `State`モナドが提供する変更可能な状態が同時に欲しくなるかもしれません。 +この問題を解決するのが*モナド変換子*です。 + +ただし`Effect`モナドがこの問題を部分的に解決することは既に見ました。 +モナド変換子はまた違った解決策を提供しますが、これらの各手法には利点と制約があります。 + +モナド変換子は型と別の型構築子を引数に取る型構築子です。 +モナドを1つ取り、独自の様々な副作用を追加した別のモナドへと変換します。 + +例を見てみましょう。`State`のモナド変換子版は`Control.Monad.State.Trans`モジュールで定義されている`StateT`です。 +PSCiを使って `StateT`の種を見てみましょう。 + +```text +> import Control.Monad.State.Trans +> :kind StateT +Type -> (Type -> Type) -> Type -> Type +``` + +とても読みにくそうに見えるかもしれませんが、使い方を理解するために、`StateT`に1つ引数を与えてみましょう。 + +`State`の場合、最初の型引数は使いたい状態の型です。 +それでは型`String`を与えてみましょう。 + +```text +> :kind StateT String +(Type -> Type) -> Type -> Type +``` + +次の引数は種 `Type -> Type`の型構築子です。 +これは `StateT`の機能を追加したい元のモナドを表します。 +例として、 `Either String`モナドを選んでみます。 + +```text +> :kind StateT String (Either String) +Type -> Type +``` + +型構築子が残りました。 +最後の引数は戻り値の型を表しており、例えばそれを`Number`にできます。 + +```text +> :kind StateT String (Either String) Number +Type +``` + +最後に種`Type`の何かが残りました。 +つまりこの型の値を探してみることができます。 + +構築したモナド`StateT String (Either String)`は、エラーで失敗する可能性があり、変更可能な状態を使える計算を表しています。 + +外側の`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 +``` + +このクラスは単一のメンバー`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`の作用を使えます。 + +例えば、次の計算は通底する状態を読み、状態が空文字列であればエラーを投げます。 + +```haskell +import Data.String (drop, take) + +split :: StateT String (Either String) String +split = do + s <- get + case s of + "" -> lift $ Left "Empty string" + _ -> do + put (drop 1 s) + pure (take 1 s) +``` + +状態が空でなければ、この計算は`put`を使って状態を`drop 1 s`(つまり`s`から最初の文字を取り除いたもの)へと更新し、`take 1 +s`(`s`の最初の文字)を返します。 + +それではPSCiでこれを試してみましょう。 + +```text +> runStateT split "test" +Right (Tuple "t" "est") + +> runStateT split "" +Left "Empty string" +``` + +これは`StateT`を使わなくても実装できるので、さほど驚くようなことはありません。 +しかし、モナドの中で扱っているので、do記法やアプリカティブコンビネータを使って、小さな計算から大きな計算を構築できます。 +例えば、2回`split`を適用すると、文字列から最初の2文字を読めます。 + +```text +> runStateT ((<>) <$> split <*> split) "test" +(Right (Tuple "te" "st")) +``` + +`split`関数とその他沢山の動作を使えば基本的な構文解析ライブラリを構築できます。 +実際、これは`parsing`ライブラリで採用されている手法です。 +これがモナド変換子の力なのです。 +必要な副作用を選択し、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。 + +## ExceptTモナド変換子 + +`transformers`パッケージでは`ExceptT e`モナド変換子も定義されています。 +これは`Either e`モナドに対応するもので、以下のAPIを提供します。 + +```haskell +class MonadError e m where + throwError :: forall a. e -> m a + catchError :: forall a. m a -> (e -> m a) -> m a + +instance Monad m => MonadError e (ExceptT e m) + +runExceptT :: forall e m a. ExceptT e m a -> m (Either e a) +``` + +`MonadError`クラスは`e`型のエラーを投げたり捕えたりに対応するモナドを捕捉し、`ExceptT +e`モナド変換子のインスタンスが提供されます。 +`Either e`モナドの`Left`と同じように、`throwError`動作では失敗を示せます。 +`catchError`動作では`throwError`を使ってエラーが投げられた後に処理を継続できます。 + +`runExceptT`制御子を使うと、型 `ExceptT e m a`を計算できます。 + +このAPIは `exceptions`パッケージの `Exception`作用によって提供されているものと似ています。 +しかし、幾つかの重要な違いがあります。 + +- `Exception`が実際のJavaScriptの例外を使っているのに対して`ExceptT`モデルは代数的データ型を使っています。 +- `Exception`作用がJavaScriptの`Error`型という1つの例外の型だけを扱うのに対して、`ExceptT`は`Error`型クラスのどんな型のエラーでも扱います。つまり、 + `ExceptT`では新たなエラー型を自由に定義できます。 + +試しに`ExceptT`を使って`Writer`モナドを包んでみましょう。 +ここでもモナド変換子`ExceptT e`の動作を直接使うことも自由にできますが、`Writer`モナドの計算は`lift`を使って持ち上げるべきです。 + +```haskell +import Control.Monad.Except +import Control.Monad.Writer + +writerAndExceptT :: ExceptT String (Writer (Array String)) String +writerAndExceptT = do + lift $ tell ["Before the error"] + _ <- throwError "Error!" + lift $ tell ["After the error"] + pure "Return value" +``` + +PSCiでこの関数を試すと、ログの蓄積とエラーの送出という2つの作用がどのように相互作用しているのかを見ることができます。 +まず、 `runExceptT`を使って外側の`ExceptT`を計算し、型 `Writer (Array String) (Either String +String)`の結果を残します。 +それから、 `runWriter`で内側の`Writer`を計算します。 + +```text +> runWriter $ runExceptT writerAndExceptT +Tuple (Left "Error!") ["Before the error"] +``` + +なお、エラーが投げられる前に書き出されるログ文言だけがログに追記されます。 + +## モナド変換子スタック + +これまで見てきたように、モナド変換子を使って既存のモナドを土台に新しいモナドを構築できます。 +何かのモナド変換子`t1`とモナド`m`について、その適用`t1 m`もまたモナドになります。 +つまり、*2つめの*モナド変換子`t2`を結果`t1 m`に適用すると、3つ目のモナド`t2 (t1 m)`を作れます。 +このようにしてモナド変換子の*スタック*を構築できます。 +これは構成されるモナドによって提供される副作用を組み合わせるものです。 + +実際には、通底するモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さもなくば`Data.Identity`モジュールで定義されている`Identity`モナドになります。 +`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換はモナド変換子の作用だけを提供します。 +`State`、`Reader`、`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`、`ReaderT`、`WriterT`で変換することによって実装されています。 + +3つの副作用が組み合わっている例を見てみましょう。 +`Identity`モナドをスタックの底にして、`StateT`、`WriterT`、`ExceptT`作用を使います。 +このモナド変換子スタックは、可変状態、ログの蓄積、そして純粋なエラーの副作用を提供します。 + +このモナド変換子スタックを使うと、ロギングの機能が追加された `split`アクションに作り変えられます。 + +```haskell +type Errors = Array String + +type Log = Array String + +type Parser = StateT String (WriterT Log (ExceptT Errors Identity)) + +split :: Parser String +split = do + s <- get + lift $ tell ["The state is " <> s] + case s of + "" -> lift $ lift $ throwError ["Empty string"] + _ -> do + put (drop 1 s) + pure (take 1 s) +``` + +この計算をPSCiで試してみると、 `split`が実行されるたびに状態がログに追加されることがわかります。 + +なお、モナド変換子スタックに現れる順序で副作用を取り除いていかなければなりません。 +最初に`StateT`型構築子を取り除くために`runStateT`を、それから`runtWriteT`、`runExceptT`を使います。 +最後に`unwrap`を使用して`Identity`モナド中で計算します。 + +```text +> runParser p s = unwrap $ runExceptT $ runWriterT $ runStateT p s + +> runParser split "test" +(Right (Tuple (Tuple "t" "est") ["The state is test"])) + +> runParser ((<>) <$> split <*> split) "test" +(Right (Tuple (Tuple "te" "st") ["The state is test", "The state is est"])) +``` + +しかし、状態が空であることが理由で解析が失敗した場合、ログは全く出力されません。 + +```text +> runParser split "" +(Left ["Empty string"]) +``` + +これは、`ExceptT`モナド変換子が提供する副作用と`WriterT`モナド変換子が提供する副作用との関係によるものです。 +これはモナド変換子スタックが構成されている順序を変更することで対処できます。 +スタックの最上部に`ExceptT`変換子を移動すると、先ほど`Writer`を`ExceptT`に変換したときに見たように、最初のエラーまでに書かれた全ての文言がログに含まれるようになります。 + +このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、`lift`関数を複数回使わなければならないということです。 +例えば`throwError`の呼び出しは、1回目は`WriteT`へ、2回目は`StateT`へ、と2回持ちあげなければなりません。 +小さなモナド変換子スタックならなんとかなりますが、そのうちすぐに不便になるでしょう。 + +幸いなことに、これから見るような型クラス推論によって提供されるコードの自動生成を使うと、ほとんどの「重労働」を任せられます。 + +## 演習 + + 1. (簡単)`Identity`関手を土台とする`ExceptT`モナド変換子を使って、2つの数の商を求める関数 + `safeDivide`を書いてください。 + この関数は分母がゼロの場合に(文字列「Divide by zero!」の)エラーを投げます。 + 1. (普通)次のような構文解析関数を書いてください。 + + ```haskell + string :: String -> Parser String + ``` + + これは現在の状態が接頭辞に照合するか、もしくはエラー文言とともに失敗します。 + + この構文解析器は次のように動作します。 + + ```text + > runParser (string "abc") "abcdef" + (Right (Tuple (Tuple "abc" "def") ["The state is abcdef"])) + ``` + + *手掛かり*:出発点として`split`の実装が使えます。 + `stripPrefix`関数も役に立つかもしれません。 +1. (難しい)文書表示ライブラリを、`ReaderT`と`WriterT`モナド変換子を使用して再実装してください。 + 以前`Reader`モナドを使用して書いたものです。 + + 文字列を出力する `line`や文字列を連結する `cat`を使うのではなく、`WriteT`モナド変換子と一緒に `Array String`モノイドを使い、結果へ行を追加するのに `tell`を使ってください。 + アポストロフィ (`'`) を付ける以外は元の実装と同じ名前を使ってください。 + +## 型クラスが助けに来たぞっ + +本章の最初で扱った `State`モナドを見てみると、 `State`モナドの動作には次のような型が与えられていました。 + +```haskell +get :: forall s. State s s +put :: forall s. s -> State s Unit +modify :: forall s. (s -> s) -> State s Unit +``` + +`Control.Monad.State.Class`モジュールで与えられている型は、実際にはこれよりもっと一般的です。 + +```haskell +get :: forall m s. MonadState s m => m s +put :: forall m s. MonadState s m => s -> m Unit +modify :: forall m s. MonadState s m => (s -> s) -> m Unit +``` + +`Control.Monad.State.Class`モジュールには`MonadState`(多変数)型クラスが定義されています。 +この型クラスは「変更可能な状態を提供する純粋なモナド」への抽象化を可能にします。 +予想できると思いますが、 `State s`型構築子は `MonadState +s`型クラスのインスタンスになっており、このクラスには他にも興味深いインスタンスが数多くあります。 + +特に、`transformers`パッケージではモナド変換子`WriterT`、`ReaderT`、`ExceptT`についての`MonadState`のインスタンスがあります。 +通底する`Monad`が`MonadState`インスタンスを持つなら常に、これらもインスタンスを持ちます。 +実践的には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく、`get`、`put`、`modify`を直接自由に使用できます。 + +当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが言えます。 +`transformers`では主な各変換子について型クラスが定義されています。 +これによりそれらの操作に対応するモナドの上に抽象化できるのです。 + +上の`split`関数の場合、構築したモナドスタックは各型クラス`MonadState`、`MonadWriter`、`MonadError`のインスタンスです。 +つまり`lift`は全く呼び出す必要がないのです。 +まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、`tell`、`throwError`をそのまま使用できます。 + +```haskell +{{#include ../exercises/chapter11/src/Split.purs:split}} +``` + +この計算は、独自のプログラミング言語を拡張し、可変状態、ロギング、エラー処理という3つの新しい副作用に対応したように見えます。 +しかし、内部的には全てはあくまで純粋な関数と不変のデータを使って実装されているのです。 + +## 代替 + +`control`パッケージでは失敗しうる計算を扱う抽象化が数多く定義されています。 +その1つは`Alternative`型クラスです。 + +```haskell +class Functor f <= Alt f where + alt :: forall a. f a -> f a -> f a + +class Alt f <= Plus f where + empty :: forall a. f a + +class (Applicative f, Plus f) <= Alternative f +``` + +`Alternative`は2つの新しいコンビネータを提供しています。 +1つは失敗しうる計算の雛形を提供する`empty`値で、もう1つはエラーが起きたときに*代替の*計算へ戻ってやり直す機能を提供する`alt`関数(そしてその別名`<|>`)です。 + +`Data.Array`モジュールでは `Alternative`型クラスで型構築子を操作する2 +つの便利な関数を提供します。 + +```haskell +many :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a) +some :: forall f a. Alternative f => Lazy (f (Array a)) => f a -> f (Array a) +``` + +`Data.List`にも等価な`many`と`some`があります。 + +`many`コンビネータは計算を*ゼロ回以上*繰り返し実行するために`Alternative`型クラスを使います。 +`some`コンビネータも似ていますが、最低1回は計算が成功する必要があります。 + +`Parser`モナド変換子スタックの場合は、`ExceptT`コンポーネントによる`Alternative`のインスタンスがあります。 +このコンポーネントでは異なる分枝のエラーに`Monoid`インスタンスを使って組み合わせることによって対応しています(だから`Errors`型に`Array +String`を選ぶ必要があったんですね)。 +これは、構文解析器を複数回実行するのに`many`関数と`some`関数を使うことができることを意味します。 + +```text +> import Data.Array (many) + +> runParser (many split) "test" +(Right (Tuple (Tuple ["t", "e", "s", "t"] "") + [ "The state is \"test\"" + , "The state is \"est\"" + , "The state is \"st\"" + , "The state is \"t\"" + ])) +``` + +ここでは入力文字列 `"test"`は、1文字からなる文字列4つの配列を返すように繰り返し分割されています。 +残った状態は空で、ログは `split`コンビネータが4回適用されたことを示しています。 + +## モナド内包表記 + +`Control.MonadPlus`モジュールには `MonadPlus`と呼ばれる`Alternative`型クラスの副クラスが定義されています。 +`MonadPlus`はモナドと`Alternative`両方のインスタンスである型構築子を取ります。 + +```haskell +class (Monad m, Alternative m) <= MonadPlus m +``` + +実際、`Parser`モナドは `MonadPlus`のインスタンスです。 + +以前本書中で配列内包表記を押さえたとき、`guard`関数を導入しました。 +これは欲しくない結果を取り除けるのに使えました。 +実際には`guard`関数はもっと一般的で、`MonadPlus`のインスタンスである任意のモナドに対して使えます。 + +```haskell +guard :: forall m. Alternative m => Boolean -> m Unit +``` + +`<|>`演算子は失敗時にバックトラッキングできるようにします。 +これがどのように役立つかを見るために、大文字だけに照合する`split`コンビネータの亜種を定義してみましょう。 + +```haskell +{{#include ../exercises/chapter11/src/Split.purs:upper}} +``` + +ここで、文字列が大文字でない場合に失敗するよう、`guard`を使用しています。 +なお、このコードは前に見た配列内包表記とよく似ています。 +このように`MonadPlus`を使うことは、*モナド内包表記*の構築と呼ばれることがあります。 + +## バックトラッキング + +`<|>`演算子を使うと、失敗したときに別の代替計算へとバックトラックできます。 +これを確かめるために、小文字に一致するもう1つの構文解析器を定義してみましょう。 + +```haskell +{{#include ../exercises/chapter11/src/Split.purs:lower}} +``` + +これにより、まずもし最初の文字が大文字なら複数の大文字に照合し、さもなくばもし最初の文字が小文字なら複数の小文字に照合する、という構文解析器を定義できます。 + +```text +> upperOrLower = some upper <|> some lower +``` + +この構文解析器は、大文字と小文字が切り替わるまで、文字に照合し続けます。 + +```text +> runParser upperOrLower "abcDEF" +(Right (Tuple (Tuple ["a","b","c"] ("DEF")) + [ "The state is \"abcDEF\"" + , "The state is \"bcDEF\"" + , "The state is \"cDEF\"" + ])) +``` + +また、`many`を使うと文字列を小文字と大文字の要素に完全に分割できます。 + +```text +> components = many upperOrLower + +> runParser components "abCDeFgh" +(Right (Tuple (Tuple [["a","b"],["C","D"],["e"],["F"],["g","h"]] "") + [ "The state is \"abCDeFgh\"" + , "The state is \"bCDeFgh\"" + , "The state is \"CDeFgh\"" + , "The state is \"DeFgh\"" + , "The state is \"eFgh\"" + , "The state is \"Fgh\"" + , "The state is \"gh\"" + , "The state is \"h\"" + ])) +``` + +繰り返しになりますが、これはモナド変換子が齎す再利用性の威力を示しています。 +標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器を、ほんの数行のコードで書くことができました。 + +## 演習 + + 1. (簡単)`string`構文解析器の実装から`lift`関数の呼び出しを取り除いてください。 + 新しい実装の型検査が通ることを確認し、そうなることを納得するまで確かめましょう。 + 1. (普通)`string`構文解析器と`some`コンビネータを使って構文解析器`asFollowedByBs`を書いてください。 + これは文字列`"a"`の連続と、それに続く文字列`"b"`の連続からなる文字列を認識するものです。 + 1. (普通)`<|>`演算子を使って構文解析器`asOrBs`を書いてください。 + これは文字`a`と文字`b`が任意の順序で現れる文字列を認識します。 + 1. (難しい)`Parser`モナドを次のようにも定義できます。 + + ```haskell + type Parser = ExceptT Errors (StateT String (WriterT Log Identity)) + ``` + + このように変更すると、構文解析関数にどのような影響を与えるでしょうか。 + +## RWSモナド + +モナド変換子のとある特定の組み合わせは頻出なので、`transformers`パッケージ内の単一のモナド変換子として提供されています。 +`Reader`、`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わさり、より単純に`RWS`モナドともされます。 +このモナドは`RWST`モナド変換子という名前の、対応するモナド変換子を持ちます。 + +ここでは `RWS`モナドを使ってテキストアドベンチャーゲームの処理を設計していきます。 + +`RWS`モナドは(戻り値の型に加えて)3つの型変数を使って定義されています。 + +```haskell +type RWS r w s = RWST r w s Identity +``` + +なお、`RWS`モナドは基底のモナドを`Identity`に設定することで独自のモナド変換子として定義されています。 +`Identity`は副作用を提供しないのでした。 + +最初の型引数`r`は大域的な構成の型を表します。 +2つ目の`w`はログを蓄積するために使用するモノイドを表します。 +3つ目の`s`は可変状態の型です。 + +このゲームの場合には、大域的な設定は +`Data.GameEnvironment`モジュールの`GameEnvironment`という名前の型で定義されています。 + +```haskell +{{#include ../exercises/chapter11/src/Data/GameEnvironment.purs:env}} +``` + +プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義されています。 +モナド変換子を実行するとなると、これらのオプションがコマンドラインから設定されます。 + +可変状態は `Data.GameState`モジュールの `GameState`と呼ばれる型で定義されています。 + +```haskell +{{#include ../exercises/chapter11/src/Data/GameState.purs:imports}} + +{{#include ../exercises/chapter11/src/Data/GameState.purs:GameState}} +``` + +`Coords`データ型は2次元平面の点を表し、 `GameItem`データ型はゲーム内のアイテムの列挙です。 + +```haskell +{{#include ../exercises/chapter11/src/Data/GameItem.purs:GameItem}} +``` + +`GameState`型は2つの新しいデータ構造を使っています。 +`Map`と`Set`はそれぞれ整列されたマップと整列された集合を表します。 +`items`属性は、ゲーム平面上の座標からその位置にあるゲームアイテムの集合への対応付けです。 +`player`属性はプレイヤーの現在の座標を格納し、`inventory`属性は現在プレイヤーが保有するゲームアイテムの集合を格納します。 + +`Map`と`Set`のデータ構造はキーによって整列され、このキーには`Ord`型クラスの任意の型を使えます。 +つまりデータ構造中のキーは完全に順序付けされます。 + +ゲームの動作を書く上で`Map`と`Set`構造をどのように使っていくのかを見ていきます。 + +ログとしては `List String`モノイドを使います。 +`Game`モナド用の型同義語を定義し、`RWS`を使って実装できます。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:Game}} +``` + +## ゲームロジックの実装 + +`Reader`、`Writer`、`State`モナドの動作を再利用することで、`Game`モナドで定義されている単純な動作を組み合わせてゲームを構築していきます。 +このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドは結果からコンソールにテキストを出力するような観測可能な副作用へと変換するために使っています。 + +このゲームで最も簡単な動作の1つは `has`動作です。 +この動作はプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調べます。 +これは次のように定義されます。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:has}} +``` + +この関数は、現在のゲームの状態を読み取るために`MonadState`型クラスで定義されている`get`動作を使っています。 +それから指定した`GameItem`が持ち物のアイテムの`Set`に出現するかどうかを調べるために`Data.Set`で定義されている`member`関数を使っています。 + +他にも`pickUp`動作があります。 +現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加します。 +これには`MonadWriter`と`MonadState`型クラスの動作を使っています。 +一番最初に現在のゲームの状態を読み取ります。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:pickup_start}} +``` + +次に `pickUp`は現在の位置にあるアイテムの集合を検索します。 +これは`Data.Map`で定義された `lookup`関数を使って行います。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:pickup_case}} +``` + +`lookup`関数は`Maybe`型構築子で示される省略可能な結果を返します。 +`lookup`関数は、キーがマップにない場合は`Nothing`を返します。 +それ以外の場合は`Just`構築子で対応する値を返します。 + +関心があるのは、指定されたゲームアイテムが対応するアイテムの集合に含まれている場合です。 +ここでも`member`関数を使うとこれを調べることができます。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}} +``` + +この場合、`put`を使ってゲームの状態を更新し、`tell`を使ってログに文言を追加できます。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:pickup_body}} +``` + +ここで2つの計算のどちらも`lift`が必要ないことに注意してください。 +なぜなら`MonadState`と`MonadWriter`の両方について`Game`モナド変換子スタック用の適切なインスタンスが存在するからです。 + +`put`への引数では、レコード更新を使ってゲームの状態の`items`及び`inventory`フィールドを変更しています。 +また、特定のキーの値を変更する`Data.Map`の`update`関数を使っています。 +今回の場合、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`関数を使って指定したアイテムを集合から取り除いています。 +`insert`を使って新しいアイテムをプレイヤーの持ち物の集合に加えるときにも、`inventory`は更新されます。 + +最後に、`pickUp`関数は`tell`を使ってユーザに通知することにより、残りの場合を処理します。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:pickup_err}} +``` + +`Reader`モナドを使う例として、 `debug`コマンドのコードを見てみましょう。 +ゲームがデバッグモードで実行されている場合、このコマンドを使うとユーザは実行時にゲームの状態を調べることができます。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:debug}} +``` + +ここでは、ゲームの構成を読み込むために`ask`動作を使用しています。 +繰り返しますが、どの計算でも`lift`する必要がなく、同じdo記法ブロック内で`MonadState`、`MonadReader`、`MonadWriter`型クラスで定義されている動作を使える点に注意してください。 + +`debugMode`フラグが設定されている場合、`tell`動作を使うとログに状態が書き込まれます。 +そうでなければ、エラー文言が追加されます。 + +`Game`モジュールの残りの部分では同様の動作の集合が定義されています。 +各動作は`MonadState`、`MonadReader`、`MonadWriter`型クラスにより定義された動作のみを使っています。 + +## 計算の実行 + +このゲームロジックは`RWS`モナドで動くため、ユーザのコマンドに応答するために計算する必要があります。 + +このゲームのフロントエンドは2つのパッケージで構成されています。 +アプリカティブなコマンドライン構文解析を提供する`optparse`と、対話的なコンソールベースのアプリケーションを書くことを可能にする、NodeJSの +`readline`モジュールを梱包する `node-readline`パッケージです。 + +このゲームロジックへのインターフェースは `Game`モジュール内の関数`game`によって提供されます。 + +```haskell +{{#include ../exercises/chapter11/src/Game.purs:game_sig}} +``` + +これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してから、`runRWS`を使って結果の`RWS`を計算します。 + +```haskell +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`を組み合わせたように見えます。 +引数として大域的な構成及び初期状態を取り、ログ、結果、最終的な状態を含むデータ構造を返します。 + +このアプリケーションのフロントエンドは、次の型シグネチャを持つ関数`runGame`によって定義されます。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:runGame_sig}} +``` + +この関数は(`node-readline`と`console`パッケージを使って)コンソールを介してユーザとやり取りします。 +`runGame`は関数の引数としてのゲームの設定を取ります。 + +`node-readline`パッケージでは`LineHandler`型が提供されています。 +これは端末からのユーザ入力を扱う`Effect`モナドの動作を表します。 +対応するAPIは次の通りです。 + +```haskell +type LineHandler a = String -> Effect a + +foreign import setLineHandler + :: forall a + . Interface + -> LineHandler a + -> Effect Unit +``` + +`Interface`型はコンソールの制御子を表しており、コンソールとやり取りする関数への引数として渡されます。 +`createConsoleInterface`関数を使用すると`Interface`を作成できます。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:import_RL}} + +{{#include ../exercises/chapter11/src/Main.purs:runGame_interface}} +``` + +最初の工程はコンソールにプロンプトを設定することです。 +`interface`制御対象を渡し、プロンプト文字列と字下げレベルを与えます。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:runGame_prompt}} +``` + +今回は行制御関数を実装することに関心があります。 +ここでの行制御は`let`宣言内の補助関数を使って次のように定義されています。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:runGame_lineHandler}} +``` + +`let`束縛が`env`という名前のゲーム構成や`interface`という名前のコンソール制御対象を包み込んでいます。 + +この制御子は追加の最初の引数としてゲームの状態を取ります。 +ゲームのロジックを実行するために`runRWS`にゲームの状態を渡さなければならないので、これは必要となっています。 + +この動作が最初に行うことは、`Data.String`モジュールの `split`関数を使用して、ユーザーの入力を単語に分割することです。 +それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`モナドで)`game`動作を実行しています。 + +純粋な計算であるゲームロジックを実行するには、画面に全てのログ文言を出力して、ユーザに次のコマンドのためのプロンプトを表示する必要があります。 +`for_`動作が(`List String`型の)ログを走査し、コンソールにその内容を出力するために使われています。 +最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`動作を使ってプロンプトを再び表示しています。 + +`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付けて、初期プロンプトを表示します。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:runGame_attach_handler}} +``` + +## 演習 + + 1. (普通)ゲームの格子上にある全てのゲームアイテムをユーザの持ちものに移動する新しいコマンド `cheat`を実装してください。 + 関数`cheat :: Game Unit`を`Game`モジュールに作り、この関数を`game`から使ってください。 + 1. (難しい)`RWS`モナドの ` Writer`コンポーネントは、エラー文言とお知らせ文言の2つの種類の文言のために使われています。 + このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用しています。 + + コードをリファクタリングしてください。 + エラー文言を扱うのに`ExceptT`モナド変換子を使い、お知らせ文言を扱うのに`RWS`を使います。 + *補足*:この演習にはテストがありません。 + +## コマンドラインオプションの扱い + +このアプリケーションの最後の部品には、コマンドラインオプションの解析と`GameEnvironment`設定レコードを作成する役目があります。 +このためには`optparse`パッケージを使用します。 + +`optparse`は*アプリカティブなコマンドラインオプション構文解析器*の一例です。 +アプリカティブ関手を使うと、いろいろな副作用の型を表す型構築子まで任意個数の引数の関数を持ち上げられることを思い出してください。 +`optparse`パッケージの場合には、コマンドラインオプションからの読み取りの副作用を追加する`Parser`関手(optparseのモジュール`Options.Applicative`からインポートされたもの。`Split`モジュールで定義した`Parser`と混同しないように)が興味深い関手になっています。 +これは次のような制御子を提供しています。 + +```haskell +customExecParser :: forall a. ParserPrefs → ParserInfo a → Effect a +``` + +実例を見るのが一番です。 +このアプリケーションの `main`関数は`customExecParser`を使って次のように定義されています。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:main}} +``` + +最初の引数は`optparse`ライブラリを設定するために使用されます。 +今回の場合、アプリケーションが引数なしで走らされたときは、(「missing argument」エラーを表示する代わりに)`OP.prefs +OP.showHelpOnEmpty`を使って使用方法の文言を表示するように設定していますが、`Options.Applicative.Builder`モジュールには他にも幾つかの選択肢を提供しています。 + +2つ目の引数は解析プログラムの完全な説明です。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:argParser}} + +{{#include ../exercises/chapter11/src/Main.purs:parserOptions}} +``` + +ここで`OP.info`は、`Parser`をヘルプ文言の書式方法のためのオプションの集合と組み合わせます。 +`env <**> OP.helper`は`env`と名付けられた任意のコマンドライン引数`Parser`を取り、自動的に`--help`オプションを加えます。 +ヘルプ文言用のオプションは型が`InfoMod`であり、これはモノイドなので、`fold`関数を使って複数のオプションを一緒に追加できます。 + +解析器の面白い部分は`GameEnvironment`の構築にあります。 + +```haskell +{{#include ../exercises/chapter11/src/Main.purs:env}} +``` + +`player`と`debug`は両方とも`Parser`なので、アプリカティブ演算子`<$>`と`<*>`を使って`gameEnvironment`関数を持ち上げられます。 +この関数は`Parser`上で型`PlayerName -> Boolean -> GameEnvironment`を持ちます。 +`OP.strOption`は文字列値を期待するコマンドラインオプションを構築し、一緒に畳み込まれた`Mod`の集まりを介して構成されています。 +`OP.flag`は似たような動作をしますが、関連付けられた値は期待しません。 +`optparse`は多様なコマンドライン解析器を構築するために使える様々な修飾子について、大部の[ドキュメント](https://pursuit.purescript.org/packages/purescript-optparse)を提供しています。 + +アプリカティブ演算子により齎される記法を使うことで、コマンドラインインターフェイスの簡潔で宣言的な仕様を与えられた点に注目です。 +加えて、新しいコマンドライン引数を追加するのは単純で、`runGame`に新しい関数引数を追加し、`env`の定義中で`<*>`を使って追加の引数まで`runGame`を持ち上げるだけでできます。 + +## 演習 + + 1. (普通)`GameEnvironment`レコードに新しい真偽値のプロパティ`cheatMode`を追加してください。 + また、`optparse`の構成に、チートモードを有効にする新しいコマンドラインフラグ`-c`を追加してください。 + チートモードが有効になっていない場合、前の演習の`cheat`コマンドは禁止されます。 + +## まとめ + +この章ではこれまで学んできた技術を実践的に実演しました。 +モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロントエンドを構築するための`Effect`モナドがそれです。 + +ユーザインターフェイスからの実装を分離したので、ゲームの別のフロントエンドも作成できるでしょう。 +例えば、`Effect`モナドでCanvas APIやDOMを使用して、ブラウザでゲームを描画するようなことができるでしょう。 + +モナド変換子によって命令型のスタイルで安全なコードを書けることが分かりました。 +このスタイルでは型システムによって作用が追跡されています。 +加えて、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供し、これによりコードの再利用が可能になりました。 +標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のような標準的な抽象化を使用して、役に立つモナドを構築できました。 + +モナド変換子は表現力の高いコードの優れた実演となっています。 +これは高階多相や多変数型クラスなどの高度な型システムの機能を利用することによって記述できるものです。 diff --git a/text-ja/chapter12.md b/text-ja/chapter12.md new file mode 100644 index 00000000..82baa434 --- /dev/null +++ b/text-ja/chapter12.md @@ -0,0 +1,715 @@ +# Canvasグラフィックス + +## この章の目標 + +この章は`canvas`パッケージに焦点を当てる発展的な例となります。 +このパッケージはPureScriptでHTML5のCanvas APIを使用して2Dグラフィックスを生成する手段を提供します。 + +## プロジェクトの準備 + +このモジュールのプロジェクトでは以下の新しい依存関係が導入されます。 + +- `canvas`はHTML5のCanvas APIメソッドの型を与えます。 +- `refs`は _大域的な変更可能領域への参照_ を使うための副作用を提供します。 + +この章の各ソースコードは、`main`メソッドが定義されているモジュールの集合へと分割されています。 +この章の各節の内容は個別のファイルで実装されており、各時点での適切なファイルの`main`メソッドを実行できるように、Spagoビルドコマンドを変更することで、`Main`モジュールを合わせられるようになっています。 + +HTMLファイル`html/index.html`には、各例で使用される単一の`canvas`要素、及びコンパイルされたPureScriptコードを読み込む`script`要素が含まれています。 +各節のコードを試すにはブラウザでHTMLファイルを開きます。 +ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありません。 + +## 単純な図形 + +`Example/Rectangle.purs`ファイルには簡単な導入例が含まれています。 +この例ではキャンバスの中心に青い四角形を1つ描画します。 +このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas +APIを扱うための`Effect`モナドの動作を含む`Graphics.Canvas`モジュールをインポートします。 + +他のモジュールでも同様ですが、`main`動作は最初に`getCanvasElementById`動作を使ってキャンバスオブジェクトへの参照を取得し、`getContext2D`動作を使ってキャンバスの2D描画文脈にアクセスします。 + +`void`関数は関手を取り値を`Unit`で置き換えます。 +例では`main`がシグネチャに沿うようにするために使われています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Rectangle.purs:main}} +``` + +*補足*:この`unsafePartial`の呼び出しは必須です。 +これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと照合するためです。 +ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子と照合させ、適切なエラー文言を提供したほうがよいでしょう。 + +これらの動作の型はPSCiを使うかドキュメントを見ると確認できます。 + +```haskell +getCanvasElementById :: String -> Effect (Maybe CanvasElement) + +getContext2D :: CanvasElement -> Effect Context2D +``` + +`CanvasElement`と `Context2D`は `Graphics.Canvas`モジュールで定義されている型です。 +このモジュールでは`Canvas`作用も定義されており、モジュール内の全てのアクションで使用されています。 + +グラフィックス文脈`ctx`はキャンバスの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用したりするための手段を提供します。 + +話を進めると、`setFillStyle`動作を使うことで塗り潰しスタイルを濃い青に設定できます。 +より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がより簡単です。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Rectangle.purs:setFillStyle}} +``` + +`setFillStyle`動作がグラフィックス文脈を引数として取っていることに注意してください。 +これは`Graphics.Canvas`ではよくあるパターンです。 + +最後に、`fillPath`動作を使用して矩形を塗り潰しています。 +`fillPath`は次のような型を持っています。 + +```haskell +fillPath :: forall a. Context2D -> Effect a -> Effect a +``` + +`fillPath`はグラフィックスの文脈と描画するパスを構築する他の動作を引数に取ります。 +`rect`動作を使うとパスを構築できます。 +`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを取ります。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Rectangle.purs:fillPath}} +``` + +mainモジュールの名前として`Example.Rectangle`を与えてこの長方形のコード例をビルドしましょう。 + +```text +$ spago bundle-app --main Example.Rectangle --to dist/Main.js +``` + +それでは `html/index.html`ファイルを開き、このコードによってキャンバスの中央に青い四角形が描画されていることを確認してみましょう。 + +## 行多相を利用する + +パスを描画する方法は他にもあります。 +`arc`関数は円弧を描画します。 +`moveTo`関数、`lineTo`関数、`closePath`関数は断片的な線分のパスを描画できます。 + +`Shapes.purs`ファイルでは長方形と円弧と三角形の、3つの図形を描画しています。 + +`rect`関数は引数としてレコードをとることを見てきました。 +実際には、長方形のプロパティは型同義語で定義されています。 + +```haskell +type Rectangle = + { x :: Number + , y :: Number + , width :: Number + , height :: Number + } +``` + +`x`と`y`プロパティは左上隅の位置を表しており、`w`と`h`のプロパティはそれぞれ幅と高さを表しています。 + +`arc`関数に以下のような型を持つレコードを渡して呼び出すと、円弧を描画できます。 + +```haskell +type Arc = + { x :: Number + , y :: Number + , radius :: Number + , start :: Number + , end :: Number + } +``` + +ここで、`x`と`y`プロパティは弧の中心、`r`は半径、`start`と`end`は弧の両端の角度を弧度法で表しています。 + +例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰します。 +弧は1回転のうち2/3ラジアン分あります。 +単位円が上下逆様になっている点に注意してください。 +これはy軸がキャンバスの下向きに伸びるためです。 + +```haskell + fillPath ctx $ arc ctx + { x : 300.0 + , y : 300.0 + , radius : 50.0 + , start : 0.0 + , end : Math.tau * 2.0 / 3.0 + } +``` + +`Rectangle`レコード型と`Arc`レコード型の両方共、`Number`型の`x`と`y`というプロパティを含んでいますね。 +どちらの場合でもこの組は点を表しています。 +つまり、何れのレコード型にも作用する行多相な関数を書けます。 + +例えば`Shapes`モジュールでは`x`と`y`のプロパティを変更し図形を並行移動する`translate`関数が定義されています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Shapes.purs:translate}} +``` + +この行多相型に注目してください。 +`translate`が `x`と +`y`というプロパティと、*それに加えて他の任意のプロパティ*を持つどんなレコードでも受け入れ、同じ型のレコードを返すと書かれています。 +`x`フィールドと `y`フィールドは更新されますが、残りのフィールドは変更されません。 + +これは*レコード更新構文*の例です。 +`shape { ... }`という式は、`shape`を元にして、括弧の中で指定された値で更新されたフィールドを持つ新たなレコードを作ります。 +なお、波括弧の中の式はレコード直値のようなコロンではなく、等号でラベルと式を区切って書きます。 + +`Shapes`の例からわかるように、`translate`関数は`Rectangle`レコードと`Arc`レコード双方に対して使えます。 + +`Shape`の例で描画される3つ目の型は線分の断片からなるパスです。 +対応するコードは次のようになります。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Shapes.purs:path}} +``` + +ここでは3つの関数が使われています。 + +- `moveTo`はパスの現在地を指定された座標に移動します。 +- `lineTo`は現在地と指定された座標の間の線分を描画し、現在地を更新します。 +- `closePath`は現在地と開始地点とを結ぶ線分を描画してパスを完結します。 + +このコード片の結果は二等辺三角形の塗り潰しになります。 + +mainモジュールとして`Example.Shapes`を指定して、この例をビルドしましょう。 + +```text +$ spago bundle-app --main Example.Shapes --to dist/Main.js +``` + +そしてもう一度`html/index.html`を開き、結果を確認してください。 +キャンバスに3つの異なる図形が描画されるはずです。 + +## 演習 + + 1. (簡単)これまでの各例について、`strokePath`関数や`setStrokeStyle`関数を使ってみましょう。 + 1. (簡単)関数の引数の内部でdo記法ブロックを使うと、`fillPath`関数と`strokePath`関数は共通のスタイルを持つ複雑なパスを描画できます。 + 同じ`fillPath`呼び出しを使って隣り合う2つの矩形を描画するように、`Rectangle`の例を変更してみてください。 + 線分と円弧の組み合わせを使って、扇形を描画してみてください。 + 1. (普通)次のような2次元の点を表すレコードが与えられたとします。 + + ```haskell + type Point = { x :: Number, y :: Number } + ``` + + これは2次元の点を表現しています。 + 多数の点からなる閉じたパスを線描きする関数 `renderPath`を書いてください。 + + ```haskell + renderPath + :: Context2D + -> Array Point + -> Effect Unit + ``` + + 次のような関数を考えます。 + + ```haskell + f :: Number -> Point + ``` + + この関数は引数として`1`から`0`の間の`Number`を取り、`Point`を返します。 + `renderPath`関数を使い、関数`f`のグラフを描く動作を書いてください。 + その動作では有限個の点で`f`を標本化することによって近似しなければなりません。 + + 関数 `f`を変更し、様々なパスが描画されることを確かめてください。 + +## 無作為に円を描く + +`Example/Random.purs`ファイルには、`Effect`モナドを使って2種類の副作用を綴じ合わせる例が含まれています。 +1つの副作用は乱数生成で、もう1つはキャンバスの操作です。 +この例では無作為に生成された円をキャンバスに100個描画します。 + +`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗り潰しのスタイルを設定します。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Random.purs:style}} +``` + +次のコードでは`for_`動作を使って`0`から`100`までの整数について反復しています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Random.purs:for}} +``` + +各繰り返しで、do記法ブロックは`0`と`1`の間に分布する3つの乱数を生成することから始まります。 +これらの数はそれぞれ`x`座標、`y`座標、半径`r`を表しています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Random.purs:random}} +``` + +次のコードでは各円について、これらの変数に基づいて`Arc`を作成し、最後に現在のスタイルに従って円弧を塗り潰し線描きします。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Random.purs:path}} +``` + +mainモジュールとして`Example.Random`を指定して、この例をビルドしましょう。 + +```text +$ spago bundle-app --main Example.Random --to dist/Main.js +``` + +`html/index.html`を開いて、結果を確認してみましょう。 + +## 座標変換 + +キャンバスは簡単な図形を描画するだけのものではありません。 +キャンバスは座標変換を管理しており、描画の前に図形を変形するのに使えます。 +図形は平行移動、回転、拡大縮小、及び斜めに変形できます。 + +`canvas`ライブラリではこれらの変換を以下の関数で提供しています。 + +```haskell +translate :: Context2D + -> TranslateTransform + -> Effect Context2D + +rotate :: Context2D + -> Number + -> Effect Context2D + +scale :: Context2D + -> ScaleTransform + -> Effect Context2D + +transform :: Context2D + -> Transform + -> Effect Context2D +``` + +`translate`動作は`TranslateTransform`レコードのプロパティで指定した大きさだけ平行移動します。 + +`rotate`動作は最初の引数で指定されたラジアンの数値に応じて、原点を中心として回転します。 + +`scale`動作は原点を中心として拡大縮小します。 +`ScaleTransform`レコードは`x`軸と`y`軸に沿った拡大率を指定するのに使います。 + +最後の `transform`はこの4つのうちで最も一般化された動作です。 +この動作では行列に従ってアフィン変換します。 + +これらの動作が呼び出された後に描画される図形は、自動的に適切な座標変換が適用されます。 + +実際には、これらの関数の各作用は、文脈の現在の変換行列に対して変換行列を*右から乗算*していきます。 +つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されていきます。 + +```haskell +transformations ctx = do + translate ctx { translateX: 10.0, translateY: 10.0 } + scale ctx { scaleX: 2.0, scaleY: 2.0 } + rotate ctx (Math.tau / 4.0) + + renderScene +``` + +この一連の動作の作用では、まずシーンが回転され、それから拡大縮小され、最後に平行移動されます。 + +## 文脈の保存 + +座標変換を使ってシーンの一部を描画し、それからその変換を元に戻す、という使い方はよくあります。 + +Canvas APIにはキャンバスの状態の*スタック*を操作する`save`と`restore`メソッドが備わっています。 +`canvas`ではこの機能を次のような関数で梱包しています。 + +```haskell +save + :: Context2D + -> Effect Context2D + +restore + :: Context2D + -> Effect Context2D +``` + +`save`動作は現在の文脈の状態(現在の変換行列や描画スタイル)をスタックにプッシュし、`restore`動作はスタックの一番上の状態をポップし、文脈の状態を復元します。 + +これらの動作により、現在の状態を保存し、いろいろなスタイルや変換を適用してから原始的な図形を描画し、最後に元の変換と状態を復元できます。 +例えば次の関数は幾つかのキャンバス動作を実行しますが、その前に回転を適用し、その後に変換を復元します。 + +```haskell +rotated ctx render = do + save ctx + rotate (Math.tau / 3.0) ctx + render + restore ctx +``` + +こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元の文脈状態を保存しつつ幾つかのキャンバス動作を実行する`withContext`関数が提供されています。 + +```haskell +withContext + :: Context2D + -> Effect a + -> Effect a +``` + +`withContext`を使うと、先ほどの `rotated`関数を次のように書き換えることができます。 + +```haskell +rotated ctx render = + withContext ctx do + rotate (Math.tau / 3.0) ctx + render +``` + +## 大域的な変更可能状態 + +この節では `refs`パッケージを使って `Effect`モナドの別の作用について実演してみます。 + +`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及びそれに紐付く作用を提供します。 + +```text +> import Effect.Ref + +> :kind Ref +Type -> Type +``` + +型`Ref a`の値は型`a`の値を含む可変参照セルであり、大域的な変更を追跡するのに使われます。 +そういったわけでこれは少しだけ使う分に留めておくべきです。 + +`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに `Ref`を使う例が含まれます。 + +このコードでは最初に`new`動作を使って値`0`を含む新しい参照を作成しています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Refs.purs:clickCount}} +``` + +クリックイベント制御子の内部では、`modify`動作を使用してクリック数を更新し、更新された値が返されています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Refs.purs:count}} +``` + +`render`関数ではクリック数に応じた変換を矩形に適用しています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/Refs.purs:withContext}} +``` + +この動作では元の変換を保存するために`withContext`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。 + +- 矩形が`(-100, -100)`だけ平行移動し、中心が原点に来ます。 +- 矩形が原点を中心に拡大されます。 +- 矩形が原点を中心に`10`の倍数分の角度で回転します。 +- 矩形が`(300, 300)`だけ平行移動し、中心がキャンバスの中心に来ます。 + +このコード例をビルドしてみましょう。 + +```text +$ spago bundle-app --main Example.Refs --to dist/Main.js +``` + +`html/index.html`ファイルを開いてみましょう。 +緑の四角形が表示され、何度かキャンバスをクリックするとキャンバスの中心の周りで回転するはずです。 + +## 演習 + + 1. (簡単)パスの線描と塗り潰しを同時に行う高階関数を書いてください。 + その関数を使用して`Random.purs`の例を書き直してください。 + 1. (普通)`Random`作用と`Dom`作用を使用して、マウスがクリックされたときに、キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してください。 + 1. (普通)指定された座標の点を中心として回転させることでシーンを変換する関数を書いてください。 + *手掛かり*:変換を使い、最初にシーンを原点まで平行移動しましょう。 + +## L-System + +この章の最後の例として、 `canvas`パッケージを使用して*L-system*(またの名を*Lindenmayer +system*)を描画する関数を記述します。 + +1つのL-Systemは*アルファベット*、つまりアルファベット由来の文字の初期の並びと、*生成規則*の集合で定義されます。 +各生成規則は、アルファベットの文字を取り、それを置き換える文字の並びを返します。 +この処理は文字の初期の並びから始まり、複数回繰り返されます。 + +もしアルファベットの各文字がキャンバス上で実行される命令と対応付けられていれば、その指示に順番に従うことでL-Systemを描画できます。 + +例えばアルファベットが文字`L`(左回転)、`R`(右回転)、`F`(前進)で構成されているとします。 +次のような生成規則を定義できます。 + +```text +L -> L +R -> R +F -> FLFRRFLF +``` + +配列 "FRRFRRFRR" から始めて処理を繰り返すと、次のような経過を辿ります。 + +```text +FRRFRRFRR +FLFRRFLFRRFLFRRFLFRRFLFRRFLFRR +FLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLF... +``` + +というように続きます。 +この命令群に対応する線分パスをプロットすると、*コッホ曲線*に近似されます。 +反復回数を増やすと、曲線の解像度が増していきます。 + +それでは型と関数のある言語へとこれを翻訳してみましょう。 + +アルファベットの文字は以下のADTで表現できます。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:letter}} +``` + +このデータ型では、アルファベットの文字ごとに1つずつデータ構築子が定義されています。 + +文字の初期配列はどのように表したらいいでしょうか。 +単なるアルファベットの配列でいいでしょう。 +これを `Sentence`と呼ぶことにします。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:sentence}} + +{{#include ../exercises/chapter12/src/Example/LSystem.purs:initial}} +``` + +生成規則は以下のように`Letter`から `Sentence`への関数として表すことができます。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:productions}} +``` + +これはまさに上記の仕様をそのまま書き写したものです。 + +これで、この形式の仕様を受け取ってキャンバスに描画する関数`lsystem`を実装できます。 +`lsystem`はどのような型を持っているべきでしょうか。 +`initial`や`productions`のような値だけでなく、アルファベットの文字をキャンバスに描画できる関数を引数に取る必要があります。 + +`lsystem`の型の最初の大まかな設計は以下です。 + +```haskell +Sentence +-> (Letter -> Sentence) +-> (Letter -> Effect Unit) +-> Int +-> Effect Unit +``` + +最初の2つの引数の型は、値 `initial`と `productions`に対応しています。 + +3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行することによって*解釈*する関数を表します。 +この例では、文字`L`は左回転、文字`R`で右回転、文字`F`は前進を意味します。 + +最後の引数は、実行したい生成規則の繰り返し回数を表す数です。 + +最初に気付くことは、この`lsystem`関数は1つの型`Letter`に対してのみ動作するのですが、どんなアルファベットについても機能すべきですから、この型はもっと一般化されるべきです。 +それでは、量子化された型変数 `a`について、`Letter`と `Sentence`を `a`と `Array a`で置き換えましょう。 + +```haskell +forall a. Array a + -> (a -> Array a) + -> (a -> Effect Unit) + -> Int + -> Effect Unit +``` + +次に気付くこととしては、「左回転」と「右回転」のような命令を実装するためには、幾つかの状態を管理する必要があります。 +具体的に言えば、その時点でパスが動いている方向を状態として持たなければなりません。 +計算を通じて状態を渡すように関数を変更する必要があります。 +ここでも`lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数`s`を使用してそれを表しています。 + +型 `s`を追加する必要があるのは3箇所で、次のようになります。 + +```haskell +forall a s. Array a + -> (a -> Array a) + -> (s -> a -> Effect s) + -> Int + -> s + -> Effect s +``` + +まず追加の引数の型として `lsystem`に型 `s`が追加されています。 +この引数はL-Systemの初期状態を表しています。 + +型 +`s`は引数にも現れますが、解釈関数(`lsystem`の第3引数)の返り値の型としても現れます。解釈関数は今のところ、引数としてL-Systemの現在の状態を受け取り、返り値として更新された新しい状態を返します。 + +この例の場合では、次のような型を使って状態を表す型を定義できます。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:state}} +``` + +プロパティ `x`と `y`はパスの現在の位置を表しています。 +プロパティ`theta`はパスの現在の向きを表しており、ラジアンで表された水平線に対するパスの角度として指定されています。 + +システムの初期状態は次のように指定されます。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:initialState}} +``` + +それでは、 `lsystem`関数を実装してみます。定義はとても単純であることがわかるでしょう。 + +`lsystem`は第4引数の値(型は`Int`)に応じて再帰するのが良さそうです。 +再帰の各ステップでは、生成規則に従って状態が更新され、現在の文が変化していきます。 +このことを念頭に置きつつ、まずは関数の引数の名前を導入して、補助関数に処理を移譲することから始めましょう。 + +```haskell +lsystem :: forall a s + . Array a + -> (a -> Array a) + -> (s -> a -> Effect s) + -> Int + -> s + -> Effect s +{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_impl}} +``` + +`go`関数は第2引数について再帰することで動作します。 +場合分けは2つであり、`n`がゼロであるときと`n`がゼロでないときです。 + +1つ目の場合は再帰は完了し、解釈関数に応じて現在の文を解釈します。 +型`Array a`の文、型`s`の状態、型`s -> a -> Effect s`の関数があります。 +以前定義した`foldM`の出番のようです。 +この関数は`control`パッケージで手に入ります。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_0}} +``` + +ゼロでない場合ではどうでしょうか。 +その場合は、単に生成規則を現在の文のそれぞれの文字に適用して、その結果を連結し、そして再帰的に`go`を呼び出すことによって繰り返します。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_go_s_i}} +``` + +これだけです。 +`foldM`や`concatMap`のような高階関数を使うと、アイデアを簡潔に表現できるのです。 + +しかし、話はこれで終わりではありません。 +ここで与えた型は、実際はまだ特殊化されすぎています。 +この定義ではキャンバスの操作が実装のどこにも使われていないことに注目してください。 +それに、全く`Effecta`モナドの構造を利用していません。 +実際には、この関数は*どんな*モナド`m`についても動作します。 + +この章に添付されたソースコードで指定されている`lsystem`の型はもっと一般的になっています。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:lsystem_anno}} +``` + +この型で書かれていることは、この解釈関数はモナド`m`が持つ任意の副作用を完全に自由に持つことができる、ということだと理解できます。 +キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれませんし、失敗や複数の戻り値に対応しているかもしれません。 +こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めします。 + +この関数は実装からデータを分離することの威力を示す良い例となっています。 +この手法の利点は、複数の異なる方法でデータを解釈できることです。 +さらに`lsystem`を2つの小さな関数へと分解できます。 +1つ目は`concatMap`の適用の繰り返しを使って文を構築するもの、2つ目は`foldM`を使って文を解釈するものです。 +これは読者の演習として残しておきます。 + +それでは解釈関数を実装して、この章の例を完成させましょう。 +`lsystem`の型が教えてくれているのは、型シグネチャが、何らかの型 `a`と `s`、型構築子 `m`について、 `s -> a -> m s`でなければならないということです。 +`a`を `Letter`、 `s`を `State`、モナド `m`を `Effect`というように選びたいということがわかっています。 +これにより次のような型になります。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpret_anno}} +``` + +この関数を実装するには、 `Letter`型の3つのデータ構築子それぞれについて処理する必要があります。文字 `L`(左回転)と +`R`(右回転)の解釈では、`theta`を適切な角度へ変更するように状態を更新するだけです。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} +``` + +文字`F`(前進)を解釈するには、次のようにパスの新しい位置を計算し、線分を描画し、状態を更新します。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretF}} +``` + +なお、この章のソースコードでは、名前 `ctx`がスコープに入るように、`interpret`関数は `main`関数内で +`let`束縛を使用して定義されています。 +`State`型が文脈を持つように変更できるでしょうが、それはこのシステムの状態の変化する部分ではないので不適切でしょう。 + +このL-Systemを描画するには、次のような`strokePath`動作を使用するだけです。 + +```haskell +{{#include ../exercises/chapter12/src/Example/LSystem.purs:strokePath}} +``` + +次のコマンドを使ってL-Systemをコンパイルします。 + +```text +$ spago bundle-app --main Example.LSystem --to dist/Main.js +``` + +`html/index.html`を開いてみましょう。 +キャンバスにコッホ曲線が描画されるのがわかると思います。 + +## 演習 + + 1. (簡単)`strokePath`の代わりに `fillPath`を使用するように、上のL-Systemの例を変更してください。 + *手掛かり*:`closePath`の呼び出しを含め、 `moveTo`の呼び出しを `interpret`関数の外側に移動する必要があります。 + 1. (簡単)描画システムへの影響を理解するために、コード中の様々な数値の定数を変更してみてください。 + 1. (普通)`lsystem`関数を2つの小さな関数に分割してください。 + 1つ目は`concatMap`の適用の繰り返しを使用して最終的な文を構築するもので、2つ目は + `foldM`を使用して結果を解釈するものでなくてはなりません。 + 1. (普通)`setShadowOffsetX`、`setShadowOffsetY`、`setShadowBlur`、`setShadowColor`動作を使い、塗りつぶされた図形にドロップシャドウを追加してください。 + *手掛かり*:PSCiを使って、これらの関数の型を調べてみましょう。 + 1. (普通)向きを変えるときの角度の大きさは今のところ一定 (`tau/6`) です。 + これに代えて、`Letter`データ型の中に角度を移動させ、生成規則によって変更できるようにしてください。 + + ```haskell + type Angle = Number + + data Letter = L Angle | R Angle | F + ``` + + この新しい情報を生成規則でどう使うと、面白い図形を作ることができるでしょうか。 +1. (難しい)4つの文字からなるアルファベットでL-Systemが与えられたとします。 + それぞれ`L`(60度左回転)、`R`(60度右回転)、`F`(前進)、`M`(これも前進)です。 + + このシステムの文の初期状態は、単一の文字 `M`です。 + + このシステムの生成規則は次のように指定されています。 + + ```text + L -> L + R -> R + F -> FLMLFRMRFRMRFLMLF + M -> MRFRMLFLMLFLMRFRM + ``` + + このL-Systemを描画してください。 + *補足*:最後の文のサイズは反復回数に従って指数関数的に増大するので、生成規則の繰り返しの回数を削減する必要があります。 + + ここで、生成規則における `L`と `M`の間の対称性に注目してください。2つの「前進」命令は、次のようなアルファベット型を使用すると、`Boolean`値を使って区別できます。 + + ```haskell + data Letter = L | R | F Boolean + ``` + + このアルファベットの表現を使用して、もう一度このL-Systemを実装してください。 +1. (難しい)解釈関数で別のモナド `m`を使ってみましょう。`Effect.Console`作用を利用してコンソール上にL-Systemを出力したり、`Random`作用を利用して状態の型に無作為の「突然変異」を適用したりしてみてください。 + +## まとめ + +この章では、`canvas`ライブラリを使用することにより、PureScriptからHTML5 Canvas APIを使う方法について学びました。 +また、これまで学んできた多くの手法からなる実用的な実演を見ました。 +マップや畳み込み、レコードと行多相、副作用を扱うための`Effect`モナドです。 + +この章の例では、高階関数の威力を示すとともに、 _実装からのデータの分離_ +も実演してみせました。これは例えば、代数データ型を使用してこれらの概念を次のように拡張し、描画関数からシーンの表現を完全に分離できるようになります。 + +```haskell +data Scene + = Rect Rectangle + | Arc Arc + | PiecewiseLinear (Array Point) + | Transformed Transform Scene + | Clipped Rectangle Scene + | ... +``` + +この手法は`drawing`パッケージで取られており、描画前に様々な方法でシーンをデータとして操作できる柔軟性を齎しています。 + +キャンバスに描画されるゲームの例については[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 new file mode 100644 index 00000000..6483a1bd --- /dev/null +++ b/text-ja/chapter13.md @@ -0,0 +1,476 @@ +# テストの自動生成 + +## この章の目標 + +この章では、テスティングの問題に対する、型クラスの特に洗練された応用について示します。 +*どのように*テストするのかをコンパイラに教えるのではなく、コードが*どのような*性質を持っているべきかを教えることでテストします。 +型クラスを使って無作為データ生成のための紋切り型なコードを書かずして、テスト項目を仕様から無作為に生成できます。 +これは*生成的テスティング*(generative testing、または*property-based +testing*)と呼ばれ、Haskellの[QuickCheck](http://wiki.haskell.org/Introduction_to_QuickCheck1)ライブラリによって普及した手法です。 + +`quickcheck`パッケージはHaskellのQuickCheckライブラリをPureScriptにポーティングしたもので、型や構文はもとのライブラリとほとんど同じようになっています。 +`quickcheck`を使って簡単なライブラリをテストし、Spagoでテストスイートを自動化されたビルドに統合する方法を見ていきます。 + +## プロジェクトの準備 + +この章のプロジェクトには依存関係として `quickcheck`が追加されます。 + +Spagoプロジェクトでは、テストソースは `test`ディレクトリに置かれ、テストスイートのメインモジュールは +`Test.Main`と名づけられます。 テストスイートは、 `spago test`コマンドを使用して実行できます。 + +## 性質を書く + +`Merge`モジュールでは簡単な関数 `merge`が実装されています。 +これを`quickcheck`ライブラリの機能を実演するために使っていきます。 + +```haskell +merge :: Array Int -> Array Int -> Array Int +``` + +`merge`は2つの整列された整数の配列を取って、結果が整列されるように要素を統合します。 +例えば次のようになります。 + +```text +> import Merge +> merge [1, 3, 5] [2, 4, 5] + +[1, 2, 3, 4, 5, 5] +``` + +典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成し、結果が正しい値と等しいことを確認することでテストを実施します。 +しかし、`merge`関数について知る必要があるものは全て、この性質に要約できます。 + +- `xs`と`ys`が整列済みなら、`merge xs ys`は両方の配列が一緒に結合されて整列された結果になります。 + +`quickcheck`では、無作為なテスト項目を生成することで、直接この性質をテストできます。 +コードが持つべき性質を関数として述べるだけです。 +この場合は1つの性質があります。 + +```haskell +main = do + quickCheck \xs ys -> + eq (merge (sort xs) (sort ys)) (sort $ xs <> ys) +``` + +このコードを実行すると、`quickcheck`は無作為な入力`xs`と`ys`を生成してこの関数に渡すことで、主張した性質を反証しようとします。 +何らかの入力に対して関数が`false`を返した場合、性質は正しくなく、ライブラリはエラーを発生させます。 +幸いなことに、次のように100個の無作為なテスト項目を生成しても、ライブラリはこの性質を反証できません。 + +```text +$ spago test + +Installation complete. +Build succeeded. +100/100 test(s) passed. +... +Tests succeeded. +``` + +もし +`merge`関数に意図的にバグを混入した場合(例えば、大なりのチェックを小なりのチェックへと変更するなど)、最初に失敗したテスト項目の後で例外が実行時に投げられます。 + +```text +Error: Test 1 failed: +Test returned false +``` + +見ての通りこのエラー文言ではあまり役に立ちませんが、少し工夫するだけで改良できます。 + +## エラー文言の改善 + +テスト項目が失敗した時に同時にエラー文言を提供する上で、`quickcheck`は``演算子を提供しています。 +次のように性質の定義とエラー文言を``で区切って書くだけです。 + +```haskell +quickCheck \xs ys -> + let + result = merge (sort xs) (sort ys) + expected = sort $ xs <> ys + in + eq result expected "Result:\n" <> show result <> "\nnot equal to expected:\n" <> show expected +``` + +このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗したときに改良されたエラー文言が表示されます。 + +```text +Error: Test 1 (seed 534161891) failed: +Result: +[-822215,-196136,-116841,618343,887447,-888285] +not equal to expected: +[-888285,-822215,-196136,-116841,618343,887447] +``` + +入力 `xs`が無作為に選ばれた数の配列として生成されていることに注目してください。 + +## 演習 + + 1. (簡単)配列に空の配列を統合しても元の配列は変更されないことを確かめる性質を書いてください。 + *補足*:この新しい性質は冗長です。 + というのもこの状況は既に既存の性質で押さえられているからです。 + ここでは読者がQuickCheckを使う練習のための簡単なやり方を示そうとしているだけです。 + 1. (簡単)`merge`の残りの性質に対して、適切なエラー文言を追加してください。 + +## 多相的なコードのテスト + +`Merge`モジュールでは、数の配列だけでなく、 `Ord`型クラスに属するどんな型の配列に対しても動作する、 `merge`関数を一般化した +`mergePoly`という関数が定義されています。 + +```haskell +mergePoly :: forall a. Ord a => Array a -> Array a -> Array a +``` + +`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエラー文言が表示されます。 + +```text +No type class instance was found for + + Test.QuickCheck.Arbitrary.Arbitrary t0 + +The instance head contains unknown type variables. +Consider adding a type annotation. +``` + +このエラー文言は、配列に持たせたい要素の型が何なのかわからないので、コンパイラが無作為なテスト項目を生成できなかったということを示しています。 +このような場合、型註釈を使ってコンパイラが特定の型を推論するように強制できます。 +例えば`Array Int`などです。 + +```haskell +quickCheck \xs ys -> + eq (mergePoly (sort xs) (sort ys) :: Array Int) (sort $ xs <> ys) +``` + +代替案として型を指定する補助関数を使うこともできます。 +こうするとより見通しのよいコードになることがあります。 +例えば同値関数の同義語として関数`ints`を定義したとしましょう。 + +```haskell +ints :: Array Int -> Array Int +ints = id +``` + +それから、コンパイラが引数の2つの配列の型 `Array Int`を推論するように、テストを変更します。 + +```haskell +quickCheck \xs ys -> + eq (ints $ mergePoly (sort xs) (sort ys)) (sort $ xs <> ys) +``` + +ここで、`ints`関数が不明な型の曖昧さを解消するために使われているため、`xs`と`ys`は型`Array Int`を持っています。 + +## 演習 + + 1. (簡単)`xs`と`ys`の型を`Array + Boolean`に強制する関数`bools`を書き、`mergePoly`をその型でテストする性質を追加してください。 + 1. (普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエラー文言を含めてQuickCheckの性質を書いてください。 + その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定しなければいけません。 + +## 任意のデータの生成 + +それでは`quickcheck`ライブラリが性質に対するテスト項目をどのように無作為に生成できているのかを見ていきます。 + +無作為に値を生成できるような型は、次のような型クラス `Arbitary`のインスタンスを持っています。 + +```haskell +class Arbitrary t where + arbitrary :: Gen t +``` + +`Gen`型構築子は*決定的無作為データ生成*の副作用を表しています。 +決定的無作為データ生成は、擬似乱数生成器を使って、シード値から決定的無作為関数の引数を生成します。 +`Test.QuickCheck.Gen`モジュールは、生成器を構築するための幾つかの有用なコンビネータを定義しています。 + +`Gen`はモナドでもアプリカティブ関手でもあるので、 +`Arbitary`型クラスの新しいインスタンスを作成するのに、いつも使っているようなコンビネータを自由に使うことができます。 + +例えば、`quickcheck`ライブラリで提供されている`Int`型用の`Arbitrary`インスタンスを使い、256個のバイト値上の分布を作れます。 +これには`Gen`用の`Functor`インスタンスを使い、整数からバイトへの関数を任意の整数値に写します。 + +```haskell +newtype Byte = Byte Int + +instance Arbitrary Byte where + arbitrary = map intToByte arbitrary + where + intToByte n | n >= 0 = Byte (n `mod` 256) + | otherwise = intToByte (-n) +``` + +ここでは、0から255までの間の整数値であるような型`Byte`を定義しています。 +`Arbitrary`インスタンスは`map`演算子を使って、`intToByte`関数を`arbitrary`動作まで持ち上げています。 +`arbitrary`動作内部の型は`Gen Int`と推論されます。 + +この考え方を `merge`用のテストに使うこともできます。 + +```haskell +quickCheck \xs ys -> + eq (numbers $ mergePoly (sort xs) (sort ys)) (sort $ xs <> ys) +``` + +このテストでは、任意の配列`xs`と`ys`を生成しますが、`merge`は整列済みの入力を期待しているので、これらを整列しておかなければなりません。 +一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する`Arbitrary`インスタンスを書くこともできます。 + +```haskell +newtype Sorted a = Sorted (Array a) + +sorted :: forall a. Sorted a -> Array a +sorted (Sorted xs) = xs + +instance (Arbitrary a, Ord a) => Arbitrary (Sorted a) where + arbitrary = map (Sorted <<< sort) arbitrary +``` + +この型構築子を使うと、テストを次のように変更できます。 + +```haskell +quickCheck \xs ys -> + eq (ints $ mergePoly (sorted xs) (sorted ys)) (sort $ sorted xs <> sorted ys) +``` + +これは些細な変更に見えるかもしれませんが、`xs`と`ys`の型はただの`Array Int`から`Sorted Int`へと変更されています。 +これにより、`mergePoly`関数は整列済みの入力を取る、という*意図*をわかりやすく示すことができます。 +理想的には、`mergePoly`関数自体の型が`Sorted`型構築子を使うようにするといいでしょう。 + +より興味深い例として、 `Tree`モジュールでは枝の値で整列された二分木の型が定義されています。 + +```haskell +data Tree a + = Leaf + | Branch (Tree a) a (Tree a) +``` + +`Tree`モジュールでは次のAPIが定義されています。 + +```haskell +insert :: forall a. Ord a => a -> Tree a -> Tree a +member :: forall a. Ord a => a -> Tree a -> Boolean +fromArray :: forall a. Ord a => Array a -> Tree a +toArray :: forall a. Tree a -> Array a +``` + +`insert`関数は新しい要素を整列済みの木に挿入し、`member`関数は特定の値について木に問い合わせます。 +例えば次のようになります。 + +```text +> import Tree + +> member 2 $ insert 1 $ insert 2 Leaf +true + +> member 1 Leaf +false +``` + +`toArray`関数と`fromArray`関数は、整列された木と配列を相互に変換できます。 +`fromArray`を使うと、木についての`Arbitrary`インスタンスを書けます。 + +```haskell +instance (Arbitrary a, Ord a) => Arbitrary (Tree a) where + arbitrary = map fromArray arbitrary +``` + +型`a`用に使える`Arbitary`インスタンスがあるなら、テストする性質の引数の型として`Tree a`を使えます。 +例えば、`member`による木の確認については、値を挿入した後は常に`true`を返すことをテストできます。 + +```haskell +quickCheck \t a -> + member a $ insert a $ treeOfInt t +``` + +ここでは、引数 `t`は `Tree Number`型の無作為に生成された木です。 +型引数は、同値関数 `treeOfInt`によって明確にされています。 + +## 演習 + + 1. (普通)`a-z`の範囲から無作為に選ばれた文字の集まりを生成する + `Arbitrary`インスタンスを持つ、`String`のnewtypeを作ってください。 + *手掛かり*:`Test.QuickCheck.Gen`モジュールから `elements`と `arrayOf`関数を使います。 + 1. (難しい)木に挿入された値は、どれだけ沢山の挿入があった後でも、その木の構成要素であることを主張する性質を書いてください。 + +## 高階関数のテスト + +`Merge`モジュールは`merge`関数の別の一般化も定義しています。 +`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を判定します。 +つまり`mergeWith`は高階関数です。 + +例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列を統合できます。 +その結果もまた長さの昇順になっているでしょう。 + +```haskell +> import Data.String + +> mergeWith length + ["", "ab", "abcd"] + ["x", "xyz"] + +["","x","ab","xyz","abcd"] +``` + +このような関数をテストするにはどうしたらいいでしょうか。 +理想的には、関数である最初の引数を含めた3つの引数全てについて、値を生成したいところです。 + +無作為に生成された関数を作れるようにする、2つ目の型クラスがあります。 +`Coarbitrary`という名前で次のように定義されています。 + +```haskell +class Coarbitrary t where + coarbitrary :: forall r. t -> Gen r -> Gen r +``` + +`coarbitrary`関数は、型`t`の関数の引数と、型`r`の関数の結果の乱数生成器を取ります。 +この関数引数を使って乱数生成器を*かき乱し*ます。 +つまり、関数の引数を使って乱数生成器の無作為な出力を変更し、結果としているのです。 + +また、もし関数の定義域が`Coarbitrary`で値域が`Arbitrary`なら、`Arbitrary`の関数を与える型クラスインスタンスが存在します。 + +```haskell +instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b) +``` + +実際のところ、引数として関数を取るような性質を記述できます。 +`mergeWith`関数の場合では、新しい引数を考慮するようにテストを修正すると、最初の引数を無作為に生成できます。 + +結果が整列されていることは保証できません。 +`Ord`インスタンスを持っているとさえ限らないのです。 +しかし、引数として渡す関数`f`に従って結果が整列されていることは期待されます。 +更に、2つの入力配列が`f`に従って整列されている必要がありますので、`sortBy`関数を使って関数`f`が適用されたあとの比較に基づいて`xs`と`ys`を整列します。 + +```haskell +quickCheck \xs ys f -> + let + result = + map f $ + mergeWith (intToBool f) + (sortBy (compare `on` f) xs) + (sortBy (compare `on` f) ys) + expected = + map f $ + sortBy (compare `on` f) $ xs <> ys + in + eq result expected +``` + +ここでは、関数 `f`の型を明確にするために、関数 `intToBool`を使用しています。 + +```haskell +intToBool :: (Int -> Boolean) -> Int -> Boolean +intToBool = id +``` + +関数は `Arbitrary`であるだけでなく `Coarbitrary`でもあります。 + +```haskell +instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b) +``` + +つまり値や関数だけに制限されません。 +*高階関数*や、引数が高階関数であるような関数やその他諸々もまた、無作為に生成できるのです。 + +## Coarbitraryのインスタンスを書く + +`Gen`の `Monad`や `Applicative`インスタンスを使って独自のデータ型に対して +`Arbitrary`インスタンスを書くことができるのとちょうど同じように、独自の `Coarbitrary`インスタンスを書くこともできます。 +これにより、無作為に生成される関数の定義域として、独自のデータ型を使うことができるようになります。 + +`Tree`型の `Coarbitrary`インスタンスを書いてみましょう。 +枝に格納されている要素の型に `Coarbitrary`インスタンスが必要になります。 + +```haskell +instance Coarbitrary a => Coarbitrary (Tree a) where +``` + +型`Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があります。 +入力値が`Leaf`であれば、そのままにしておく生成器を返します。 + +```haskell + coarbitrary Leaf = id +``` + +もし木が `Branch`なら、左の部分木、値、右の部分木を使って生成器をかき乱します。 +関数合成を使って独自のかき乱し関数を作ります。 + +```haskell + coarbitrary (Branch l a r) = + coarbitrary l <<< + coarbitrary a <<< + coarbitrary r +``` + +これで、木を引数にとるような関数を引数に含む性質を自由に書くことができるようになりました。 +例えば`Tree`モジュールでは関数`anywhere`が定義されています。 +これは述語が引数のどんな部分木についても満たされるかを調べます。 + +```haskell +anywhere :: forall a. (Tree a -> Boolean) -> Tree a -> Boolean +``` + +今となっては述語関数を無作為に生成できます。 +例えば、`anywhere`関数は*選言の法則を満たす*ことが期待されます。 + +```haskell +quickCheck \f g t -> + anywhere (\s -> f s || g s) t == + anywhere f (treeOfInt t) || anywhere g t +``` + +ここで、 `treeOfInt`関数は木に含まれる値の型を型 `Int`に固定するために使われています。 + +```haskell +treeOfInt :: Tree Int -> Tree Int +treeOfInt = id +``` + +## 副作用のないテスト + +通常、テストの目的ではテストスイートの`main`動作に`quickCheck`関数の呼び出しが含まれています。 +しかし`quickCheck`関数には亜種があり、`quickCheckPure`という名前です。 +副作用を使わない代わりに、入力として乱数の種を取ってテスト結果の配列を返す純粋な関数です。 + +PSCiを使用して `quickCheckPure`を試せます。 +ここでは `merge`操作が結合法則を満たすことをテストします。 + +```text +> import Prelude +> import Merge +> import Test.QuickCheck +> import Test.QuickCheck.LCG (mkSeed) + +> :paste +… quickCheckPure (mkSeed 12345) 10 \xs ys zs -> +… ((xs `merge` ys) `merge` zs) == +… (xs `merge` (ys `merge` zs)) +… ^D + +Success : Success : ... +``` + +`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を取ります。 +もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出力されます。 + +`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションのフォームデータ例を無作為に生成するというような状況で便利かもしれません。 + +## 演習 + + 1. (簡単)`Byte`と `Sorted`型構築子についての `Coarbitrary`インスタンスを書いてください。 + 1. (普通)任意の関数 `f`について、 `mergeWith f`関数の結合性を主張する(高階)性質を書いてください。 + `quickCheckPure`を使ってPSCiでその性質をテストしてください。 + 1. (普通)次のデータ型の`Arbitrary`と`Coarbitrary`インスタンスを書いてください。 + + ```haskell + data OneTwoThree a = One a | Two a a | Three a a a + ``` + + *手掛かり*:`Test.QuickCheck.Gen`で定義された`oneOf`関数を使って`Arbitrary`インスタンスを定義してください。 + 1. (普通)`all`を使って`quickCheckPure`関数の結果を単純化してください。 + この新しい関数は型`List Result -> Boolean`を持ち、全てのテストが通れば`true`を、そうでなければ`false`を返します。 + 2. (普通)`quickCheckPure`の結果を単純にする別の手法として、関数`squashResults :: List Result -> Result`を書いてみてください。 + `Data.Maybe.First`の`First`モノイドと共に`foldMap`関数を使うことで、失敗した場合の最初のエラーを保持することを検討してください。 + +## まとめ + +この章では`quickcheck`パッケージに出会いました。 +これを使うと*生成的テスティング*のパラダイムを使って、宣言的な方法でテストを書くことができました。具体的には以下です。 + +- `spago test`を使ってQuickCheckのテストを自動化する方法を見ました。 +- 性質を関数として書く方法とエラー文言を改良する``演算子の使い方を説明しました。 +- `Arbitrary`と`Coarbitrary`型クラスによって定型的なテストコードの自動生成を可能にする方法や、高階な性質のテストを可能にする方法を見ました。 +- 独自のデータ型に対して `Arbitrary`と `Coarbitrary`インスタンスを実装する方法を見ました。 diff --git a/text-ja/chapter6.md b/text-ja/chapter6.md index 4ed2f1d2..bb69e9a9 100644 --- a/text-ja/chapter6.md +++ b/text-ja/chapter6.md @@ -39,7 +39,7 @@ class Show a where show :: a -> String ``` -このコードでは、型変数 `a`でパラメータ化された、`Show`という新しい _型クラス_ (type class) を宣言しています。 +このコードでは、型変数`a`を引数に取る`Show`という新しい*型クラス*を宣言しています。 型クラス _インスタンス_ には、型クラスで定義された関数の、その型に特殊化された実装が含まれています。 diff --git a/text-ja/chapter7.md b/text-ja/chapter7.md index 65f6d08e..daaac50a 100644 --- a/text-ja/chapter7.md +++ b/text-ja/chapter7.md @@ -256,7 +256,7 @@ a`の式を見つけたなら、その式はそのより大きな言語だけに Freeman, Phillip A ``` -この関数が、クエリパラメータとして与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装を形成しているとしましょう。 +この関数が、クエリ引数として与えられた3つの引数を持つ、(とっても簡単な)webサービスの実装を形成しているとしましょう。 使用者が3つの各引数を与えたことを確かめたいので、引数が存在するかどうかを表す`Maybe`型を使うことになるでしょう。 `fullName`を`Maybe`の上へ持ち上げると、欠けている引数を検査するwebサービスの実装を作成できます。 diff --git a/translation/ja.po b/translation/ja.po index 82946aa5..13a54ffc 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-22 08:54+0900\n" +"PO-Revision-Date: 2023-08-24 22:41+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -10116,10 +10116,6 @@ msgstr "merge :: Array Int -> Array Int -> Array Int\n" #. type: Plain text #: text/chapter13.md:24 -#, fuzzy -#| msgid "" -#| "`merge` takes two sorted arrays of integers, and merges their elements so " -#| "that the result is also sorted. For example:" msgid "" "`merge` takes two sorted arrays of integers and merges their elements so " "that the result is also sorted. For example:" @@ -10144,22 +10140,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:33 -#, fuzzy -#| 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 the appropriate values. However, everything we need to know about the " -#| "`merge` function can be summarized by this property:" 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 " "the appropriate values. However, everything we need to know about the " "`merge` function can be summarized by this property:" msgstr "" -"典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成" -"し、結果が正しい値と等しいことを確認することでテストを実施します。\n" -"しかし、 `merge`関数について知る必要があるものは全て、この性質に要約できま" -"す。" +"典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成し、結果が正しい値と等しいことを確認することでテストを実施します。\n" +"しかし、`merge`関数について知る必要があるものは全て、この性質に要約できます。" #. type: Bullet: '- ' #: text/chapter13.md:35 @@ -10172,11 +10160,6 @@ msgstr "" #. type: Plain text #: text/chapter13.md:37 -#, fuzzy -#| 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:" msgid "" "`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. " @@ -10201,14 +10184,6 @@ msgstr "" #. type: Plain text #: text/chapter13.md:45 -#, fuzzy -#| 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:" 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 " @@ -10216,12 +10191,9 @@ msgid "" "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個の無作為なテスト項目を生成しても、ライブラリはこ" -"の性質を反証できません。" +"このコードを実行すると、`quickcheck`は無作為な入力`xs`と`ys`を生成してこの関数に渡すことで、主張した性質を反証しようとします。\n" +"何らかの入力に対して関数が`false`を返した場合、性質は正しくなく、ライブラリはエラーを発生させます。\n" +"幸いなことに、次のように100個の無作為なテスト項目を生成しても、ライブラリはこの性質を反証できません。" #. type: Fenced code block (text) #: text/chapter13.md:46 @@ -10337,13 +10309,6 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter13.md:94 -#, fuzzy -#| 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." msgid "" "(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 " @@ -10414,7 +10379,6 @@ msgstr "" #. type: Plain text #: text/chapter13.md:115 -#, fuzzy 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 " @@ -10437,11 +10401,6 @@ msgstr "" #. type: Plain text #: text/chapter13.md:122 -#, fuzzy -#| 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:" msgid "" "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 " @@ -10449,7 +10408,7 @@ msgid "" msgstr "" "代替案として型を指定する補助関数を使うこともできます。\n" "こうするとより見通しのよいコードになることがあります。\n" -"例えば同値関数の同義な関数`ints`を定義したとしましょう。" +"例えば同値関数の同義語として関数`ints`を定義したとしましょう。" #. type: Fenced code block (haskell) #: text/chapter13.md:123 @@ -10482,31 +10441,18 @@ msgstr "" #. type: Plain text #: text/chapter13.md:136 -#, fuzzy -#| msgid "" -#| "Here, `xs` and `ys` both have type `Array Int`, since the `ints` function " -#| "has been used to disambiguate the unknown type." msgid "" "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`を持っています。" +msgstr "ここで、`ints`関数が不明な型の曖昧さを解消するために使われているため、`xs`と`ys`は型`Array Int`を持っています。" #. type: Bullet: ' 1. ' #: text/chapter13.md:141 -#, fuzzy -#| 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." msgid "" "(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`を書き、 " -"`mergePoly`をその型でテストする性質を追加してください。" +msgstr "(簡単)`xs`と`ys`の型を`Array Boolean`に強制する関数`bools`を書き、`mergePoly`をその型でテストする性質を追加してください。" #. type: Bullet: ' 1. ' #: text/chapter13.md:141 @@ -10527,16 +10473,10 @@ msgstr "任意のデータの生成" #. type: Plain text #: text/chapter13.md:145 -#, fuzzy -#| msgid "" -#| "Now we will see how the `quickcheck` library is able to randomly generate " -#| "test cases for our properties." msgid "" "Now we will see how the `quickcheck` library can randomly generate test " "cases for our properties." -msgstr "" -"`quickcheck`ライブラリを使って性質に対するテスト項目を無作為に生成する方法に" -"ついて説明します。" +msgstr "それでは`quickcheck`ライブラリが性質に対するテスト項目をどのように無作為に生成できているのかを見ていきます。" #. type: Plain text #: text/chapter13.md:147 @@ -10585,22 +10525,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:158 -#, fuzzy -#| 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:" 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:" msgstr "" -"例えば、 `quickcheck`ライブラリで提供されている `Int`型用の `Arbitrary`インス" -"タンスを使い、256個のバイト値上の分布を作ることができます。\n" -"これには`Gen`用に`Functor`インスタンスを使って整数から任意の整数値のバイトま" -"でマップします。" +"例えば、`quickcheck`ライブラリで提供されている`Int`型用の`Arbitrary`インスタンスを使い、256個のバイト値上の分布を作れます。\n" +"これには`Gen`用の`Functor`インスタンスを使い、整数からバイトへの関数を任意の整数値に写します。" #. type: Fenced code block (haskell) #: text/chapter13.md:159 @@ -10651,22 +10583,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:179 -#, fuzzy -#| 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:" 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 that " "generates sorted data:" msgstr "" -"このテストでは、任意の配列 `xs`と `ys`を生成しますが、 `merge`は整列済みの入" -"力を期待しているので、 `xs`と `ys`を整列しておかなければなりません。\n" -"一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する " -"`Arbitrary`インスタンスを書くこともできます。" +"このテストでは、任意の配列`xs`と`ys`を生成しますが、`merge`は整列済みの入力を期待しているので、これらを整列しておかなければなりません。\n" +"一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する`Arbitrary`インスタンスを書くこともできます。" #. type: Fenced code block (haskell) #: text/chapter13.md:180 @@ -10705,13 +10629,6 @@ msgstr "" #. type: Plain text #: text/chapter13.md:198 -#, fuzzy -#| 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. Ideally, the type of the `mergePoly` function itself would be " -#| "updated to use the `Sorted` type constructor." 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 " @@ -10719,12 +10636,9 @@ msgid "" "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 @@ -10768,17 +10682,11 @@ msgstr "" #. type: Plain text #: text/chapter13.md:217 -#, fuzzy -#| 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:" msgid "" "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) @@ -10803,19 +10711,12 @@ msgstr "" #. type: Plain text #: text/chapter13.md:229 -#, fuzzy -#| 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:" msgid "" "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 @@ -10829,21 +10730,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:236 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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 @@ -10879,17 +10773,10 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter13.md:248 -#, fuzzy -#| msgid "" -#| "(Difficult) Write a property which asserts that a value inserted into a " -#| "tree is still a member of that tree after arbitrarily many more " -#| "insertions." msgid "" "(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 "" -"(難しい)木に挿入された値は、どれだけ挿入があった後でも、その木の構成要素で" -"あることを主張する性質を書いてください。" +msgstr "(難しい)木に挿入された値は、どれだけ沢山の挿入があった後でも、その木の構成要素であることを主張する性質を書いてください。" #. type: Title ## #: text/chapter13.md:249 @@ -10899,38 +10786,25 @@ msgstr "高階関数のテスト" #. type: Plain text #: text/chapter13.md:252 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| 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:" msgid "" "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" -"このとき、結果も長さの昇順になっていなければなりません。" +"例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列を統合できます。\n" +"その結果もまた長さの昇順になっているでしょう。" #. type: Fenced code block (haskell) #: text/chapter13.md:255 @@ -10954,31 +10828,21 @@ msgstr "" #. type: Plain text #: text/chapter13.md:266 -#, fuzzy -#| 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." 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." msgstr "" "このような関数をテストするにはどうしたらいいでしょうか。\n" -"理想的には、関数である最初の引数を含めた、3つの引数全てについて、値を生成した" -"いと思うでしょう。" +"理想的には、関数である最初の引数を含めた3つの引数全てについて、値を生成したいところです。" #. type: Plain text #: text/chapter13.md:268 -#, fuzzy -#| msgid "" -#| "There is a second type class which allows us to create randomly-generated " -#| "functions. It is called `Coarbitrary`, and it is defined as follows:" msgid "" "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 @@ -10992,30 +10856,23 @@ msgstr "" #. type: Plain text #: text/chapter13.md:275 -#, fuzzy msgid "" "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`についての乱数生成器を関数の引数として取り、乱数生成器を*かき乱す*のにこの引数を使います。\n" -"つまり関数の引数を使って、乱数生成器の無作為な出力を変更しているのです。" +"`coarbitrary`関数は、型`t`の関数の引数と、型`r`の関数の結果の乱数生成器を取ります。\n" +"この関数引数を使って乱数生成器を*かき乱し*ます。\n" +"つまり、関数の引数を使って乱数生成器の無作為な出力を変更し、結果としているのです。" #. type: Plain text #: text/chapter13.md:277 -#, fuzzy -#| msgid "" -#| "In addition, there is a type class instance which gives us `Arbitrary` " -#| "functions if the function domain is `Coarbitrary` and the function " -#| "codomain is `Arbitrary`:" msgid "" "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`" -"の関数を与える型クラスインスタンスが存在します。" +msgstr "また、もし関数の定義域が`Coarbitrary`で値域が`Arbitrary`なら、`Arbitrary`の関数を与える型クラスインスタンスが存在します。" #. type: Fenced code block (haskell) #: text/chapter13.md:278 @@ -11025,31 +10882,16 @@ msgstr "instance (Coarbitrary a, Arbitrary b) => Arbitrary (a -> b)\n" #. type: Plain text #: text/chapter13.md:283 -#, fuzzy -#| 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." msgid "" "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 -#, fuzzy -#| 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 " -#| "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 the function `f` has been applied:" 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 " @@ -11059,11 +10901,9 @@ msgid "" "the function `f` has been applied:" msgstr "" "結果が整列されていることは保証できません。\n" -"必ずしも`Ord`インスタンスを持っているとさえ限らないのです。\n" -"しかし、引数として渡す関数 `f`に従って結果が整列されていることは期待されま" -"す。\n" -"更に、2つの入力配列が `f`に従って整列されている必要がありますので、`sortBy`関" -"数を使って関数 `f`が適用されたあとの比較に基づいて `xs`と`ys`を整列します。" +"`Ord`インスタンスを持っているとさえ限らないのです。\n" +"しかし、引数として渡す関数`f`に従って結果が整列されていることは期待されます。\n" +"更に、2つの入力配列が`f`に従って整列されている必要がありますので、`sortBy`関数を使って関数`f`が適用されたあとの比較に基づいて`xs`と`ys`を整列します。" #. type: Fenced code block (haskell) #: text/chapter13.md:286 @@ -11126,20 +10966,13 @@ msgstr "instance (Arbitrary a, Coarbitrary b) => Coarbitrary (a -> b)\n" #. type: Plain text #: text/chapter13.md:315 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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 @@ -11178,19 +11011,13 @@ msgstr "instance Coarbitrary a => Coarbitrary (Tree a) where\n" #. type: Plain text #: text/chapter13.md:327 -#, fuzzy -#| 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:" msgid "" "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`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があ" -"ります。\n" -"入力値が `Leaf`であれば、そのままにしておく生成器を返します。" +"型`Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があります。\n" +"入力値が`Leaf`であれば、そのままにしておく生成器を返します。" #. type: Fenced code block (haskell) #: text/chapter13.md:328 @@ -11225,21 +11052,14 @@ msgstr "" #. type: Plain text #: text/chapter13.md:342 -#, fuzzy -#| 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:" msgid "" "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`が定義されており、これは述語が引数のどん" -"な部分木についても成り立っているかを調べる関数です。" +"これで、木を引数にとるような関数を引数に含む性質を自由に書くことができるようになりました。\n" +"例えば`Tree`モジュールでは関数`anywhere`が定義されています。\n" +"これは述語が引数のどんな部分木についても満たされるかを調べます。" #. type: Fenced code block (haskell) #: text/chapter13.md:343 @@ -11249,16 +11069,12 @@ msgstr "anywhere :: forall a. (Tree a -> Boolean) -> Tree a -> Boolean\n" #. type: Plain text #: text/chapter13.md:348 -#, fuzzy -#| msgid "" -#| "Now we are able to generate the predicate function randomly. For example, " -#| "we expect the `anywhere` function to _respect disjunction_:" msgid "" "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 @@ -11299,7 +11115,6 @@ msgstr "副作用のないテスト" #. type: Plain text #: text/chapter13.md:365 -#, fuzzy 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 " @@ -11308,8 +11123,8 @@ msgid "" "input and returns an array of test results." msgstr "" "通常、テストの目的ではテストスイートの`main`動作に`quickCheck`関数の呼び出しが含まれています。\n" -"しかし、副作用を使わない`quickCheckPure`と呼ばれる`quickCheck`関数の亜種もあります。\n" -"`quickCheckPure`は、入力として乱数の種を取り、テスト結果の配列を返す純粋な関数です。" +"しかし`quickCheck`関数には亜種があり、`quickCheckPure`という名前です。\n" +"副作用を使わない代わりに、入力として乱数の種を取ってテスト結果の配列を返す純粋な関数です。" #. type: Plain text #: text/chapter13.md:367 @@ -11362,18 +11177,11 @@ msgstr "" #. type: Plain text #: text/chapter13.md:386 -#, fuzzy -#| 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." msgid "" "`quickCheckPure` might be useful in other situations, such as generating " "random input data for performance benchmarks or sample form data for web " "applications." -msgstr "" -"`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションの" -"フォームデータ例を無作為に生成するというような状況で便利かもしれません。" +msgstr "`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションのフォームデータ例を無作為に生成するというような状況で便利かもしれません。" #. type: Bullet: ' 1. ' #: text/chapter13.md:392 @@ -11418,21 +11226,17 @@ msgstr "" #. type: Plain text #: text/chapter13.md:400 -#, fuzzy, 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) 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" +#, 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 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 @@ -11452,27 +11256,18 @@ msgstr "`spago test`を使ってQuickCheckのテストを自動化する方法 #. type: Bullet: '- ' #: text/chapter13.md:408 -#, fuzzy msgid "" "We saw how to write properties as functions and how to use the `` " "operator to improve error messages." -msgstr "性質を関数として書く方法とエラー文言を改良する ``演算子の使い方を説明しました。" +msgstr "性質を関数として書く方法とエラー文言を改良する``演算子の使い方を説明しました。" #. type: Bullet: '- ' #: text/chapter13.md:408 -#, fuzzy -#| 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 properties." 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 " "properties." -msgstr "" -"`Arbitrary`と `Coarbitrary`型クラスによって、如何にして定型的なテストコードの" -"自動生成を可能にし、またどうすれば高階な性質関数が可能になるかを見てきまし" -"た。" +msgstr "`Arbitrary`と`Coarbitrary`型クラスによって定型的なテストコードの自動生成を可能にする方法や、高階な性質のテストを可能にする方法を見ました。" #. type: Bullet: '- ' #: text/chapter13.md:408 From 3f02855ce4b101ef087f7fd12d137a323502415a Mon Sep 17 00:00:00 2001 From: gemmaro Date: Thu, 24 Aug 2023 23:43:59 +0900 Subject: [PATCH 19/29] [ update ] Guix manifest: remove mdBook depend --- manifest.scm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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)) From cd555b016454b18439455ae8cfc42de04a3c99df Mon Sep 17 00:00:00 2001 From: gemmaro Date: Thu, 24 Aug 2023 23:46:34 +0900 Subject: [PATCH 20/29] [ update ] chapter 14 translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ fix ] duplicate "、" * [ generate ] translation --- text-ja/chapter14.md | 828 +++++++++++++++++++++++++++++++++++++++++++ text-ja/chapter6.md | 2 +- translation/ja.po | 370 +++++-------------- 3 files changed, 911 insertions(+), 289 deletions(-) create mode 100644 text-ja/chapter14.md diff --git a/text-ja/chapter14.md b/text-ja/chapter14.md new file mode 100644 index 00000000..d8f13a6c --- /dev/null +++ b/text-ja/chapter14.md @@ -0,0 +1,828 @@ +# 領域特化言語 + +## この章の目標 + +この章では多数の標準的な手法を使い、PureScriptにおける*領域特化言語*(または*DSL*)の実装について探求していきます。 + +領域特化言語とは、特定の問題領域での開発に適した言語のことです。 +構文及び機能は、その領域内の考え方を表現するに使われるコードの読みやすさを最大化すべく選択されます。 +本書の中では、既に領域特化言語の例を幾つか見てきています。 + +- 第11章で開発された`Game`モナドと関連する動作は、*テキストアドベンチャーゲーム開発*という領域に対しての領域特化言語を構成しています。 +- 第13章で扱った`quickcheck`パッケージは、*生成的テスティング*の領域に向けた領域特化言語です。 + このコンビネータはテストの性質に対して特に表現力の高い記法を可能にします。 + +この章では、領域特化言語の実装において、幾つかの標準的な技法にについて構造的な手法を取ります。 +この話題の完全な解説では決してありませんが、目的に合う実践的なDSLを構築するのに充分な知識は得られるでしょう。 + +ここでの実行例はHTML文書を作成するための領域特化言語です。 +正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装を徐々に改善しつつ進めていきます。 + +## プロジェクトの準備 + +この章に付随するプロジェクトには新しい依存性が1つ追加されます。 +これから使う道具の1つである*Freeモナド*が定義されている`free`ライブラリです。 + +このプロジェクトをPSCiを使って試していきます。 + +## HTMLデータ型 + +このHTMLライブラリの最も基本的なバージョンは +`Data.DOM.Simple`モジュールで定義されています。このモジュールには次の型定義が含まれています。 + +```haskell +newtype Element = Element + { name :: String + , attribs :: Array Attribute + , content :: Maybe (Array Content) + } + +data Content + = TextContent String + | ElementContent Element + +newtype Attribute = Attribute + { key :: String + , value :: String + } +``` + +`Element`型はHTMLの要素を表します。 +各要素は要素名、属性の対の配列と、内容で構成されます。 +内容のプロパティには`Maybe`型を適切に使い、要素が開いている(他の要素やテキストを含む)か閉じているかを示します。 + +このライブラリの鍵となる機能は次の関数です。 + +```haskell +render :: Element -> String +``` + +この関数はHTML要素をHTML文字列として出力します。 +PSCiで明示的に適当な型の値を構築し、ライブラリのこのバージョンを試してみましょう。 + +```text +$ spago repl + +> import Prelude +> import Data.DOM.Simple +> import Data.Maybe +> import Effect.Console + +> :paste +… log $ render $ Element +… { name: "p" +… , attribs: [ +… Attribute +… { key: "class" +… , value: "main" +… } +… ] +… , content: Just [ +… TextContent "Hello World!" +… ] +… } +… ^D + +

Hello World!

+unit +``` + +現状のライブラリには幾つもの問題があります。 + +- HTML文書の作成に手が掛かります。 + 全ての新しい要素に少なくとも1つのレコードと1つのデータ構築子が必要です。 +- 無効な文書を表現できてしまいます。 + - 開発者が要素名の入力を間違えるかもしれません + - 開発者が属性を間違った要素に関連付けることができてしまいます + - 開いた要素が正しい場合に開発者が閉じた要素を使えてしまいます + +残りの章ではとある手法を用いてこれらの問題を解決し、このライブラリーをHTML文書を作成するために使える領域特化言語にしていきます。 + +## スマート構築子 + +最初に導入する手法は単純ですがとても効果的です。 +モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリストを使ってデータ構築子`Element`、`Content`、`Attribute`を隠蔽します。 +そして正しいことが分かっているデータを構築する、いわゆる*スマート構築子*だけをエクスポートします。 + +例を示しましょう。まず、HTML要素を作成するための便利な関数を提供します。 + +```haskell +element :: String -> Array Attribute -> Maybe (Array Content) -> Element +element name attribs content = Element + { name: name + , attribs: attribs + , content: content + } +``` + +次にHTML要素のためのスマート構築子を作成します。 +この要素は利用者が`element`関数を適用して作成できるようになってほしいものです。 + +```haskell +a :: Array Attribute -> Array Content -> Element +a attribs content = element "a" attribs (Just content) + +p :: Array Attribute -> Array Content -> Element +p attribs content = element "p" attribs (Just content) + +img :: Array Attribute -> Element +img attribs = element "img" attribs Nothing +``` + +最後に、正しいデータ構造だけが構築されることがわかっているこれらの関数をエクスポートするように、モジュールエクスポートリストを更新します。 + +```haskell +module Data.DOM.Smart + ( Element + , Attribute(..) + , Content(..) + + , a + , p + , img + + , render + ) where +``` + +モジュールエクスポートリストはモジュール名の直後の括弧内に書きます。 +各モジュールのエクスポートは次の3種類の何れかになります。 + +- 値(ないし関数)。その値の名前により指定されます。 +- 型クラス。クラス名により指定されます。 +- 型構築子とそれに紐付くデータ構築子。 + 型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定されます。 + +ここでは、`Element`の*型*をエクスポートしていますが、データ構築子はエクスポートしていません。 +もしデータ構築子をエクスポートすると、使用者が不正なHTML要素を構築できてしまいます。 + +`Attribute`と `Content`型についてはデータ構築子を全てエクスポートしています(エクスポートリストの記号 `..`で示されています)。 +すぐ後で、これらの型にもスマート構築子の手法を適用していきます。 + +既にライブラリに幾つもの大きな改良が加わっていることに注目です。 + +- 不正な名前を持つHTML要素は表現できません(勿論ライブラリが提供する要素名に制限されています)。 +- 閉じた要素は構築するときに内容を含められません。 + +`Content`型にとても簡単にこの手法を適用できます。 +単にエクスポートリストから`Content`型のデータ構築子を取り除き、次のスマート構築子を提供します。 + +```haskell +text :: String -> Content +text = TextContent + +elem :: Element -> Content +elem = ElementContent +``` + +`Attribute`型にも同じ手法を適用してみましょう。 +まず、属性のための汎用のスマート構築子を用意します。 +以下は最初の試行です。 + +```haskell +attribute :: String -> String -> Attribute +attribute key value = Attribute + { key: key + , value: value + } + +infix 4 attribute as := +``` + +この定義では元の`Element`型と同じ問題に直面しています。 +存在しなかったり、名前が間違って入力された属性を表現できます。 +この問題を解決するために、属性名を表すnewtypeを作成します。 + +```haskell +newtype AttributeKey = AttributeKey String +``` + +これを使えば演算子を次のように変更できます。 + +```haskell +attribute :: AttributeKey -> String -> Attribute +attribute (AttributeKey key) value = Attribute + { key: key + , value: value + } +``` + +`AttributeKey`データ構築子をエクスポートしなければ、明示的にエクスポートされた次のような関数を使う以外に、使用者が型 +`AttributeKey`の値を構築する方法はありません。 +以下に幾つかの例を示します。 + +```haskell +href :: AttributeKey +href = AttributeKey "href" + +_class :: AttributeKey +_class = AttributeKey "class" + +src :: AttributeKey +src = AttributeKey "src" + +width :: AttributeKey +width = AttributeKey "width" + +height :: AttributeKey +height = AttributeKey "height" +``` + +新しいモジュールの最終的なエクスポートリストは次のようになります。 +最早どのデータ構築子も直接エクスポートしていない点に注目です。 + +```haskell +module Data.DOM.Smart + ( Element + , Attribute + , Content + , AttributeKey + + , a + , p + , img + + , href + , _class + , src + , width + , height + + , attribute, (:=) + , text + , elem + + , render + ) where +``` + +PSCiでこの新しいモジュールを試してみると、既にコードの簡潔さにおいて大幅な向上が見て取れます。 + +```text +$ spago repl + +> import Prelude +> import Data.DOM.Smart +> import Effect.Console +> log $ render $ p [ _class := "main" ] [ text "Hello World!" ] + +

Hello World!

+unit +``` + +しかし、基盤をなすデータ表現は全く変更されなかったので、`render`関数を変更する必要はなかったことにも注目してください。 +これはスマート構築子による手法の利点のひとつです。 +外部APIの使用者によって認識される表現から、モジュールの内部データ表現を分離できるのです。 + +## 演習 + + 1. (簡単)`Data.DOM.Smart`モジュールで `render`を使った新しいHTML文書の作成を試してみましょう。 + 1. (普通)`checked`や`disabled`といったHTML属性は値を要求せず、*空の属性*として書き出せます。 + + ```html + + ``` + + 空の属性を扱えるように `Attribute`の表現を変更してください。 + 要素に空の属性を追加するための`attribute`または`:=`の代わりに使える関数を記述してください。 + +## 幻影型 + +次の手法の動機付けとして、以下のコードを考えます。 + +```text +> log $ render $ img + [ src := "cat.jpg" + , width := "foo" + , height := "bar" + ] + + +unit +``` + +ここでの問題は、 `width`属性と`height`属性に文字列値を提供しているということです。 +ここで与えることができるのはピクセル単位ないしパーセントの数値だけであるべきです。 + +`AttributeKey`型にいわゆる _幻影型_ (phantom type) 引数を導入すると、この問題を解決できます。 + +```haskell +newtype AttributeKey a = AttributeKey String +``` + +定義の右辺に対応する型 `a`の値が存在しないので、この型変数 `a`は*幻影型*と呼ばれています。 +この型 `a`はコンパイル時に追加の情報を提供するためだけに存在しています。 +型`AttributeKey +a`の任意の値は実行時には単なる文字列ですが、コンパイル時はその値の型により、このキーに関連する値で求められる型がわかります。 + +`attribute`関数の型を次のように変更すれば、`AttributeKey`の新しい形式を考慮するようにできます。 + +```haskell +attribute :: forall a. IsValue a => AttributeKey a -> a -> Attribute +attribute (AttributeKey key) value = Attribute + { key: key + , value: toValue value + } +``` + +ここで、幻影型の引数 `a`は、属性キーと属性値が照応する型を持っていることを確認するために使われます。 +使用者は `AttributeKey +a`の型の値を直接作成できないので(ライブラリで提供されている定数を介してのみ得られます)、全ての属性が構築により正しくなります。 + +なお、`IsValue`制約はキーに関連付けられた値の型が何であれその値を文字列に変換し、生成したHTML内に出力できることを保証します。 +`IsValue`型クラスは次のように定義されています。 + +```haskell +class IsValue a where + toValue :: a -> String +``` + +`String`と `Int`型についての型クラスインスタンスも提供しておきます。 + +```haskell +instance IsValue String where + toValue = id + +instance IsValue Int where + toValue = show +``` + +また、これらの型が新しい型変数を反映するように、 `AttributeKey`定数を更新しなければいけません。 + +```haskell +href :: AttributeKey String +href = AttributeKey "href" + +_class :: AttributeKey String +_class = AttributeKey "class" + +src :: AttributeKey String +src = AttributeKey "src" + +width :: AttributeKey Int +width = AttributeKey "width" + +height :: AttributeKey Int +height = AttributeKey "height" +``` + +これで、不正なHTML文書を表現することが不可能になっていることがわかります。 +また、`width`と `height`属性を表現するのに文字列ではなく数を使うことが強制されていることがわかります。 + +```text +> import Prelude +> import Data.DOM.Phantom +> import Effect.Console + +> :paste +… log $ render $ img +… [ src := "cat.jpg" +… , width := 100 +… , height := 200 +… ] +… ^D + + +unit +``` + +## 演習 + + 1. (簡単)ピクセルまたはパーセントの何れかの長さを表すデータ型を作成してください。 + その型について`IsValue`のインスタンスを書いてください。 + この新しい型を使うように`width`と`height`属性を変更してください。 + 1. (難しい)真偽値`true`、`false`用の最上位の表現を定義することで、幻影型を使って`AttributeKey`が`disabled`や`checked`のような*空の属性*を表現しているかどうかをエンコードできます。 + + ```haskell + data True + data False + ``` + + 幻影型を使って、使用者が `attribute`演算子を空の属性に対して使うことを防ぐように、前の演習の解答を変更してください。 + +## Freeモナド + +APIに施す最後の変更では、`Content`型をモナドにしてdo記法を使えるようにするために、*Freeモナド*と呼ばれる構造を使っていきます。 +これによって入れ子になった要素がわかりやすくなるような形式でHTML文書を構造化できます。 +以下の代わりに…… + +```haskell +p [ _class := "main" ] + [ elem $ img + [ src := "cat.jpg" + , width := 100 + , height := 200 + ] + , text "A cat" + ] +``` + +このように書くことができるようになります。 + +```haskell +p [ _class := "main" ] $ do + elem $ img + [ src := "cat.jpg" + , width := 100 + , height := 200 + ] + text "A cat" +``` + +しかし、do記法だけがFreeモナドの恩恵ではありません。 +Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複数の解釈*を持たせることさえできます。 + +`Free`モナドは`free`ライブラリの`Control.Monad.Free`モジュールで定義されています。 +PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができます。 + +```text +> import Control.Monad.Free + +> :kind Free +(Type -> Type) -> Type -> Type +``` + +`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示しています。 +実はなんと、`Free`モナドを使えば任意の`Functor`を`Monad`にできるのです。 + +モナドの動作の*表現*の定義から始めます。 +これには対応したい各モナド動作について、1つのデータ構築子を持つ`Functor`を作成する必要があります。 +今回の場合、2つのモナドの動作は`elem`と`text`になります。 +`Content`型を次のように変更するだけでできます。 + +```haskell +data ContentF a + = TextContent String a + | ElementContent Element a + +instance Functor ContentF where + map f (TextContent s x) = TextContent s (f x) + map f (ElementContent e x) = ElementContent e (f x) +``` + +ここで、この`ContentF`型構築子は以前の`Content`データ型とよく似ています。 +しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引数として取るように変更されています。 +`Functor`インスタンスでは、単に各データ構築子で型`a`の値に関数`f`を適用します。 + +これにより、新しい`Content`モナドを`Free`モナド用の型シノニムとして定義できます。 +これは最初の型引数として `ContentF`型構築子を使うことで構築されます。 + +```haskell +type Content = Free ContentF +``` + +型同義語の代わりに`newtype`を使用して、使用者に対してライブラリの内部表現を露出することを避けられます。 +`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使用者に制限しています。 + +`ContentF`は `Functor`なので、 `Free ContentF`用の`Monad`インスタンスが自動的に手に入ります。 + +`Content`の新しい型引数を考慮するように`Element`データ型を僅かに変更する必要があります。 +モナドの計算の戻り値の型が `Unit`であることだけが必要です。 + +```haskell +newtype Element = Element + { name :: String + , attribs :: Array Attribute + , content :: Maybe (Content Unit) + } +``` + +また、`Content`モナドについての新しいモナドの動作になるよう、`elem`と`text`関数を変更する必要があります。 +これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えます。 +以下がその型です。 + +```haskell +liftF :: forall f a. f a -> Free f a +``` + +`liftF`により、何らかの型`a`について、型`f a`の値からFreeモナドの動作を構築できるようになります。 +今回の場合、`ContentF`型構築子のデータ構築子をそのまま使えます。 + +```haskell +text :: String -> Content Unit +text s = liftF $ TextContent s unit + +elem :: Element -> Content Unit +elem e = liftF $ ElementContent e unit +``` + +他にも同じようなコードの変更はありますが、興味深い変更は `render`関数にあります。ここでは、このFreeモナドを _解釈_ +しなければいけません。 + +## モナドの解釈 + +`Control.Monad.Free`モジュールでは、Freeモナドで計算を解釈するための多数の関数が提供されています。 + +```haskell +runFree + :: forall f a + . Functor f + => (f (Free f a) -> Free f a) + -> Free f a + -> a + +runFreeM + :: forall f m a + . (Functor f, MonadRec m) + => (f (Free f a) -> m (Free f a)) + -> Free f a + -> m a +``` + +`runFree`関数は、*純粋な*結果を計算するために使用されます。 +`runFreeM`関数があればFreeモナドの動作を解釈するためにモナドが使えます。 + +*補足*:厳密には、より強い`MonadRec`制約を満たすモナド`m`に制限されています。 +実際、ら`m`は安全な*末尾再帰モナド*に対応してため、スタックオーバーフローを心配する必要はありません。 + +まず、動作を解釈できるモナドを選ばなければなりません。 +`Writer String`モナドを使って、結果のHTML文字列を累算することにします。 + +新しい`render`メソッドが開始すると、補助関数 +`renderElement`に移譲し、`execWriter`を使って`Writer`モナドで計算します。 + +```haskell +render :: Element -> String +render = execWriter <<< renderElement +``` + +`renderElement`はwhereブロックで定義されます。 + +```haskell + where + renderElement :: Element -> Writer String Unit + renderElement (Element e) = do +``` + +`renderElement`の定義は直感的で、複数の小さな文字列を累算するために`Writer`モナドの`tell`動作を使っています。 + +```haskell + tell "<" + tell e.name + for_ e.attribs $ \x -> do + tell " " + renderAttribute x + renderContent e.content +``` + +次に、`renderAttribute`関数を定義します。 +こちらも同じくらい単純です。 + +```haskell + where + renderAttribute :: Attribute -> Writer String Unit + renderAttribute (Attribute x) = do + tell x.key + tell "=\"" + tell x.value + tell "\"" +``` + +`renderContent`関数は、もっと興味深いものです。 +ここでは`runFreeM`関数を使い、Freeモナドの内部で計算を解釈しています。 +計算は補助関数 `renderContentItem`に移譲しています。 + +```haskell + renderContent :: Maybe (Content Unit) -> Writer String Unit + renderContent Nothing = tell " />" + renderContent (Just content) = do + tell ">" + runFreeM renderContentItem content + tell "" +``` + +`renderContentItem`の型は `runFreeM`の型シグネチャから推測できます。 +関手 `f`は型構築子 `ContentF`で、モナド `m`は解釈している計算のモナド、つまり `Writer String`です。 +これにより `renderContentItem`は次の型シグネチャだとわかります。 + +```haskell + renderContentItem :: ContentF (Content Unit) -> Writer String (Content Unit) +``` + +`ContentF`の2つのデータ構築子でパターン照合すればこの関数を実装できます。 + +```haskell + renderContentItem (TextContent s rest) = do + tell s + pure rest + renderContentItem (ElementContent e rest) = do + renderElement e + pure rest +``` + +それぞれの場合において、式`rest`は型`Content Unit`を持っており、解釈された計算の残りを表しています。 +`rest`動作を返すことでそれぞれの場合を完成できます。 + +できました。 +PSCiで、次のようにすれば新しいモナドのAPIを試すことができます。 + +```text +> import Prelude +> import Data.DOM.Free +> import Effect.Console + +> :paste +… log $ render $ p [] $ do +… elem $ img [ src := "cat.jpg" ] +… text "A cat" +… ^D + +

A cat

+unit +``` + +## 演習 + + 1. (普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメントを出力する新しい動作`comment`に対応してください。 + `liftF`を使ってこの新しい動作を実装してください。 + 新しい構築子を適切に解釈するように、解釈`renderContentItem`を更新してください。 + +## 言語の拡張 + +全動作が型`Unit`の何かを返すようなモナドは、さほど興味深いものではありません。 +実際のところ、概ね良くなったと思われる構文は別として、このモナドは`Monoid`以上の機能を何ら追加していません。 + +非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナドを構築する威力をお見せしましょう。 + +*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を生成したいとします。 +手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めれば、これは達成できます。 +1つはアンカーの定義自身に、もう1つは各ハイパーリンクにあります。 +しかし、この手法には基本的な問題が幾つかあります。 + +- 開発者が一意なアンカー名の生成をし損なうかもしれません。 +- 開発者がアンカー名を1つ以上の箇所で打ち間違うかもしれません。 + +開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい一意な名前を生成するためのモナド動作を提供できます。 + +最初の工程は名前の型を新しく追加することです。 + +```haskell +newtype Name = Name String + +runName :: Name -> String +runName (Name n) = n +``` + +繰り返しになりますが、`Name`は +`String`のnewtypeとして定義しているものの、モジュールのエクスポートリスト内でデータ構築子をエクスポートしないように注意する必要があります。 + +次に、属性値に`Name`を使えるよう、新しい型に`IsValue`型クラスのインスタンスを定義します。 + +```haskell +instance IsValue Name where + toValue (Name n) = n +``` + +また、次のように `a`要素に現れるハイパーリンク用の新しいデータ型を定義します。 + +```haskell +data Href + = URLHref String + | AnchorHref Name + +instance IsValue Href where + toValue (URLHref url) = url + toValue (AnchorHref (Name nm)) = "#" <> nm +``` + +この新しい型により、`href`属性の型の値を変更して、利用者にこの新しい `Href`型の使用を強制できます。 +また、新しい`name`属性も作成でき、要素をアンカーに変換するのに使えます。 + +```haskell +href :: AttributeKey Href +href = AttributeKey "href" + +name :: AttributeKey Name +name = AttributeKey "name" +``` + +残っている問題は、現在モジュールの使用者が新しい名前を生成する方法がないということです。 +`Content`モナドでこの機能を提供できます。まず、 `ContentF`型構築子に新しいデータ構築子を追加する必要があります。 + +```haskell +data ContentF a + = TextContent String a + | ElementContent Element a + | NewName (Name -> a) +``` + +`NewName`データ構築子は型`Name`の値を返す動作に対応しています。 +データ構築子の引数として`Name`を要求するのではなく、型`Name -> a`の*関数*を提供するように使用者に要求していることに注意してください。 +型`a`は*計算の残り*を表していることを思い出すと、この関数は、型`Name`の値が返されたあとで、計算を継続する方法を提供しているのだとわかります。 + +新しいデータ構築子を考慮するよう、次のように`ContentF`用の`Functor`インスタンスを更新する必要もあります。 + +```haskell +instance Functor ContentF where + map f (TextContent s x) = TextContent s (f x) + map f (ElementContent e x) = ElementContent e (f x) + map f (NewName k) = NewName (f <<< k) +``` + +これで、以前と同じように`liftF`関数を使って新しい動作を構築できます。 + +```haskell +newName :: Content Name +newName = liftF $ NewName id +``` + +`id`関数を継続として提供していることに注意してください。 +つまり型`Name`の結果を変更せずに返しています。 + +最後に、新しい動作を解釈させるように解釈関数を更新する必要があります。 +以前は計算を解釈するために`Writer +String`モナドを使っていましたが、このモナドは新しい名前を生成できないので、何か他のものに切り替えなければなりません。 +`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせられます。 +型注釈が短く保たれるよう、この解釈モナドを型同義語として定義できます。 + +```haskell +type Interp = WriterT String (State Int) +``` + +ここで、`Int`型の状態は増加していくカウンタとして振舞い、一意な名前を生成するのに使われます。 + +`Writer`と`WriterT`モナドはそれらの動作を抽象化するのに同じ型クラスの構成要素を使うので、どの動作も変更する必要がありません。 +必要なのは、`Writer String`への参照全てを`Interp`で置き換えることだけです。 +しかし、計算に使われる制御子は変更する必要があります。 +単なる`execWriter`の代わりに、`evalState`も使う必要があります。 + +```haskell +render :: Element -> String +render e = evalState (execWriterT (renderElement e)) 0 +``` + +また、新しい `NewName`データ構築子を解釈するために、 `renderContentItem`に新しい場合を追加しなければいけません。 + +```haskell +renderContentItem (NewName k) = do + n <- get + let fresh = Name $ "name" <> show n + put $ n + 1 + pure (k fresh) +``` + +ここで、型 `Name -> Content a`の継続 `k`が与えられているので、型 `Content a`の解釈を構築しなければいけません。 +この解釈は単純です。 +`get`を使って状態を読み、その状態を使って一意な名前を生成し、それから `put`で状態に1だけ足すのです。 +最後に、継続にこの新しい名前を渡して、計算を完了します。 + +以上をもって、この新しい機能をPSCiで試せます。 +これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンクのリンク先の両方として使います。 + +```text +> import Prelude +> import Data.DOM.Name +> import Effect.Console + +> :paste +… render $ p [ ] $ do +… top <- newName +… elem $ a [ name := top ] $ +… text "Top" +… elem $ a [ href := AnchorHref top ] $ +… text "Back to top" +… ^D + +

TopBack to top

+unit +``` + +複数回の`newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめられます。 + +## 演習 + + 1. (普通)使用者から `Element`型を隠蔽すると、更にAPIを簡素にできます。 + 次の手順に従って、これらの変更を加えてください。 + - `p`や`img`のような(返る型が`Element`の)関数を`elem`動作と結合して、型`Content + Unit`を返す新しい動作を作ってください。 + - `Element`の代わりに型`Content Unit`の引数を受け付けるように`render`関数を変更してください。 + 1. (普通)型同義語の代わりに`newtype`を使って`Content`モナドの実装を隠してください。 + `newtype`用のデータ構築子はエクスポートすべきではありません。 + 1. (難しい)`ContentF`型を変更して以下の新しい動作に対応してください。 + + ```haskell + isMobile :: Content Boolean + ``` + + この動作は、この文書がモバイルデバイス上での表示のために描画されているかどうかを示す真偽値を返します。 + + *手掛かり*:`ask`動作と`ReaderT`モナド変換子を使って、この動作を解釈してください。 + あるいは、`RWS`モナドを使うほうが好みの人もいるかもしれません。 + +## まとめ + +この章では、幾つかの標準的な技術を使って、素朴な実装を段階的に改善することにより、HTML文書を作成するための領域特化言語を開発しました。 + +- *スマート構築子*を使ってデータ表現の詳細を隠し、利用者には*構築により正しい*文書だけを作ることを許しました。 +- *独自に定義された中置2引数演算子*を使い、言語の構文を改善しました。 +- *幻影型*を使ってデータの型の中に追加の情報を折り込みました。 + これにより利用者が誤った型の属性値を与えることを防いでいます。 +- *Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。 + それからこの表現を新しいモナド動作に対応するよう拡張し、標準的なモナド変換子を使ってモナドの計算を解釈しました。 + +これらの手法は全て、使用者が間違いを犯すのを防いだり領域特化言語の構文を改良したりするために、PureScriptのモジュールと型システムを活用しています。 + +関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野です。 +それでも、幾つかの単純な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言語で作業することの威力を示すことができていれば幸いです。 diff --git a/text-ja/chapter6.md b/text-ja/chapter6.md index bb69e9a9..35e23235 100644 --- a/text-ja/chapter6.md +++ b/text-ja/chapter6.md @@ -118,7 +118,7 @@ has type variables which are not mentioned in the body of the type. Consider add `Show`インスタンスが存在しないということではなく、PSCiがこの型を推論できなかったということです。 これは推論された型で*未知の型*`a`とされていることが示しています。 -`::`演算子を使って式に註釈を付け、、PSCiが正しい型クラスインスタンスを選べるようにできます。 +`::`演算子を使って式に註釈を付けてPSCiが正しい型クラスインスタンスを選べるようにできます。 ```text > show (Left 10 :: Either Int String) diff --git a/translation/ja.po b/translation/ja.po index 13a54ffc..b2e90af2 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-24 22:41+0900\n" +"PO-Revision-Date: 2023-08-25 08:38+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -11295,13 +11295,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:8 -#, fuzzy -#| msgid "" -#| "A domain-specific language is a language which 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:" msgid "" "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 " @@ -11309,8 +11302,7 @@ msgid "" "have already seen several examples of domain-specific languages in this book:" msgstr "" "領域特化言語とは、特定の問題領域での開発に適した言語のことです。\n" -"領域特化言語の構文及び機能は、その領域内の考え方を表現するコードの読みやすさ" -"を最大限に発揮すべく選択されます。\n" +"構文及び機能は、その領域内の考え方を表現するに使われるコードの読みやすさを最大化すべく選択されます。\n" "本書の中では、既に領域特化言語の例を幾つか見てきています。" #. type: Bullet: '- ' @@ -11323,63 +11315,44 @@ msgstr "第11章で開発された`Game`モナドと関連する動作は、*テ #. type: Bullet: '- ' #: text/chapter14.md:11 -#, fuzzy -#| msgid "" -#| "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." msgid "" "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 -#, fuzzy msgid "" "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 -#, fuzzy -#| 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 " -#| "correct HTML documents, and we will work by improving a naive " -#| "implementation in small steps." msgid "" "Our running example will be a domain-specific language for creating HTML " "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文書を記述するための型安全な言語を開発することが目的で、素朴な実装" -"を徐々に改善しつつ進めていきます。" +"ここでの実行例はHTML文書を作成するための領域特化言語です。\n" +"正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装を徐々に改善しつつ進めていきます。" #. type: Plain text #: text/chapter14.md:19 -#, fuzzy -#| 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." msgid "" "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 @@ -11388,8 +11361,7 @@ msgstr "このプロジェクトをPSCiを使って試していきます。" #. type: Title ## #: text/chapter14.md:22 -#, fuzzy, no-wrap -#| msgid "A HTML Data Type" +#, no-wrap msgid "An HTML Data Type" msgstr "HTMLデータ型" @@ -11438,22 +11410,15 @@ msgstr "" #. type: Plain text #: text/chapter14.md:44 -#, fuzzy -#| msgid "" -#| "The `Element` type represents HTML elements. Each element consists of an " -#| "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." msgid "" "The `Element` type represents HTML elements. Each element consists of an " "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 @@ -11538,7 +11503,6 @@ msgstr "現状のライブラリには幾つもの問題があります。" #. type: Bullet: '- ' #: text/chapter14.md:87 -#, fuzzy msgid "" "Creating HTML documents is difficult – every new element requires at least " "one record and one data constructor." @@ -11584,13 +11548,6 @@ msgstr "スマート構築子" #. type: Plain text #: text/chapter14.md:93 -#, fuzzy -#| 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." 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 " @@ -11598,11 +11555,9 @@ msgid "" "`Attribute` data constructors, and only export so-called _smart " "constructors_, which construct data known to be correct." msgstr "" -"最初に導入する手法は方法こそ単純なものですが、とても効果的です。\n" -"モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリ" -"ストを使ってデータ構築子 `Element`、 `Content`、 `Attribute`を隠蔽し、正しい" -"ことが明らかなデータだけ構築する、いわゆる*スマート構築子*だけをエクスポート" -"します。" +"最初に導入する手法は単純ですがとても効果的です。\n" +"モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリストを使ってデータ構築子`Element`、`Content`、`Attribute`を隠蔽します。\n" +"そして正しいことが分かっているデータを構築する、いわゆる*スマート構築子*だけをエクスポートします。" #. type: Plain text #: text/chapter14.md:95 @@ -11632,16 +11587,12 @@ msgstr "" #. type: Plain text #: text/chapter14.md:106 -#, fuzzy -#| msgid "" -#| "Next, we create smart constructors for those HTML elements we want our " -#| "users to be able to create, by applying the `element` function:" msgid "" "Next, we create smart constructors for those HTML elements we want our users " "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 @@ -11723,34 +11674,22 @@ msgstr "型クラス。クラス名により指定されます。" #. type: Bullet: '- ' #: text/chapter14.md:139 -#, fuzzy -#| msgid "" -#| "A type constructor and any associated data constructors, indicated by the " -#| "name of the type followed by a parenthesized list of exported data " -#| "constructors." msgid "" "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 -#, fuzzy -#| 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." msgid "" "Here, we export the `Element` _type_, but we do not export its data " "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 @@ -11782,19 +11721,13 @@ msgstr "閉じた要素は構築するときに内容を含められません。 #. type: Plain text #: text/chapter14.md:150 -#, fuzzy -#| 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, and provide the following smart constructors:" 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 " "and provide the following smart constructors:" msgstr "" "`Content`型にとても簡単にこの手法を適用できます。\n" -"単にエクスポートリストから `Content`型のデータ構築子を取り除き、次のスマート" -"構築子を提供します。" +"単にエクスポートリストから`Content`型のデータ構築子を取り除き、次のスマート構築子を提供します。" #. type: Fenced code block (haskell) #: text/chapter14.md:151 @@ -11844,20 +11777,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:172 -#, fuzzy -#| 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 names were entered incorrectly. To solve this problem, we " -#| "can create a newtype which represents attribute names:" msgid "" "This representation suffers from the same problem as the original `Element` " "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 that represents attribute names:" msgstr "" -"この定義では元の `Element`型と同じ問題に直面しています。\n" -"存在しなかったり、名前が間違っているような属性を表現できます。\n" +"この定義では元の`Element`型と同じ問題に直面しています。\n" +"存在しなかったり、名前が間違って入力された属性を表現できます。\n" "この問題を解決するために、属性名を表すnewtypeを作成します。" #. type: Fenced code block (haskell) @@ -12027,13 +11954,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:248 -#, fuzzy -#| 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." 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 " @@ -12041,11 +11961,9 @@ msgid "" "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 @@ -12058,16 +11976,10 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:253 -#, fuzzy -#| msgid "" -#| "(Medium) Some HTML attributes such as `checked` and `disabled` do not " -#| "require values, and may be rendered as _empty attributes_:" msgid "" "(Medium) Some HTML attributes, such as `checked` and `disabled`, do not " "require values and may be rendered as _empty attributes_:" -msgstr "" -"(普通)`checked`と `disabled`など、値を要求しないHTML属性がありますが、これ" -"らは次のような _空の属性_ として表示されるかもしれません。" +msgstr "(普通)`checked`や`disabled`といったHTML属性は値を要求せず、*空の属性*として書き出せます。" #. type: Plain text #: text/chapter14.md:257 @@ -12335,38 +12247,23 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:356 -#, fuzzy -#| 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." msgid "" "(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`属性を変更してください。" +"(簡単)ピクセルまたはパーセントの何れかの長さを表すデータ型を作成してください。\n" +"その型について`IsValue`のインスタンスを書いてください。\n" +"この新しい型を使うように`width`と`height`属性を変更してください。" #. type: Bullet: ' 1. ' #: text/chapter14.md:356 -#, fuzzy -#| 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 " -#| "`checked`." 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 " "`checked`." -msgstr "" -"(難しい)幻影型を使って真偽値 `true`、 `false`用の最上位の表現を定義すること" -"で、 `AttributeKey`が `disabled`や `checked`のような*空の属性*を表現している" -"かどうかをエンコードできます。" +msgstr "(難しい)真偽値`true`、`false`用の最上位の表現を定義することで、幻影型を使って`AttributeKey`が`disabled`や`checked`のような*空の属性*を表現しているかどうかをエンコードできます。" #. type: Plain text #: text/chapter14.md:361 @@ -12396,21 +12293,15 @@ msgstr "Freeモナド" #. type: Plain text #: text/chapter14.md:367 -#, fuzzy -#| 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:" 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:" msgstr "" -"APIに施す最後の変更は、 `Content`型をモナドにしてdo記法を使えるようにするため" -"に、 _Freeモナド_ と呼ばれる構造を使うことです。これによって入れ子になった要" -"素がわかりやすくなるようにHTML文書を構造化できます。以下の代わりに……" +"APIに施す最後の変更では、`Content`型をモナドにしてdo記法を使えるようにするために、*Freeモナド*と呼ばれる構造を使っていきます。\n" +"これによって入れ子になった要素がわかりやすくなるような形式でHTML文書を構造化できます。\n" +"以下の代わりに……" #. type: Fenced code block (haskell) #: text/chapter14.md:368 @@ -12461,32 +12352,24 @@ msgstr "" #. type: Plain text #: text/chapter14.md:392 -#, fuzzy 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 " "actions." msgstr "" -"しかし、do記法だけがFreeモナドの恩恵だというわけではありません。\n" +"しかし、do記法だけがFreeモナドの恩恵ではありません。\n" "Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複数の解釈*を持たせることさえできます。" #. type: Plain text #: text/chapter14.md:394 -#, fuzzy -#| msgid "" -#| "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:" msgid "" "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" -"PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができま" -"す。" +"`Free`モナドは`free`ライブラリの`Control.Monad.Free`モジュールで定義されています。\n" +"PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができます。" #. type: Fenced code block (text) #: text/chapter14.md:395 @@ -12504,23 +12387,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:403 -#, fuzzy -#| 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`!" 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`!" msgstr "" -"`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示していま" -"す。\n" -"実は、`Free`モナドを使えば任意の`Functor`を`Monad`にできます。" +"`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示しています。\n" +"実はなんと、`Free`モナドを使えば任意の`Functor`を`Monad`にできるのです。" #. type: Plain text #: text/chapter14.md:405 -#, fuzzy 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 " @@ -12528,9 +12404,9 @@ msgid "" "be `elem` and `text`. We can simply modify our `Content` type as follows:" msgstr "" "モナドの動作の*表現*の定義から始めます。\n" -"こうするには、対応する各モナド動作それぞれについて、1つのデータ構築子を持つ`Functor`を作成する必要があります。\n" +"これには対応したい各モナド動作について、1つのデータ構築子を持つ`Functor`を作成する必要があります。\n" "今回の場合、2つのモナドの動作は`elem`と`text`になります。\n" -"実際には、`Content`型を次のように変更するだけです。" +"`Content`型を次のように変更するだけでできます。" #. type: Fenced code block (haskell) #: text/chapter14.md:406 @@ -12554,13 +12430,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:417 -#, fuzzy -#| 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 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." 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 " @@ -12568,11 +12437,9 @@ msgid "" "`Functor` instance simply applies the function `f` to the value of type `a` " "in each data constructor." msgstr "" -"ここで、この `ContentF`型構築子は以前の `Content`データ型とよく似ています。\n" -"しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引" -"数として取るように変更されています。\n" -"`Functor`インスタンスでは、単に各データ構築子で型 `a`の構成要素に関数 `f`を適" -"用します。" +"ここで、この`ContentF`型構築子は以前の`Content`データ型とよく似ています。\n" +"しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引数として取るように変更されています。\n" +"`Functor`インスタンスでは、単に各データ構築子で型`a`の値に関数`f`を適用します。" #. type: Plain text #: text/chapter14.md:419 @@ -12593,14 +12460,13 @@ msgstr "type Content = Free ContentF\n" #. type: Plain text #: text/chapter14.md:425 -#, fuzzy 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 " "`Content` data constructor, we restrict our users to only using the monadic " "actions we provide." msgstr "" -"型同義語の代わりにnewtypeを使用して、使用者に対してライブラリの内部表現を露出することを避けられます。\n" +"型同義語の代わりに`newtype`を使用して、使用者に対してライブラリの内部表現を露出することを避けられます。\n" "`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使用者に制限しています。" #. type: Plain text @@ -12641,16 +12507,15 @@ msgstr "" #. type: Plain text #: text/chapter14.md:439 -#, fuzzy 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 " "type:" msgstr "" -"また、`Content`モナドについての新しいモナドの動作になる`elem`と`text`関数を変更する必要があります。\n" +"また、`Content`モナドについての新しいモナドの動作になるよう、`elem`と`text`関数を変更する必要があります。\n" "これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えます。\n" -"この関数の型は次のようになっています。" +"以下がその型です。" #. type: Fenced code block (haskell) #: text/chapter14.md:440 @@ -12660,14 +12525,13 @@ msgstr "liftF :: forall f a. f a -> Free f a\n" #. type: Plain text #: text/chapter14.md:445 -#, fuzzy 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 use the data constructors " "of our `ContentF` type constructor directly:" msgstr "" "`liftF`により、何らかの型`a`について、型`f a`の値からFreeモナドの動作を構築できるようになります。\n" -"今回の場合、`ContentF`型構築子のデータ構築子をそのまま使うだけです。" +"今回の場合、`ContentF`型構築子のデータ構築子をそのまま使えます。" #. type: Fenced code block (haskell) #: text/chapter14.md:446 @@ -12753,26 +12617,16 @@ msgstr "" #. type: Plain text #: text/chapter14.md:479 -#, fuzzy -#| 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_." msgid "" "_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" -"実際には、これはスタックオーバーフローを心配する必要がないことを意味しま" -"す。\n" -"なぜなら `m`は安全な*末尾再帰モナド*に対応しているからです。" +"*補足*:厳密には、より強い`MonadRec`制約を満たすモナド`m`に制限されています。\n" +"実際、ら`m`は安全な*末尾再帰モナド*に対応してため、スタックオーバーフローを心配する必要はありません。" #. type: Plain text #: text/chapter14.md:481 -#, fuzzy msgid "" "First, we have to choose a monad in which we can interpret our actions. We " "will use the `Writer String` monad to accumulate an HTML string as our " @@ -12924,15 +12778,10 @@ msgstr " renderContentItem :: ContentF (Content Unit) -> Writer String (Con #. type: Plain text #: text/chapter14.md:540 -#, fuzzy -#| msgid "" -#| "We can implement this function by simply pattern matching on the two data " -#| "constructors of `ContentF`:" msgid "" "We can implement this function by pattern matching on the two data " "constructors of `ContentF`:" -msgstr "" -"`ContentF`の2つのデータ構築子でパターン照合するだけでこの関数を実装できます。" +msgstr "`ContentF`の2つのデータ構築子でパターン照合すればこの関数を実装できます。" #. type: Fenced code block (haskell) #: text/chapter14.md:541 @@ -12954,14 +12803,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:551 -#, fuzzy msgid "" "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 @@ -13030,15 +12878,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:578 -#, fuzzy msgid "" "Let's illustrate the power of the free monad construction by extending our " "language with a new monadic action that returns a non-trivial result." -msgstr "非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナド構造の威力をお見せしましょう。" +msgstr "非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナドを構築する威力をお見せしましょう。" #. type: Plain text #: text/chapter14.md:580 -#, fuzzy msgid "" "Suppose we want to generate HTML documents that contain hyperlinks to " "different sections of the document using _anchors_. We can accomplish this " @@ -13046,11 +12892,10 @@ msgid "" "document: once at the anchor's definition and once in each hyperlink. " "However, this approach has some basic issues:" msgstr "" -"*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を生成するとします。\n" -"これは既に達成できています。\n" -"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めればよいのです。\n" -"1つはアンカーの定義自身に、もう1つはそれぞれのハイパーリンクにあります。\n" -"しかし、この方法には根本的な問題が幾つかあります。" +"*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を生成したいとします。\n" +"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めれば、これは達成できます。\n" +"1つはアンカーの定義自身に、もう1つは各ハイパーリンクにあります。\n" +"しかし、この手法には基本的な問題が幾つかあります。" #. type: Bullet: '- ' #: text/chapter14.md:583 @@ -13064,7 +12909,6 @@ msgstr "開発者がアンカー名を1つ以上の箇所で打ち間違うか #. type: Plain text #: text/chapter14.md:585 -#, fuzzy msgid "" "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 " @@ -13102,16 +12946,10 @@ msgstr "" #. type: Plain text #: text/chapter14.md:598 -#, fuzzy -#| 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:" msgid "" "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`型クラ" -"スのインスタンスを定義します。" +msgstr "次に、属性値に`Name`を使えるよう、新しい型に`IsValue`型クラスのインスタンスを定義します。" #. type: Fenced code block (haskell) #: text/chapter14.md:599 @@ -13255,20 +13093,15 @@ msgstr "" #. type: Plain text #: text/chapter14.md:654 -#, fuzzy -#| msgid "" -#| "Notice that we provide the `id` function as our continuation, meaning " -#| "that we return the result of type `Name` unchanged." msgid "" "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 -#, fuzzy msgid "" "Finally, we need to update our interpretation function to interpret the new " "action. We previously used the `Writer String` monad to interpret our " @@ -13277,10 +13110,10 @@ msgid "" "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" -"型注釈を短く保てるように、この解釈モナドを型同義語として定義しておきます。" +"最後に、新しい動作を解釈させるように解釈関数を更新する必要があります。\n" +"以前は計算を解釈するために`Writer String`モナドを使っていましたが、このモナドは新しい名前を生成できないので、何か他のものに切り替えなければなりません。\n" +"`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせられます。\n" +"型注釈が短く保たれるよう、この解釈モナドを型同義語として定義できます。" #. type: Fenced code block (haskell) #: text/chapter14.md:657 @@ -13299,7 +13132,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:664 -#, fuzzy 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 " @@ -13307,10 +13139,10 @@ msgid "" "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 @@ -13359,19 +13191,13 @@ msgstr "" #. type: Plain text #: text/chapter14.md:683 -#, fuzzy -#| 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 element and the target of a hyperlink:" 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 " "element and the target of a hyperlink:" msgstr "" -"以上をもって、この新しい機能をPSCiで試すことができます。\n" -"これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンク" -"のリンク先の両方として使います。" +"以上をもって、この新しい機能をPSCiで試せます。\n" +"これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンクのリンク先の両方として使います。" #. type: Fenced code block (text) #: text/chapter14.md:684 @@ -13411,16 +13237,10 @@ msgstr "" #. type: Plain text #: text/chapter14.md:703 -#, fuzzy -#| msgid "" -#| "You can verify that multiple calls to `newName` do in fact result in " -#| "unique names." msgid "" "You can verify that multiple calls to `newName` do, in fact, result in " "unique names." -msgstr "" -"複数回の `newName`の呼び出しの結果が、実際に一意な名前になっていることも確か" -"められます。" +msgstr "複数回の`newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめられます。" #. type: Bullet: ' 1. ' #: text/chapter14.md:711 @@ -13449,15 +13269,13 @@ msgstr "" #. type: Bullet: ' 1. ' #: text/chapter14.md:711 -#, fuzzy msgid "" "(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 @@ -13492,11 +13310,6 @@ msgstr "" #. type: Plain text #: text/chapter14.md:723 -#, fuzzy -#| msgid "" -#| "In this chapter, we developed a domain-specific language for creating " -#| "HTML documents, by incrementally improving a naive implementation using " -#| "some standard techniques:" msgid "" "In this chapter, we developed a domain-specific language for creating HTML " "documents by incrementally improving a naive implementation using some " @@ -13507,25 +13320,14 @@ msgstr "" #. type: Bullet: '- ' #: text/chapter14.md:728 -#, fuzzy -#| msgid "" -#| "We used _smart constructors_ to hide the details of our data " -#| "representation, only permitting the user to create documents which were " -#| "_correct-by-construction_." msgid "" "We used _smart constructors_ to hide the details of our data representation, " "only permitting the user to create documents that were _correct-by-" "construction_." -msgstr "" -"_スマート構築子_ を使ってデータ表現の詳細を隠し、利用者には _構築により正しい" -"_ 文書だけを作ることを許しました。" +msgstr "*スマート構築子*を使ってデータ表現の詳細を隠し、利用者には*構築により正しい*文書だけを作ることを許しました。" #. type: Bullet: '- ' #: text/chapter14.md:728 -#, fuzzy -#| msgid "" -#| "We used an _user-defined infix binary operator_ to improve the syntax of " -#| "the language." msgid "" "We used a _user-defined infix binary operator_ to improve the syntax of the " "language." @@ -13537,12 +13339,11 @@ 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:728 -#, fuzzy 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 " @@ -13550,7 +13351,7 @@ msgid "" "the monadic computations using standard monad transformers." msgstr "" "*Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。\n" -"それからこの表現を新しいモナド動作に対応するよう拡張し、標準モナド変換子を使ってモナドの計算を解釈しました。" +"それからこの表現を新しいモナド動作に対応するよう拡張し、標準的なモナド変換子を使ってモナドの計算を解釈しました。" #. type: Plain text #: text/chapter14.md:730 @@ -13564,21 +13365,14 @@ msgstr "" #. type: Plain text #: text/chapter14.md:731 -#, fuzzy -#| 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." msgid "" "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 @@ -20387,7 +20181,7 @@ msgstr "" msgid "" "We can annotate the expression with a type using the `::` operator, so that " "PSCi can choose the correct type class instance:" -msgstr "`::`演算子を使って式に註釈を付け、、PSCiが正しい型クラスインスタンスを選べるようにできます。" +msgstr "`::`演算子を使って式に註釈を付けてPSCiが正しい型クラスインスタンスを選べるようにできます。" #. type: Fenced code block (text) #: text/chapter6.md:112 From 1ffdd5297c349b035f3ba458c1cf7c4d3cd5f3c8 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 08:52:22 +0900 Subject: [PATCH 21/29] [ lint ] Japanese expressions --- .textlintrc.json | 24 ++++++++++++++++++++---- text-ja/chapter11.md | 2 +- text-ja/chapter3.md | 2 +- text-ja/chapter7.md | 2 +- translation/ja.po | 8 ++++---- 5 files changed, 27 insertions(+), 11 deletions(-) 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/text-ja/chapter11.md b/text-ja/chapter11.md index 1c1b1ecf..4815b67a 100644 --- a/text-ja/chapter11.md +++ b/text-ja/chapter11.md @@ -687,7 +687,7 @@ s`型クラスのインスタンスになっており、このクラスには他 特に、`transformers`パッケージではモナド変換子`WriterT`、`ReaderT`、`ExceptT`についての`MonadState`のインスタンスがあります。 通底する`Monad`が`MonadState`インスタンスを持つなら常に、これらもインスタンスを持ちます。 -実践的には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく、`get`、`put`、`modify`を直接自由に使用できます。 +つまり実際には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく`get`や`put`や`modify`を直接自由に使用できます。 当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが言えます。 `transformers`では主な各変換子について型クラスが定義されています。 diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md index bf771dd8..e15ebe90 100644 --- a/text-ja/chapter3.md +++ b/text-ja/chapter3.md @@ -656,7 +656,7 @@ findEntry firstName lastName book = head (filter filterEntry book) ``` しかし本章には*中置*[2引数演算子](https://github.com/purescript/documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれています。 -例えば`filterEntry`の定義中の`==`演算子で、2つの引数の*間*に置かれています。 +`filterEntry`の定義中の`==`演算子がそうで、2つの引数の*間*に置かれています。 PureScriptのソースコードでこうした中置演算子は隠れた*前置*の実装への中置別称として定義されています。 例えば`==`は以下の行により前置の`eq`関数の中置別称として定義されています。 diff --git a/text-ja/chapter7.md b/text-ja/chapter7.md index daaac50a..08c90aba 100644 --- a/text-ja/chapter7.md +++ b/text-ja/chapter7.md @@ -353,7 +353,7 @@ Maybe String -> Maybe String -> Maybe String -> Either String String ``` このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラー文言が表示されます。 -しかし、もし複数の入力が省略されているとき、最初のエラーしか見れません。 +しかし、もし複数の入力が省略されているとき、最初のエラーしか見られません。 ```text > fullNameEither Nothing Nothing Nothing diff --git a/translation/ja.po b/translation/ja.po index b2e90af2..edfa645d 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-07-10 21:30+0900\n" -"PO-Revision-Date: 2023-08-25 08:38+0900\n" +"PO-Revision-Date: 2023-08-25 08:51+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -6890,7 +6890,7 @@ msgid "" msgstr "" "特に、`transformers`パッケージではモナド変換子`WriterT`、`ReaderT`、`ExceptT`についての`MonadState`のインスタンスがあります。\n" "通底する`Monad`が`MonadState`インスタンスを持つなら常に、これらもインスタンスを持ちます。\n" -"実践的には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく、`get`、`put`、`modify`を直接自由に使用できます。" +"つまり実際には、`StateT`がモナド変換子スタックの*どこか*に現れ、`StateT`より上の全てが`MonadState`のインスタンスであれば、`lift`を使う必要なく`get`や`put`や`modify`を直接自由に使用できます。" #. type: Plain text #: text/chapter11.md:594 @@ -15506,7 +15506,7 @@ msgid "" "an infix alias for the prefix `eq` function with the line:" msgstr "" "しかし本章には*中置*[2引数演算子](https://github.com/purescript/documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれています。\n" -"例えば`filterEntry`の定義中の`==`演算子で、2つの引数の*間*に置かれています。\n" +"`filterEntry`の定義中の`==`演算子がそうで、2つの引数の*間*に置かれています。\n" "PureScriptのソースコードでこうした中置演算子は隠れた*前置*の実装への中置別称として定義されています。\n" "例えば`==`は以下の行により前置の`eq`関数の中置別称として定義されています。" @@ -23324,7 +23324,7 @@ msgid "" "missing multiple inputs, we still only see the first error:" msgstr "" "このとき、全てのフィールドが与えられば成功の結果が表示され、そうでなければ省略されたフィールドのうち最初のものに対応するエラー文言が表示されます。\n" -"しかし、もし複数の入力が省略されているとき、最初のエラーしか見れません。" +"しかし、もし複数の入力が省略されているとき、最初のエラーしか見られません。" #. type: Fenced code block (text) #: text/chapter7.md:323 From cba4ac1a65374e2b38d9156129237a89e54a0d47 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 20:43:00 +0900 Subject: [PATCH 22/29] [ update ] PO file --- text-ja/chapter1.md | 8 +- text-ja/chapter3.md | 219 ++- text-ja/chapter4.md | 23 +- text-ja/chapter5.md | 2 +- text-ja/chapter6.md | 4 +- text-ja/chapter7.md | 2 +- translation/all.pot | 957 ++++++----- translation/ja.po | 3947 +++++++++++++++++++++++++++++-------------- 8 files changed, 3361 insertions(+), 1801 deletions(-) diff --git a/text-ja/chapter1.md b/text-ja/chapter1.md index a9a57a69..cfb9e67e 100644 --- a/text-ja/chapter1.md +++ b/text-ja/chapter1.md @@ -46,6 +46,8 @@ PureScriptは軽量な構文を備えていますが、この構文によりと また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに重要な、高速で理解しやすいコードを生成します。 概してPureScriptとは、純粋関数型プログラミングの理論的な強力さと、JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語だということを理解して頂けたらと思います。 +> Note that PureScript can target other backends, not only JavaScript, but this book focuses on targeting web browser and node environments. + ## 型と型推論 動的型付けの言語と静的型付けの言語をめぐる議論については充分に文書化されています。 @@ -198,7 +200,11 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 PureScript!](https://try.purescript.org)は利用者がwebブラウザでPureScriptのコードをコンパイルできるwebサイトです。 幾つかの簡単なコードの例もあります。 -もし例を読んで学ぶ方が好きでしたら、GitHubの`purescript`組織、`purescript-node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。 +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. ## 著者について diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md index e15ebe90..f1014ba2 100644 --- a/text-ja/chapter3.md +++ b/text-ja/chapter3.md @@ -21,6 +21,9 @@ ここでは、幾つかのモジュールをインポートします。 +- The `Prelude` module, which contains a small set of standard definitions + and functions. It re-exports many foundational modules from + the `purescript-prelude` library. - `Control.Plus`モジュールには`empty`値が定義されています。 - `Data.List`モジュールは`lists`パッケージで提供されています。 またこのパッケージはSpagoを使ってインストールできます。 @@ -30,7 +33,10 @@ 訳者注:ダブルドット (`..`) を使用すると、 指定された型コンストラクタのすべてのデータコンストラクタをインポートできます。 -このモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください。明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。 +Notice that the imports for these modules are listed explicitly in +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. ソースコードリポジトリをクローンしたと仮定すると、この章のプロジェクトは次のコマンドでSpagoを使用して構築できます。 @@ -115,20 +121,13 @@ String`型のフィールド`interests`で、後者は`String`の配列という ["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'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: ```haskell +import Prelude -- bring the (+) operator into scope + add :: Int -> Int -> Int add x y = x + y ``` @@ -138,6 +137,7 @@ PSCiで複数行の宣言を入力するには、`:paste`コマンドを使用 このモードでは、*Control-D*キーシーケンスを使って宣言を終了します。 ```text +> import Prelude > :paste … add :: Int -> Int -> Int … add = \x y -> x + y @@ -151,52 +151,12 @@ PSCiでこの関数が定義されていると、次のように関数の隣に2 30 ``` -## 量化された型 - -前の節ではPreludeで定義された関数の型を幾つか見てきました。 -例えば`flip`関数は次のような型を持っていました。 - -```text -> :type flip -forall a b c. (a -> b -> c) -> b -> a -> c -``` - -この`forall`キーワードは、`flip`が*全称量化された型*を持つことを示しています。 -つまり`a`や`b`や`c`をどの型に置き換えても良く、`flip`はその型で動作するのです。 - -例えば、`a`を`Int`、`b`を`String`、`c`を`String`と選んだとします。 -その場合、`flip`の型を次のように*特殊化*できます。 - -```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では空白がコードのまとまりを示すために使われているということです。 -宣言が複数行にわたる場合は、最初の行以外は最初の行の字下げより深くしなければなりません。 +If a declaration spans multiple lines, any lines except the first must be +indented past the indentation level of the first line. したがって、次は正しいPureScriptコードです。 @@ -234,19 +194,32 @@ y + z … ^D ``` -PureScriptの幾つかの予約語(例えば `where`や `of`、 -`let`)は新たなコードのまとまりを導入しますが、そのコードのまとまり内の宣言はそれより深く字下げされている必要があります。 +Certain PureScript keywords introduce a new block of code, in which +declarations must be further-indented: ```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`の宣言より深く字下げされていることに注意してください。 +This doesn't compile: + +```haskell +example x y z = + let + foo = x * y + bar = y * z + in + foo + bar +``` -ただし、ソースファイルの先頭、最初の `module`宣言における予約語 `where`だけは、この規則の唯一の例外になっています。 +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. ## 独自の型の定義 @@ -318,6 +291,60 @@ Type PureScriptの _種システム_ は他にも面白い種に対応していますが、それらについては本書の他の部分で見ていくことになるでしょう。 +## 量化された型 + +For illustration purposes, let's define a primitive function that takes any +two arguments and returns the first one: + +```text +> :paste +… constantlyFirst :: forall a b. a -> b -> a +… constantlyFirst = \a b -> a +… ^D +``` + +> Note that if you use `:type` to ask about the type of `constantlyFirst`, it will be more verbose: +> +> ```text +> : type constantlyFirst +> forall (a :: Type) (b :: Type). a -> b -> a +> ``` +> +> The type signature contains additional kind information, which explicitly notes that `a` and `b` should be concrete types. + +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. + +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 + +```text +Int -> String -> Int +``` + +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: + +```text +> constantlyFirst 3 "ignored" + +3 +``` + +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`): + +```text +:type constantlyFirst true "ignored" +Boolean + +:type constantlyFirst "keep" 3 +String +``` + ## 住所録の項目の表示 それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。 @@ -422,7 +449,7 @@ $ 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`の要素のリストを取り、同じ型の項目を持つ新しいリストを返すということです。 @@ -453,18 +480,70 @@ insertEntry entry book = Cons entry book ## カリー化された関数 -PureScriptでは、関数は常に1つの引数だけを取ります。 -`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。 +Functions in PureScript take exactly one argument. While it looks like the +`insertEntry` function takes two arguments, it is an example of a _curried +function_. In PureScript, all functions are considered curried. + +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. + +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: + +```haskell +add :: Int -> Int -> Int +add x y = x + y + +addFive :: Int -> Int +addFive = add 5 +``` + +`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: + +> Note that you must define the `add` function if you haven't already: +> +> ```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 +``` + +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`. + +```haskell +{{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}} +``` -`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。 +The `->` operator (in the type signature) associates to the right, which means that the compiler parses the type as ```haskell Entry -> (AddressBook -> AddressBook) ``` -すなわち、`insertEntry`は関数を返す関数なのです。 -この関数は単一の引数`Entry`を取り、新しい関数を返します。 -今度はこの関数が単一の引数`AddressBook`を取り、新しい`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`. これはつまり、最初の引数だけを与えて`insertEntry`を*部分適用*できたりするということです。 PSCiで結果の型が見られます。 @@ -579,11 +658,11 @@ $ 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つの型の一部を取り出してみましょう。 diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md index 6a96a7a2..bb8cea21 100644 --- a/text-ja/chapter4.md +++ b/text-ja/chapter4.md @@ -137,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つの型を自由に選ぶことができる、ということも示されています。 @@ -236,7 +236,7 @@ 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] @@ -251,7 +251,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] @@ -398,7 +398,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は次の型を報告するものと考えてください。 @@ -455,20 +455,21 @@ 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は以下の(より具体的な)答えをくれていると考えておきましょう。 +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: ```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 ``` diff --git a/text-ja/chapter5.md b/text-ja/chapter5.md index 748adc52..3d08a94c 100644 --- a/text-ja/chapter5.md +++ b/text-ja/chapter5.md @@ -196,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`は何でしょうか。 diff --git a/text-ja/chapter6.md b/text-ja/chapter6.md index 35e23235..9dbe5b0c 100644 --- a/text-ja/chapter6.md +++ b/text-ja/chapter6.md @@ -457,7 +457,7 @@ 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`と註釈を付けることはできます。 @@ -635,7 +635,7 @@ 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") diff --git a/text-ja/chapter7.md b/text-ja/chapter7.md index 08c90aba..6aa28689 100644 --- a/text-ja/chapter7.md +++ b/text-ja/chapter7.md @@ -99,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`は次のように特殊化されます。 diff --git a/translation/all.pot b/translation/all.pot index 36c888e0..2a929da3 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-07-10 21:30+0900\n" +"POT-Creation-Date: 2023-08-25 20:42+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -408,14 +408,22 @@ msgid "" "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 " @@ -428,7 +436,7 @@ msgid "" 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 " @@ -444,7 +452,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter1.md:47 +#: text/chapter1.md:49 #, no-wrap msgid "" "iAmANumber =\n" @@ -453,7 +461,7 @@ 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 " @@ -462,7 +470,7 @@ msgid "" 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,7 +500,7 @@ 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 " @@ -502,13 +510,13 @@ msgid "" 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 " @@ -517,7 +525,7 @@ msgid "" 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,7 +536,7 @@ 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 " @@ -538,13 +546,13 @@ msgid "" 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,7 +601,7 @@ 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 " @@ -603,7 +611,7 @@ msgid "" 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,7 +635,7 @@ 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 " @@ -637,7 +645,7 @@ msgid "" 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 " @@ -650,13 +658,13 @@ 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 " @@ -670,7 +678,7 @@ 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 " @@ -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:" 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,13 +718,13 @@ 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 " @@ -725,7 +733,7 @@ msgid "" 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,7 +749,7 @@ 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 " @@ -750,7 +758,7 @@ msgid "" 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 " @@ -761,13 +769,13 @@ msgid "" 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,7 +783,7 @@ 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 " @@ -784,7 +792,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [Purescript Discourse Forum](https://discourse.purescript.org/) is " @@ -792,7 +800,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "[PureScript: Jordan's " @@ -803,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 " @@ -812,7 +820,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The unofficial [PureScript " @@ -821,7 +829,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [PureScript documentation " @@ -831,7 +839,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "The [PureScript website](https://www.purescript.org) contains links to " @@ -840,7 +848,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter1.md:146 +#: text/chapter1.md:148 #, markdown-text msgid "" "[Try PureScript!](https://try.purescript.org) is a website that allows users " @@ -849,22 +857,24 @@ msgid "" 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 " @@ -875,7 +885,7 @@ msgid "" 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 " @@ -884,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 " @@ -899,7 +909,7 @@ msgid "" 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 " @@ -907,13 +917,13 @@ 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 " @@ -923,7 +933,7 @@ msgid "" 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 " @@ -933,7 +943,7 @@ msgid "" 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 " @@ -1603,7 +1613,7 @@ msgstr "" #: 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 @@ -3462,7 +3472,7 @@ msgstr "" #. type: Title ## #: 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:722 text/chapter4.md:631 text/chapter5.md:529 +#: 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 @@ -11824,13 +11834,22 @@ 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, provided by the `lists` package, which can be " @@ -11839,7 +11858,7 @@ msgid "" 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 " @@ -11847,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 " @@ -11864,7 +11884,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:29 +#: text/chapter3.md:30 #, no-wrap msgid "" "$ cd chapter3\n" @@ -11872,13 +11892,13 @@ 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 corresponding to JavaScript's " @@ -11889,7 +11909,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:38 +#: text/chapter3.md:39 #, no-wrap msgid "" "$ spago repl\n" @@ -11905,7 +11925,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:52 +#: text/chapter3.md:53 #, markdown-text msgid "" "PureScript defines other built-in types: integers, characters, arrays, " @@ -11913,7 +11933,7 @@ msgid "" 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 " @@ -11921,7 +11941,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:55 +#: text/chapter3.md:56 #, no-wrap msgid "" "> :type 1\n" @@ -11929,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 " @@ -11937,7 +11957,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:62 +#: text/chapter3.md:63 #, no-wrap msgid "" "> :type 'a'\n" @@ -11945,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 " @@ -11953,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" @@ -11967,7 +11987,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:81 +#: text/chapter3.md:82 #, markdown-text msgid "" "The last example shows an error from the type checker, which failed to " @@ -11975,7 +11995,7 @@ msgid "" 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 " @@ -11983,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\", " @@ -11996,7 +12016,7 @@ 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` " @@ -12005,7 +12025,7 @@ msgid "" 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 " @@ -12013,7 +12033,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:97 +#: text/chapter3.md:98 #, no-wrap msgid "" "> author.name\n" @@ -12024,44 +12044,26 @@ 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 using a backslash character " @@ -12072,9 +12074,10 @@ msgid "" 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" @@ -12082,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 " @@ -12090,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" @@ -12098,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 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 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 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 "" - -#. 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 " @@ -12198,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 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" @@ -12220,13 +12139,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:186 +#: text/chapter3.md:146 #, markdown-text 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" @@ -12234,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_ " @@ -12242,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 " @@ -12251,7 +12170,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:196 +#: text/chapter3.md:156 #, no-wrap msgid "" "> :paste\n" @@ -12261,13 +12180,13 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:204 +#: text/chapter3.md:164 #, markdown-text msgid "But this is not:" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:205 +#: text/chapter3.md:165 #, no-wrap msgid "" "> :paste\n" @@ -12277,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 " @@ -12326,13 +12258,13 @@ 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 " @@ -12343,19 +12275,19 @@ msgid "" 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, " @@ -12363,13 +12295,13 @@ msgid "" 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` differs from `Array Entry`, which represents an " @@ -12377,13 +12309,13 @@ msgid "" 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 " @@ -12392,7 +12324,7 @@ 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 " @@ -12402,7 +12334,7 @@ msgid "" 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 " @@ -12410,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" @@ -12419,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_, " @@ -12428,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 " @@ -12436,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 -> " @@ -12446,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 " @@ -12454,7 +12386,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:271 +#: text/chapter3.md:242 #, no-wrap msgid "" "> :kind Number\n" @@ -12469,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 " @@ -12477,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 " @@ -12495,7 +12528,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:289 +#: text/chapter3.md:306 #, no-wrap msgid "" "{{#include " @@ -12503,7 +12536,7 @@ 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 that takes an " @@ -12512,7 +12545,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:295 +#: text/chapter3.md:312 #, no-wrap msgid "" "{{#include " @@ -12520,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 " @@ -12529,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 " @@ -12546,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 " @@ -12561,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" @@ -12582,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 " @@ -12590,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\" " @@ -12598,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" @@ -12613,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 " @@ -12621,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" @@ -12631,13 +12664,13 @@ 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 " @@ -12645,13 +12678,13 @@ msgid "" 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 " @@ -12659,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 " @@ -12667,7 +12700,7 @@ 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 " @@ -12676,7 +12709,7 @@ msgid "" 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 " @@ -12688,7 +12721,7 @@ msgid "" 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 " @@ -12696,7 +12729,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:368 +#: text/chapter3.md:385 #, no-wrap msgid "" "$ spago repl\n" @@ -12704,11 +12737,11 @@ 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`, takes a " @@ -12717,25 +12750,25 @@ msgid "" 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 " @@ -12744,19 +12777,19 @@ 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 " @@ -12765,45 +12798,123 @@ msgid "" 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 an example of a _curried " -"function_." +"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:404 +#: 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 "" -"The `->` operator in the type of `insertEntry` associates to the right, " -"which means that the compiler parses the type as\n" +"> 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:464 +#, markdown-text, no-wrap +msgid "" +"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 that 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 we can _partially apply_ `insertEntry` by specifying only its " @@ -12811,7 +12922,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:413 +#: text/chapter3.md:473 #, no-wrap msgid "" "> :type insertEntry entry\n" @@ -12820,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 " @@ -12828,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" @@ -12836,7 +12947,7 @@ 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 " @@ -12844,7 +12955,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:428 +#: text/chapter3.md:488 #, no-wrap msgid "" "> :type insertEntry entry emptyBook\n" @@ -12852,7 +12963,7 @@ 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, which explains " @@ -12861,7 +12972,7 @@ msgid "" 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 " @@ -12870,7 +12981,7 @@ msgid "" 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 " @@ -12880,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" @@ -12894,7 +13005,7 @@ 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) " @@ -12905,7 +13016,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:448 +#: text/chapter3.md:508 #, no-wrap msgid "" "insertEntry :: Entry -> AddressBook -> AddressBook\n" @@ -12913,19 +13024,19 @@ 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, called _eta conversion_, can be used (along with other " @@ -12934,7 +13045,7 @@ msgid "" 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 " @@ -12944,13 +13055,13 @@ msgid "" 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 " @@ -12959,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 " @@ -12975,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 " @@ -12989,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\" " @@ -13015,13 +13126,13 @@ 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 " @@ -13031,7 +13142,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:500 +#: text/chapter3.md:560 #, markdown-text msgid "" "We can filter the address book, keeping only those entries with the correct " @@ -13040,7 +13151,7 @@ msgid "" 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 " @@ -13049,7 +13160,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:503 +#: text/chapter3.md:563 #, no-wrap msgid "" "$ spago repl\n" @@ -13057,21 +13168,21 @@ 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 " @@ -13081,7 +13192,7 @@ msgid "" 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 " @@ -13092,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_ " @@ -13100,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" @@ -13109,7 +13220,7 @@ 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 " @@ -13117,7 +13228,7 @@ msgid "" 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 " @@ -13128,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, " @@ -13136,7 +13247,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:536 +#: text/chapter3.md:596 #, no-wrap msgid "" "{{#include " @@ -13144,7 +13255,7 @@ 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 " @@ -13154,13 +13265,13 @@ msgid "" 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" @@ -13171,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 " @@ -13185,7 +13296,7 @@ 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` " @@ -13194,7 +13305,7 @@ msgid "" 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 " @@ -13206,7 +13317,7 @@ 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 unnecessary to " @@ -13215,13 +13326,13 @@ msgid "" 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 functions discussed so far used _prefix_ function application, where " @@ -13231,13 +13342,13 @@ msgid "" 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 " @@ -13250,13 +13361,13 @@ msgid "" 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 "" "Therefore `entry.firstName == firstName` in `filterEntry` could be replaced " @@ -13265,7 +13376,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:578 +#: text/chapter3.md:638 #, markdown-text msgid "" "In some situations, putting a prefix function in an infix position as an " @@ -13273,7 +13384,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:579 +#: text/chapter3.md:639 #, no-wrap msgid "" "> mod 8 3\n" @@ -13281,7 +13392,7 @@ 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 " @@ -13290,7 +13401,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:586 +#: text/chapter3.md:646 #, no-wrap msgid "" "> 8 `mod` 3\n" @@ -13298,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 " @@ -13306,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" @@ -13314,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 " @@ -13323,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" @@ -13332,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.` " @@ -13344,25 +13455,25 @@ 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 "" "The right associativity of our new `++` operator lets us get rid of the " @@ -13370,13 +13481,13 @@ msgid "" 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 " @@ -13384,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 " @@ -13406,7 +13517,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:634 +#: text/chapter3.md:694 #, markdown-text msgid "" "Note that `$` isn't a special syntax hardcoded into the language. It's " @@ -13415,7 +13526,7 @@ msgid "" 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" @@ -13425,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 " @@ -13441,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 " @@ -13449,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 " @@ -13463,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, " @@ -13471,7 +13582,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:654 +#: text/chapter3.md:714 #, no-wrap msgid "" "> 8 + 3\n" @@ -13482,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 " @@ -13494,7 +13605,7 @@ msgid "" msgstr "" #. type: Fenced code block (text) -#: text/chapter3.md:664 +#: text/chapter3.md:724 #, no-wrap msgid "" "> add3 = (3 + _)\n" @@ -13503,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 " @@ -13511,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" @@ -13526,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 " @@ -13541,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` " @@ -13551,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 " @@ -13560,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 " @@ -13568,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 " @@ -13582,7 +13693,7 @@ msgid "" msgstr "" #. type: Fenced code block (haskell) -#: text/chapter3.md:699 +#: text/chapter3.md:759 #, no-wrap msgid "" "{{#include " @@ -13591,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: " @@ -13612,7 +13723,7 @@ msgid "" msgstr "" #. type: Plain text -#: text/chapter3.md:713 +#: text/chapter3.md:773 #, markdown-text msgid "" "I will let you decide which definition is easier to understand, but it is " @@ -13622,7 +13733,7 @@ msgid "" 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 " @@ -13632,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 -> " @@ -13642,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 " @@ -13652,7 +13763,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" "(Medium) Write a function `isInBook` that tests whether a name appears in a " @@ -13662,7 +13773,7 @@ msgid "" msgstr "" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 #, markdown-text msgid "" "(Difficult) Write a function `removeDuplicates` which removes \"duplicate\" " @@ -13675,7 +13786,7 @@ msgid "" 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 and " @@ -13683,43 +13794,43 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text 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 "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 "Use curried functions to represent functions of multiple arguments." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text msgid "Create programs from smaller components by composition." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text msgid "Structure code neatly using `where` expressions." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text msgid "Avoid null values by using the `Maybe` type." msgstr "" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 #, markdown-text msgid "" "Use techniques like eta conversion and function composition to refactor code " @@ -13727,7 +13838,7 @@ msgid "" 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 "" @@ -14087,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 @@ -14102,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 @@ -14322,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" @@ -14351,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" @@ -14682,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 @@ -14808,10 +14920,12 @@ 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 @@ -14819,18 +14933,18 @@ msgstr "" #, markdown-text msgid "" "These types are more general than we are interested in right now. For this " -"chapter, we can assume that PSCi has given the following (more specific) " -"answer:" +"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 "" @@ -15958,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 @@ -18093,7 +18207,7 @@ 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 @@ -18523,7 +18637,8 @@ msgstr "" #, 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" @@ -19454,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 diff --git a/translation/ja.po b/translation/ja.po index edfa645d..d7485117 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" -"POT-Creation-Date: 2023-07-10 21:30+0900\n" +"POT-Creation-Date: 2023-08-25 20:42+0900\n" "PO-Revision-Date: 2023-08-25 08:51+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" @@ -154,8 +154,11 @@ 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" +"より初心者にやさしくできそうな分かりづらい節を指摘するような単純なものであ" +"れ、共有いただいたどんなフィードバックにも感謝します。" #. type: Plain text #: README.md:12 @@ -164,8 +167,10 @@ 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" -"テストの最新の状態については[#79](https://github.com/purescript-contrib/purescript-book/issues/79)を見てください。" +"各章には単体テストも加えられているので、演習への自分の回答が正しいかどうか確" +"かめることができます。\n" +"テストの最新の状態については[#79](https://github.com/purescript-contrib/" +"purescript-book/issues/79)を見てください。" #. type: Title ## #: README.md:13 @@ -206,7 +211,9 @@ msgid "" "This book will show you how to get started with the PureScript programming " "language, from the basics (setting up a development environment) to the " "advanced." -msgstr "本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミング言語の始め方を示します。" +msgstr "" +"本書は、基礎(開発環境の立ち上げ)から応用に至るまでの、PureScriptプログラミ" +"ング言語の始め方を示します。" #. type: Plain text #: README.md:22 @@ -216,7 +223,8 @@ msgid "" "be introduced. Here are some examples of problems that will be solved in " "this book:" msgstr "" -"各章は特定の課題により動機付けられており、その問題を解いていく過程において、新しい関数型プログラミングの道具と技法が導入されていきます。\n" +"各章は特定の課題により動機付けられており、その問題を解いていく過程において、" +"新しい関数型プログラミングの道具と技法が導入されていきます。\n" "以下は本書で解いていく課題の幾つかの例です。" #. type: Bullet: '- ' @@ -434,7 +442,8 @@ msgid "" "abstraction. Unrestricted JavaScript code also makes equational reasoning " "very difficult." msgstr "" -"関数は大幅な生産性の向上をもたらしうる単純な抽象化を可能にします。\n" +"関数は大幅な生産性の向上をもたらしうる単純な抽象化を可能にします。\n" "しかし、JavaScriptでの関数型プログラミングには欠点があります。\n" "JavaScriptは冗長で、型付けされず、強力な抽象化の形式を欠いているのです。\n" "また、野放図なJavaScriptコードは等式推論がとても困難です。" @@ -453,19 +462,29 @@ msgid "" "JavaScript." msgstr "" "PureScriptはこうした課題への対処を目指すプログラミング言語です。\n" -"PureScriptは軽量な構文を備えていますが、この構文によりとても表現力豊かでありながら分かりやすく読みやすいコードが書けるのです。\n" +"PureScriptは軽量な構文を備えていますが、この構文によりとても表現力豊かであり" +"ながら分かりやすく読みやすいコードが書けるのです。\n" "強力な抽象化を支援する豊かな型システムも採用しています。\n" -"また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに重要な、高速で理解しやすいコードを生成します。\n" -"概してPureScriptとは、純粋関数型プログラミングの理論的な強力さと、JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語だということを理解して頂けたらと思います。" +"また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに" +"重要な、高速で理解しやすいコードを生成します。\n" +"概して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 "" #. 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, " @@ -475,14 +494,18 @@ msgid "" "unlike in dynamically typed languages, types exist only at _compile-time_ " "and have no representation at runtime." msgstr "" -"動的型付けの言語と静的型付けの言語をめぐる議論については充分に文書化されています。\n" -"PureScriptは*静的型付け*の言語、つまり正しいプログラムはコンパイラによって*型*を与えられる言語です。\n" +"動的型付けの言語と静的型付けの言語をめぐる議論については充分に文書化されてい" +"ます。\n" +"PureScriptは*静的型付け*の言語、つまり正しいプログラムはコンパイラによって*型" +"*を与えられる言語です。\n" "またこの型は、その動作を示すものです。\n" -"逆に言えば、型を与えることができないプログラムは*誤ったプログラム*であり、コンパイラによって拒否されます。\n" -"動的型付けの言語とは異なり、PureScriptでは型は*コンパイル時*にのみ存在し、実行時には一切その表現がありません。" +"逆に言えば、型を与えることができないプログラムは*誤ったプログラム*であり、コ" +"ンパイラによって拒否されます。\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 " "unlike the types that you might have seen in other languages like Java or " @@ -495,15 +518,20 @@ msgid "" "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の型はMLやHaskellのような言語に影響を受けています。\n" -"PureScriptの型は表現力豊かであり、開発者はプログラムについての強い主張を表明できます。\n" +"多くの点で、PureScriptの型とこれまでJavaやC#のような他の言語で見てきたであろ" +"う型が異なっていることにも、注意することが大切です。\n" +"大まかに言えばPureScriptの型はJavaやC#と同じ目的を持っているものの、" +"PureScriptの型はMLやHaskellのような言語に影響を受けています。\n" +"PureScriptの型は表現力豊かであり、開発者はプログラムについての強い主張を表明" +"できます。\n" "最も重要なのはPureScriptの型システムが*型推論*に対応していることです。\n" -"型推論があれば他の言語より明示的な型注釈が遥かに少なく済み、型システムを厄介者ではなく*道具*にしてくれます。\n" -"単純な一例として、次のコードは*数*を定義していますが、`Number`型への言及はコードのどこにもありません。" +"型推論があれば他の言語より明示的な型注釈が遥かに少なく済み、型システムを厄介" +"者ではなく*道具*にしてくれます。\n" +"単純な一例として、次のコードは*数*を定義していますが、`Number`型への言及は" +"コードのどこにもありません。" #. type: Fenced code block (haskell) -#: text/chapter1.md:47 +#: text/chapter1.md:49 #, no-wrap msgid "" "iAmANumber =\n" @@ -515,7 +543,7 @@ 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 that are _unknown to the " @@ -525,7 +553,7 @@ msgstr "" "それでも、型注釈なく型の正しさを確かめられていることを示しています。" #. type: Fenced code block (haskell) -#: text/chapter1.md:55 +#: text/chapter1.md:57 #, no-wrap msgid "" "iterate f 0 x = x\n" @@ -535,7 +563,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 " @@ -545,7 +573,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 " @@ -563,35 +591,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 that is fundamentally type-driven: type classes, made popular in " "the functional programming language Haskell." msgstr "" -"加えて、型システムによって提供されるこの安全網は、より高度な抽象化を可能にします。\n" -"実際に、根本的に型駆動な抽象化の強力な形式である型クラスをPureScriptは提供しています。\n" +"加えて、型システムによって提供されるこの安全網は、より高度な抽象化を可能にし" +"ます。\n" +"実際に、根本的に型駆動な抽象化の強力な形式である型クラスをPureScriptは提供し" +"ています。\n" "この型クラスとは、関数型プログラミング言語Haskellによって有名になりました。" #. type: Title ## -#: text/chapter1.md:66 +#: text/chapter1.md:68 #, no-wrap msgid "Polyglot Web Programming" msgstr "多言語webプログラミング" #. type: Plain text -#: text/chapter1.md:69 +#: text/chapter1.md:71 msgid "" "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" -"特に成功している応用例を挙げると、データ解析、構文解析、コンパイラの実装、ジェネリックプログラミング、並列処理といった具合に、枚挙に暇がありません。" +"特に成功している応用例を挙げると、データ解析、構文解析、コンパイラの実装、" +"ジェネリックプログラミング、並列処理といった具合に、枚挙に暇がありません。" #. 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 " @@ -607,23 +638,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 " "more other languages to write the rest of the JavaScript." msgstr "" -"しかし、PureScriptの強みの1つは、JavaScriptを対象とする他の言語との相互運用性にあります。\n" -"アプリケーションの開発の一部にだけPureScriptを使用し、JavaScriptの残りの部分を記述するのに1つ以上の他の言語を使用するという方法もあります。" +"しかし、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." @@ -632,7 +665,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." @@ -641,7 +674,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 "" @@ -649,23 +682,25 @@ 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" -"ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、JavaScriptからPureScriptコードを呼び出す方法、及びその逆についても見ていきます。" +"ここで学ぶ手法は大規模なアプリケーションに組み込むこともできますが、" +"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 " @@ -674,21 +709,24 @@ msgid "" msgstr "" "本書のソフトウェア要件は最小限です。\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 " "GHC Haskell compiler, and we will walk through this process in the next " "chapter." msgstr "" -"PureScriptコンパイラ自体はバイナリの配布物としてもダウンロードできますし、最新のGHC 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." @@ -697,13 +735,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 " @@ -716,18 +754,20 @@ 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 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 " @@ -737,18 +777,22 @@ msgid "" "apply ideas from one language in the other, although many of the concepts " "presented here will have some interpretation in Haskell." msgstr "" -"PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通じている読者は本書で提示された概念や構文の多くに見覚えがあるでしょう。\n" -"しかし、PureScriptとHaskellの間には数多くの重要な違いがあることも理解しておくと良いでしょう。\n" -"ここで紹介する概念の多くはHaskellでも同じように解釈できるとはいえ、どちらかの言語での考え方を他方の言語でそのまま応用しようとすることは、必ずしも適切ではありません。" +"PureScriptはプログラミング言語Haskellに強く影響を受けているため、Haskellに通" +"じている読者は本書で提示された概念や構文の多くに見覚えがあるでしょう。\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 " "functional programming experience would be well-advised, however, to work " @@ -760,12 +804,15 @@ msgid "" "the book without reading the preceding chapters." msgstr "" "本書のほとんどの章が各章毎に完結しています。\n" -"しかし、関数型プログラミングの経験がほとんどない初心者の方は、各章を順番に進めていくのが賢明です。\n" +"しかし、関数型プログラミングの経験がほとんどない初心者の方は、各章を順番に進" +"めていくのが賢明です。\n" "最初の数章は本書の後半の内容を理解するのに必要な下地作りです。\n" -"関数型プログラミングの考え方に充分通じた読者(特にMLやHaskellのような強く型付けされた言語での経験を持つ読者)なら、本書の前半の章を読まなくても、後半の章のコードの大まかな理解を得ることが恐らく可能でしょう。" +"関数型プログラミングの考え方に充分通じた読者(特に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 is available " @@ -776,18 +823,22 @@ msgid "" "sections will contain shorter snippets which you can execute in the " "interactive mode PSCi to test your understanding." msgstr "" -"各章では1つの実用的な例に焦点を当て、新しい考え方を導入するための動機を与えます。\n" -"各章のコードは本書の[GitHubのリポジトリ](https://github.com/purescript-contrib/purescript-book)から入手できます。\n" -"該当の章のソースコードから抜粋したコード片が含まれる章もありますが、本書の内容に沿ってリポジトリのソースコードを読まれると良いでしょう。\n" -"長めの節には、理解を確かめられるように対話式モードのPSCiで実行できる短めのコード片が含まれます。" +"各章では1つの実用的な例に焦点を当て、新しい考え方を導入するための動機を与えま" +"す。\n" +"各章のコードは本書の[GitHubのリポジトリ](https://github.com/purescript-" +"contrib/purescript-book)から入手できます。\n" +"該当の章のソースコードから抜粋したコード片が含まれる章もありますが、本書の内" +"容に沿ってリポジトリのソースコードを読まれると良いでしょう。\n" +"長めの節には、理解を確かめられるように対話式モードのPSCiで実行できる短めの" +"コード片が含まれます。" #. type: Plain text -#: text/chapter1.md:106 +#: 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" @@ -803,20 +854,20 @@ 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 " @@ -824,10 +875,11 @@ msgid "" msgstr "" "通常、これらのコマンドはLinuxやMac OSの利用者に合わせたものになっています。\n" "そのためWindowsの利用者は小さな変更を加える必要があるかもしれません。\n" -"ファイル区切り文字を変更したり、シェルの組み込み機能をWindowsの相当するものに置き換えるなどです。" +"ファイル区切り文字を変更したり、シェルの組み込み機能を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:" @@ -836,7 +888,7 @@ msgstr "" "います。" #. type: Fenced code block (text) -#: text/chapter1.md:125 +#: text/chapter1.md:127 #, no-wrap msgid "" "> 1 + 2\n" @@ -846,7 +898,7 @@ 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 " @@ -856,7 +908,7 @@ msgstr "" "内容を完全に理解するために、各章の演習に取り組むことを強くお勧めします。" #. 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 " @@ -864,19 +916,20 @@ msgid "" "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." msgstr "" -"本書は初心者にPureScriptへの導入を提供することを目的としており、課題に対するお決まりの解決策の一覧を提供するような類の本ではありません。\n" +"本書は初心者に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:" @@ -885,35 +938,40 @@ 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 " "chatting about PureScript" msgstr "" -"[PureScriptのDiscordサーバ](https://discord.gg/vKn9up84bp)は抱えている問題についてチャットするのに良い場所です。\n" +"[PureScriptのDiscordサーバ](https://discord.gg/vKn9up84bp)は抱えている問題に" +"ついてチャットするのに良い場所です。\n" "こちらのサーバは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." -msgstr "[PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくある問題への解決策を探すのに良い場所です。" +msgstr "" +"[PurescriptのDiscourseフォーラム](https://discourse.purescript.org/)もよくあ" +"る問題への解決策を探すのに良い場所です。" #. 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 " "into great depth. If a concept in this book is difficult to understand, " "consider reading the corresponding section in that reference." msgstr "" -"[PureScript: Jordan's Reference](https://github.com/jordanmartinez/purescript-jordans-reference)は別のかなり深く踏み込んだ学習資料です。\n" -"本書中の概念で理解しにくいものがあったら、そちらの参考書の対応する節を読むとよいでしょう。" +"[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 " @@ -925,7 +983,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 " @@ -936,7 +994,7 @@ 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 " @@ -947,41 +1005,51 @@ 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 " "resources for beginners." msgstr "" -"[PureScriptのwebサイト](https://www.purescript.org)には幾つかの学習資料へのリンクがあります。\n" +"[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 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 +#, fuzzy +#| 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." 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." -msgstr "もし例を読んで学ぶ方が好きでしたら、GitHubの`purescript`組織、`purescript-node`組織及び`purescript-contrib`組織にはPureScriptコードの例が沢山あります。" +"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コードの例が沢山あります。" #. 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 " @@ -990,11 +1058,13 @@ msgid "" "C#, F#, Haskell and PureScript)." msgstr "" "私はPureScriptコンパイラの最初の開発者です。\n" -"カリフォルニア州ロサンゼルスを拠点にしており、8ビットパーソナルコンピュータであるAmstrad CPC上のBASICでまだ幼い時にプログラミングを始めました。\n" -"それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そしてPureScript)で専門的に業務に携わってきました。" +"カリフォルニア州ロサンゼルスを拠点にしており、8ビットパーソナルコンピュータで" +"あるAmstrad CPC上のBASICでまだ幼い時にプログラミングを始めました。\n" +"それ以来、私は幾つものプログラミング言語(JavaやScala、C#、F#、Haskell、そし" +"て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 " @@ -1005,7 +1075,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 " @@ -1017,14 +1087,19 @@ msgid "" "semantics of JavaScript, while enjoying the syntax and type system of a " "language like Haskell." msgstr "" -"JavaScriptでの経験をもとに、私はPureScriptコンパイラの開発を始めることにしました。\n" -"気が付くとHaskellのような言語から取り上げた関数型プログラミングの手法を使っていましたが、それを応用するためのもっと理に適った環境を求めていました。\n" -"そのとき検討した案のなかには、Haskellからその意味論を維持しながらJavaScriptへとコンパイルするいろいろな試み(Fay、Haste、GHCJS)もありました。\n" -"しかし私が興味を持っていたのは、この問題へ別の切り口からアプローチすると、どの程度うまくいくのかということでした。\n" -"そのアプローチとは、JavaScriptの意味論を維持しつつ、Haskellのような言語の構文と型システムを楽しむことなのです。" +"JavaScriptでの経験をもとに、私はPureScriptコンパイラの開発を始めることにしま" +"した。\n" +"気が付くとHaskellのような言語から取り上げた関数型プログラミングの手法を使って" +"いましたが、それを応用するためのもっと理に適った環境を求めていました。\n" +"そのとき検討した案のなかには、Haskellからその意味論を維持しながらJavaScriptへ" +"とコンパイルするいろいろな試み(Fay、Haste、GHCJS)もありました。\n" +"しかし私が興味を持っていたのは、この問題へ別の切り口からアプローチすると、ど" +"の程度うまくいくのかということでした。\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)." @@ -1033,37 +1108,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 " "certainly have failed." msgstr "" -"現在に至るまでPureScriptに手を貸してくださった多くの協力者に感謝したいと思います。\n" -"コンパイラ、ツール、ライブラリ、ドキュメント、テストでの、巨大で組織的な尽力なくしては、プロジェクトは間違いなく失敗していたことでしょう。" +"現在に至るまで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/)." -msgstr "本書の表紙に示されたPureScriptのロゴはGareth Hughesによって作成されたもので、[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/" +"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 "最後に、本書の内容に関する反応や訂正をくださった全ての方に、心より感謝したいと思います。" +msgstr "" +"最後に、本書の内容に関する反応や訂正をくださった全ての方に、心より感謝したい" +"と思います。" #. type: Title # #: text/chapter10.md:1 @@ -1087,8 +1169,10 @@ msgid "" "_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コードからJavaScriptコードへの呼び出し、及びその逆が可能になります。\n" +"本章ではPureScriptの*外部関数インターフェース* (foreign function interface; " +"*FFI*) を紹介します。\n" +"これによりPureScriptコードからJavaScriptコードへの呼び出し、及びその逆が可能" +"になります。\n" "以下の方法を押さえていきます。" #. type: Bullet: '- ' @@ -1146,8 +1230,10 @@ msgid "" "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 @@ -1176,7 +1262,8 @@ msgid "" "source files from those chapters." msgstr "" "このモジュールのソースコードは、第3章、第7章及び第8章の続きになります。\n" -"そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれています。" +"そうしたわけでソースツリーにはこれらの章からの適切なソースファイルが含まれて" +"います。" #. type: Plain text #: text/chapter10.md:26 @@ -1225,10 +1312,14 @@ msgid "" "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はこの言語の*応用的な*機能であることには心に留めておかれると良いでしょう。\n" -"安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現について理解していなければなりません。\n" -"この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝授することを目指します。" +"JavaScriptの扱いをできる限り単純にするため、PureScriptは直感的な外部関数イン" +"ターフェースを提供しています。\n" +"しかし、FFIはこの言語の*応用的な*機能であることには心に留めておかれると良いで" +"しょう。\n" +"安全かつ効率的に使用するには、扱うつもりであるデータの実行時の表現について理" +"解していなければなりません。\n" +"この章では、PureScriptの標準ライブラリのコードに付いて回るそのような理解を伝" +"授することを目指します。" #. type: Plain text #: text/chapter10.md:36 @@ -1240,7 +1331,8 @@ msgid "" "approach." msgstr "" "PureScriptのFFIはとても柔軟に設計されています。\n" -"実際には、外部関数にとても単純な型を与えるか、型システムを利用して外部のコードの誤った使い方を防ぐようにするか、開発者が選べるようになっています。\n" +"実際には、外部関数にとても単純な型を与えるか、型システムを利用して外部のコー" +"ドの誤った使い方を防ぐようにするか、開発者が選べるようになっています。\n" "標準ライブラリのコードは、後者の手法を採る傾向にあります。" #. type: Plain text @@ -1596,7 +1688,8 @@ 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 @@ -1653,7 +1746,8 @@ msgstr "" "PureScriptのカリー化された関数には勿論利点があります。\n" "部分的に関数を適用でき、関数型に型クラスインスタンスを与えられるのです。\n" "しかし効率上の代償も付いてきます。\n" -"効率性が決定的に重要なコードでは時々、多変数を受け付けるカリー化されていないJavaScript関数を定義する必要があります。" +"効率性が決定的に重要なコードでは時々、多変数を受け付けるカリー化されていない" +"JavaScript関数を定義する必要があります。" #. type: Plain text #: text/chapter10.md:183 @@ -1767,8 +1861,10 @@ msgid "" "caniuse.com/#feat=arrow-functions) who have not yet updated their web " "browser." msgstr "" -"前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しすればIE11)と互換性がありません。\n" -"執筆時点でwebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことができないと推計](https://caniuse.com/#feat=arrow-functions)されています。" +"前に見た矢印関数構文はES6の機能であり、そのため幾つかの古いブラウザ(名指しす" +"ればIE11)と互換性がありません。\n" +"執筆時点でwebブラウザをまだ更新していない[6%の利用者が矢印関数を使うことがで" +"きないと推計](https://caniuse.com/#feat=arrow-functions)されています。" #. type: Plain text #: text/chapter10.md:227 @@ -1788,7 +1884,10 @@ msgid "" "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)などのツールを含めると良いでしょう。" +msgstr "" +"それでも自分のFFIコードで矢印関数を使うこともできますが、デプロイの作業工程で" +"ES5に互換性のある関数へ変換するために[Babel](https://github.com/babel/" +"babel#intro)などのツールを含めると良いでしょう。" #. type: Plain text #: text/chapter10.md:231 @@ -1842,7 +1941,7 @@ msgstr "本書の残りの例では入れ子の関数の代わりに矢印関数 #: 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 @@ -1919,8 +2018,10 @@ msgid "" "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の関数の呼び出し方を示します。\n" -"前にありましたが、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 @@ -1976,8 +2077,10 @@ msgid "" "record. Note that a `Record` in PureScript is represented as an `Object` in " "JavaScript:" msgstr "" -"`Record`を渡すところを実演するために、以下に2つの`Complex`な数をレコードとして取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。\n" -"PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意してください。" +"`Record`を渡すところを実演するために、以下に2つの`Complex`な数をレコードとし" +"て取り、和を別のレコードとして返すJavaScriptの呼び出し方を示します。\n" +"PureScriptでの`Record`がJavaScriptでは`Object`として表現されることに注意して" +"ください。" #. type: Fenced code block (hs) #: text/chapter10.md:293 @@ -2040,7 +2143,8 @@ msgid "" "the JSON section, as well as cover techniques to protect against type " "mismatches." msgstr "" -"なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要があります。\n" +"なお、上の手法にはJavaScriptが期待通りの型を返すことを信用する必要がありま" +"す。\n" "PureScriptはJavaScriptのコードに型検査を適用できないからです。\n" "この型安全性の配慮について後のJSONの節でより詳しく解説していきます。\n" "型の不整合から身を守る手法についても押さえます。" @@ -2232,7 +2336,9 @@ msgstr "forall a. (a -> Maybe a) -> Maybe a -> Array a -> Maybe a\n" msgid "" "While both forms work, the latter is more vulnerable to unwanted inputs in " "place of `Just` and `Nothing`." -msgstr "どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に対してより脆弱です。" +msgstr "" +"どちらの形式でも動きますが、後者は`Just`と`Nothing`の場所での招かれざる入力に" +"対してより脆弱です。" #. type: Plain text #: text/chapter10.md:395 @@ -2278,7 +2384,8 @@ msgid "" "value (but not `null`). We'll call this type `Undefined a`." msgstr "" "`Maybe a`を返す代わりに`arr[0]`を返したいのだとしましょう。\n" -"型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する型がほしいです。\n" +"型`a`ないし`undefined`値(ただし`null`ではありません)の何れかの値を表現する" +"型がほしいです。\n" "この型を`Undefined a`と呼びましょう。" #. type: Plain text @@ -2349,7 +2456,8 @@ msgid "" "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でこの型を使えますからね。" @@ -2410,7 +2518,8 @@ msgid "" msgstr "" "このように、定義したこの外部関数はとても単純です。\n" "つまりPureScriptの型検査器を使うことによる利益が最大限得られるのです。\n" -"一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理はPureScriptコードへ移動しておくことをお勧めします。" +"一般に、外部関数は可能な限り小さく保ち、できるだけアプリケーションの処理は" +"PureScriptコードへ移動しておくことをお勧めします。" #. type: Title ## #: text/chapter10.md:458 text/chapter8.md:365 text/chapter8.md:444 @@ -2982,8 +3091,10 @@ msgid "" "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`で走らせた場合、印字の*合間に*僅かな遅延があり、より予測に近い挙動をします。" +"REPLでの非同期ログ出力はブロック全体が実行を終了するまで印字を待機する点に注" +"意しましょう。\n" +"このコードを`spago test`で走らせた場合、印字の*合間に*僅かな遅延があり、より" +"予測に近い挙動をします。" #. type: Plain text #: text/chapter10.md:680 @@ -3277,7 +3388,9 @@ msgstr "" msgid "" "If we create an alternate foreign import that defines the return type as " "`Json`:" -msgstr "返る型を`Json`として定義するようにして、代わりとなる外部インポートを作るとこうなります。" +msgstr "" +"返る型を`Json`として定義するようにして、代わりとなる外部インポートを作るとこ" +"うなります。" #. type: Fenced code block (hs) #: text/chapter10.md:789 @@ -3551,8 +3664,10 @@ msgid "" "you'll need to add some type class constraints for `k` and `v`. The compiler " "will guide you." msgstr "" -"(簡単)より広い種類のマップに関して動作するよう、前のJavaScriptの関数の新しい梱包を書いてください。\n" -"シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either JsonDecodeError (Set v)`です。\n" +"(簡単)より広い種類のマップに関して動作するよう、前のJavaScriptの関数の新し" +"い梱包を書いてください。\n" +"シグネチャは`valuesOfMapGeneric :: forall k v. Map k v -> Either " +"JsonDecodeError (Set v)`です。\n" "なお、`k`と`v`に幾つかの型クラス制約を加える必要があるでしょう。\n" "コンパイラが導いてくれます。" @@ -3563,8 +3678,10 @@ msgid "" "`quadraticRootsSet` that returns the `Complex` roots as a `Set` via JSON " "(instead of as a `Pair`)." msgstr "" -"(普通)少し前の`quadraticRoots`関数を書き換えて`quadraticRootSet`としてください。\n" -"この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返します。" +"(普通)少し前の`quadraticRoots`関数を書き換えて`quadraticRootSet`としてくだ" +"さい。\n" +"この関数は`Complex`の根をJSONを介して(`Pair`の代わりに)`Set`として返しま" +"す。" #. type: Plain text #: text/chapter10.md:902 @@ -3690,7 +3807,9 @@ msgstr "" 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の梱包を作ることから始めていきます。" +msgstr "" +"`Effect.Storage`モジュールに以下のwebストレージAPIのためのFFIの梱包を作ること" +"から始めていきます。" #. type: Bullet: '- ' #: text/chapter10.md:934 @@ -3841,8 +3960,10 @@ msgid "" "while we're at it. More information on how this works is available in the " "argonaut docs:" msgstr "" -"これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンスを必要としているからです。\n" -"また、ついでに汎用のエンコードインスタンスとデコードインスタンスを導出していきます。\n" +"これはなぜかというと`Person`レコード中の`PhoneType`が`EncodeJson`インスタンス" +"を必要としているからです。\n" +"また、ついでに汎用のエンコードインスタンスとデコードインスタンスを導出してい" +"きます。\n" "この仕組みについての詳細情報はargonautのドキュメントにあります。" #. type: Fenced code block (hs) @@ -3888,8 +4009,10 @@ msgid "" "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`ブロックの中に纏めるのは理に適っています。" @@ -3978,7 +4101,9 @@ msgstr "" 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`を使って前置し、エラー文言の質を向上させます。" +msgstr "" +"仕上げとして、各`Left`値の`String`に`lmap`を使って前置し、エラー文言の質を向" +"上させます。" #. type: Fenced code block (hs) #: text/chapter10.md:1042 @@ -4006,7 +4131,8 @@ msgid "" "triggered. See if you can trigger each of them." msgstr "" "最初のエラーのみがこのアプリの通常の操作内で起こります。\n" -"他のエラーはwebブラウザの開発ツールを開いてローカルストレージ中に保存された「person」文字列を編集し、そのページを参照することで引き起こせます。\n" +"他のエラーはwebブラウザの開発ツールを開いてローカルストレージ中に保存された" +"「person」文字列を編集し、そのページを参照することで引き起こせます。\n" "どのようにJSON文字列を変更したかが、どのエラーを引き起こすかを決定します。\n" "各エラーを引き起こせるかご確認ください。" @@ -4022,8 +4148,10 @@ msgstr "" "これでローカルストレージについては押さえました。\n" "次に`alert`動作を実装していきます。\n" "この動作は`Effect.Console`モジュールの`log`動作に似ています。\n" -"唯一の相違点は`alert`動作が`window.alert`メソッドを使うことで、対して`log`動作は`console.log`メソッドを使っています。\n" -"そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができます。\n" +"唯一の相違点は`alert`動作が`window.alert`メソッドを使うことで、対して`log`動" +"作は`console.log`メソッドを使っています。\n" +"そういうわけで`alert`は`window.alert`が定義された環境でのみ使うことができま" +"す。\n" "webブラウザなどです。" #. type: Fenced code block (hs) @@ -4115,7 +4243,7 @@ msgstr "" #. type: Title ## #: 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:722 text/chapter4.md:631 text/chapter5.md:529 +#: 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 @@ -4161,8 +4289,11 @@ msgid "" "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を使用するライブラリの例を多数提供しています。\n" -"残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾つか見ていきます。" +"より多くの例については、GitHubの`purescript`組織、`purescript-contrib`組織、" +"及び`purescript-node`組織が、FFIを使用するライブラリの例を多数提供していま" +"す。\n" +"残りの章では、型安全な方法で現実世界の問題を解決するために使うライブラリを幾" +"つか見ていきます。" #. type: Title ## #: text/chapter10.md:1093 @@ -4260,7 +4391,8 @@ msgid "" msgstr "" "ここでは`spago build`でコンパイルされていることを前提としています。\n" "SpagoはPureScriptモジュールをESモジュールにコンパイルするものです。\n" -"そのため、`import`を使って`Test`モジュールをインポートした後、`Test`オブジェクトの`gcd`関数を参照できました。" +"そのため、`import`を使って`Test`モジュールをインポートした後、`Test`オブジェ" +"クトの`gcd`関数を参照できました。" #. type: Plain text #: text/chapter10.md:1124 @@ -4290,7 +4422,8 @@ msgid "" "top-level declarations." msgstr "" "PureScriptはコード生成時にできるだけ名前を保持することを目指します。\n" -"とりわけ、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存されることが期待できます。\n" +"とりわけ、PureScriptやJavaScriptのキーワードでなければほとんどの識別子が保存" +"されることが期待できます。\n" "少なくとも最上位で宣言される名前についてはそうです。" #. type: Plain text @@ -4351,8 +4484,11 @@ msgid "" "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から使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" +"コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図してい" +"る場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めし" +"ます。\n" +"ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScript" +"から使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" #. type: Title ### #: text/chapter10.md:1155 @@ -4368,7 +4504,8 @@ msgid "" "mean? In PureScript, it means that the type of an expression should be " "compatible with its representation at runtime." msgstr "" -"型はプログラムがある意味で「正しい」ことをコンパイル時に論証できるようにします。\n" +"型はプログラムがある意味で「正しい」ことをコンパイル時に論証できるようにしま" +"す。\n" "つまり、その点については壊れることがありません。\n" "しかし、これは何を意味するのでしょうか。\n" "PureScriptでは、式の型は実行時の表現と互換性があることを意味します。" @@ -4425,8 +4562,10 @@ msgid "" "using `typeof`." msgstr "" "`Int`や`Number`や`String`の型の式についても似た法則が成り立ちます。\n" -"`Int`や`Number`型の式はnullでないJavaScriptの数へと評価されますし、`String`型の式はnullでないJavaScriptの文字列へと評価されます。\n" -"`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式は実行時に整数に評価されます。" +"`Int`や`Number`型の式はnullでないJavaScriptの数へと評価されますし、`String`型" +"の式はnullでないJavaScriptの文字列へと評価されます。\n" +"`typeof`を使った場合に型`Number`の値と見分けがつかなくなるにせよ、型`Int`の式" +"は実行時に整数に評価されます。" #. type: Plain text #: text/chapter10.md:1168 @@ -4439,10 +4578,13 @@ msgid "" "anything from a function also returns `undefined`)." msgstr "" "`Unit`についてはどうでしょうか。\n" -"`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何で表現されるかは重要ではありません。\n" +"`Unit`には現住 (`unit`) が1つのみで値が観測できないため、実のところ実行時に何" +"で表現されるかは重要ではありません。\n" "古いコードは`{}`を使って表現する傾向がありました。\n" "しかし比較的新しいコードでは`undefined`を使う傾向にあります。\n" -"なので、`Unit`を表現するのに使うものは何であれ差し支えありませんが、`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を返します)。" +"なので、`Unit`を表現するのに使うものは何であれ差し支えありませんが、" +"`undefined`を使うことが推奨されます(関数から何も返さないときも`undefined`を" +"返します)。" #. type: Plain text #: text/chapter10.md:1170 @@ -4470,8 +4612,10 @@ msgid "" "whose elements have the correct runtime representation for type `a`." msgstr "" "ご想像の通り、PureScriptの配列はJavaScriptの配列に対応しています。\n" -"しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っていることは覚えておいてください。\n" -"具体的には、もしPureScriptの式`e`が何らかの型`a`について型`Array a`を持つなら、`e`は(nullでない)JavaScript配列へと評価されます。\n" +"しかし、PureScriptの配列は均質である、つまり全ての要素が同じ型を持っているこ" +"とは覚えておいてください。\n" +"具体的には、もしPureScriptの式`e`が何らかの型`a`について型`Array a`を持つな" +"ら、`e`は(nullでない)JavaScript配列へと評価されます。\n" "この配列の全ての要素は型`a`の適切な実行時表現を持ちます。" #. type: Plain text @@ -4483,8 +4627,10 @@ msgid "" "labels. Of course, the fields of a record are not required to be of the same " "type." msgstr "" -"PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てきました。\n" -"関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レコードのフィールド中のデータの実行時の表現について論証できます。\n" +"PureScriptのレコードがJavaScriptのオブジェクトへと評価されることは既に見てき" +"ました。\n" +"関数や配列の場合のように、そのラベルに関連付けられている型を考慮すれば、レ" +"コードのフィールド中のデータの実行時の表現について論証できます。\n" "勿論、レコードのフィールドは、同じ型である必要はありません。" #. type: Title ### @@ -4501,8 +4647,10 @@ msgid "" "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:1182 @@ -4560,7 +4708,8 @@ msgid "" msgstr "" "ここで2つのJavaScriptオブジェクト型`Zero`と`One`を見てください。\n" "JavaScriptのキーワード`new`を使用すると、各型の値を作成できます。\n" -"引数を持つ構築子については、コンパイラは`value0`、`value1`などという名前のフィールドに、対応するデータを格納します。" +"引数を持つ構築子については、コンパイラは`value0`、`value1`などという名前の" +"フィールドに、対応するデータを格納します。" #. type: Plain text #: text/chapter10.md:1207 @@ -4587,7 +4736,8 @@ msgid "" "arguments. For example, this algebraic data type:" msgstr "" "1引数より多く取る構築子についてはどうでしょうか。\n" -"その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成します。\n" +"その場合でも、PureScriptコンパイラは新しいオブジェクト型と補助関数を作成しま" +"す。\n" "ただしこの場合、補助関数は2引数のカリー化された関数です。\n" "例えば次のような代数的データ型を考えます。" @@ -4633,7 +4783,9 @@ msgstr "" msgid "" "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`関数を使用すると作成できます。" +msgstr "" +"ここで、オブジェクト型`Two`の値はキーワード`new`または`Two.create`関数を使用" +"すると作成できます。" #. type: Plain text #: text/chapter10.md:1232 @@ -4644,7 +4796,8 @@ msgid "" "the same as its argument type." msgstr "" "newtypeの場合はまた少し異なります。\n" -"newtypeは代数的データ型のようなもので、単一の引数を取る単一の構築子を持つよう制限されていたことを思い出してください。\n" +"newtypeは代数的データ型のようなもので、単一の引数を取る単一の構築子を持つよう" +"制限されていたことを思い出してください。\n" "この場合、newtypeの実行時表現は、その引数の型と同じになります。" #. type: Plain text @@ -4652,7 +4805,9 @@ msgstr "" msgid "" "For example, this newtype represents telephone numbers is represented as a " "JavaScript string at runtime:" -msgstr "例えば、以下の電話番号を表すnewtypeは実行時にJavaScriptの文字列として表現されます。" +msgstr "" +"例えば、以下の電話番号を表すnewtypeは実行時にJavaScriptの文字列として表現され" +"ます。" #. type: Fenced code block (haskell) #: text/chapter10.md:1235 @@ -4665,7 +4820,9 @@ msgstr "newtype PhoneNumber = PhoneNumber String\n" msgid "" "This is useful for designing libraries since newtypes provide an additional " "layer of type safety without the runtime overhead of another function call." -msgstr "newtypeは、関数呼び出しによる実行時のオーバーヘッドなく更なる型安全性のための層を提供するため、ライブラリを設計するのに便利です。" +msgstr "" +"newtypeは、関数呼び出しによる実行時のオーバーヘッドなく更なる型安全性のための" +"層を提供するため、ライブラリを設計するのに便利です。" #. type: Title ### #: text/chapter10.md:1241 @@ -4754,8 +4911,10 @@ msgstr "" "しかし、それだけでは充分ではありません。\n" "量化された型の実行時表現は、これよりも更に厳しいものです。\n" "任意の式が*パラメトリック多相的*であることを要求しています。\n" -"つまり、その実装において、引数の型についてのどんな情報も使うことができないのです。\n" -"この追加の条件は、以下のJavaScriptの関数のような問題のある実装が多相型に現住することを防止します。" +"つまり、その実装において、引数の型についてのどんな情報も使うことができないの" +"です。\n" +"この追加の条件は、以下のJavaScriptの関数のような問題のある実装が多相型に現住" +"することを防止します。" #. type: Fenced code block (javascript) #: text/chapter10.md:1266 @@ -4835,7 +4994,9 @@ msgstr "" msgid "" "For example, here is a simple PureScript function with a constrained type " "that uses the `Show` type class:" -msgstr "例えば以下は、`Show`型クラスを使う制約付きの型を持つ、単純なPureScript関数です。" +msgstr "" +"例えば以下は、`Show`型クラスを使う制約付きの型を持つ、単純なPureScript関数で" +"す。" #. type: Fenced code block (haskell) #: text/chapter10.md:1288 @@ -5001,8 +5162,10 @@ msgid "" "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`型の実行時表現と一致します。\n" +"`random`関数は実行時には引数なしの関数として表現されていることに注目してくだ" +"さい。\n" +"この関数は乱数生成という副作用を実行して返しますが、返り値は`Number`型の実行" +"時表現と一致します。\n" "`Number`型はnullでないJavaScriptの数です。" #. type: Plain text @@ -5049,7 +5212,8 @@ msgid "" "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" +"実行時の `log`の表現は、単一の引数のJavaScript関数で、引数なしの関数を返しま" +"す。\n" "内側の関数はコンソールに文言を書き込むという副作用を実行します。" #. type: Plain text @@ -5080,7 +5244,9 @@ msgstr "" msgid "" "When using `spago bundle-app --to` or `spago run`, this call to `main` is " "generated automatically whenever the `Main` module is defined." -msgstr "`spago bundle-app --to`または`spago run`を使用する場合、`Main`モジュールが定義されている場合は常に、この`main`の呼び出しを自動的に生成できます。" +msgstr "" +"`spago bundle-app --to`または`spago run`を使用する場合、`Main`モジュールが定" +"義されている場合は常に、この`main`の呼び出しを自動的に生成できます。" #. type: Title # #: text/chapter11.md:1 @@ -5099,8 +5265,10 @@ msgid "" msgstr "" "この章の目標は*モナド変換子*について学ぶことです。\n" "モナド変換子は異なるモナドから提供された副作用を合成する方法を提供します。\n" -"動機付けとする例は、NodeJSのコンソール上で遊ぶことができるテキストアドベンチャーゲームです。\n" -"ゲームの様々な副作用(ロギング、状態、及び構成)が全てモナド変換子スタックによって提供されます。" +"動機付けとする例は、NodeJSのコンソール上で遊ぶことができるテキストアドベン" +"チャーゲームです。\n" +"ゲームの様々な副作用(ロギング、状態、及び構成)が全てモナド変換子スタックに" +"よって提供されます。" #. type: Plain text #: text/chapter11.md:10 text/chapter12.md:10 @@ -5133,7 +5301,8 @@ msgstr "" msgid "" "`optparse`, which provides applicative parsers for processing command-line " "arguments" -msgstr "`optparse`はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" +msgstr "" +"`optparse`はコマンドライン引数を処理するアプリカティブ構文解析器を提供します" #. type: Title ## #: text/chapter11.md:16 @@ -5185,7 +5354,9 @@ msgid "" "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" +"コマンドライン引数を与えるためには、追加の引数を直接アプリケーションに渡す`-" +"a`オプション付きで`spago run`を呼び出すか、`spago bundle-app`とすればよいで" +"す。\n" "2つ目の方法では`node`で直接走らせられるindex.jsファイルが作られます。" #. type: Plain text @@ -5223,8 +5394,10 @@ msgid "" "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" -"`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合に、ゲームの状態を出力できます。" +"プロンプトからは、`look`、`inventory`、`take`、`use`、`north`、`south`、" +"`east`、`west`などのコマンドを入力できます。\n" +"`debug`コマンドもあり、`--debug`コマンドラインオプションを与えられていた場合" +"に、ゲームの状態を出力できます。" #. type: Plain text #: text/chapter11.md:53 @@ -5235,8 +5408,10 @@ msgid "" "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" +"ゲームは2次元の碁盤の目の上が舞台で、コマンド`north`、`south`、`east`、`west`" +"を発行することによってプレイヤーが移動します。\n" +"ゲームにはアイテムの集まりがあり、プレイヤーの所有物であったり、ゲームの盤上" +"の特定の位置にあったりします。\n" "`take`コマンドを使うと、プレイヤーはアイテムを拾い上げられます。" #. type: Plain text @@ -5310,7 +5485,10 @@ msgid "" "The game is very simple, but the aim of the chapter is to use the " "`transformers` package to build a library that will enable rapid development " "of this type of game." -msgstr "このゲームはとても単純ですが、この章の目的は`transformers`パッケージを使用してこのような種類のゲームを素早く開発できるようにするライブラリを構築することです。" +msgstr "" +"このゲームはとても単純ですが、この章の目的は`transformers`パッケージを使用し" +"てこのような種類のゲームを素早く開発できるようにするライブラリを構築すること" +"です。" #. type: Title ## #: text/chapter11.md:88 @@ -5348,8 +5526,10 @@ msgid "" "monad\", the instance of the `Monad` type class is actually provided for the " "`State s` type constructor for any type `s`." msgstr "" -"`State`型構築子は、状態の型`s`、及び返り値の型`a`という2種類の引数を取ります。\n" -"「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのインスタンスが任意の型`s`についての`State s`型構築子に対して提供されています。" +"`State`型構築子は、状態の型`s`、及び返り値の型`a`という2種類の引数を取りま" +"す。\n" +"「`State`モナド」というように説明はしていますが、実際には`Monad`型クラスのイ" +"ンスタンスが任意の型`s`についての`State s`型構築子に対して提供されています。" #. type: Plain text #: text/chapter11.md:97 @@ -5381,9 +5561,12 @@ msgid "" "don't worry if you see different signatures in your IDE tooltips or on " "Pursuit." msgstr "" -"なお、ここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形式で表されています。\n" -"実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきます。\n" -"ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないでください。" +"なお、ここではこれらのAPIシグネチャは`State`型構築子を使った、単純化された形" +"式で表されています。\n" +"実際のAPIは本章の後にある「型クラス」節で押さえる`MonadState`が関わってきま" +"す。\n" +"ですからIDEのツールチップやPursuitで違うシグネチャを見たとしても心配しないで" +"ください。" #. type: Plain text #: text/chapter11.md:109 @@ -5394,8 +5577,10 @@ msgid "" "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:110 @@ -5445,7 +5630,8 @@ msgid "" "of type `Tuple a s`." msgstr "" "3つの各関数は型`s`の初期状態と型`State s a`の計算を引数に取ります。\n" -"`evalState`は返り値だけを返し、`execState`は最終的な状態だけを返し、`runState`は`Tuple a s`型の値として表現された両方を返します。" +"`evalState`は返り値だけを返し、`execState`は最終的な状態だけを返し、" +"`runState`は`Tuple a s`型の値として表現された両方を返します。" #. type: Plain text #: text/chapter11.md:130 @@ -5491,7 +5677,10 @@ msgid "" "(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 "(普通)括弧からなる文字列が*平衡している*のは、0個以上のより短い平衡した文字列を連結したものか、より短い平衡した文字列を一対の括弧で囲んだものかの何れかです。" +msgstr "" +"(普通)括弧からなる文字列が*平衡している*のは、0個以上のより短い平衡した文字" +"列を連結したものか、より短い平衡した文字列を一対の括弧で囲んだものかの何れか" +"です。" #. type: Plain text #: text/chapter11.md:147 @@ -5619,7 +5808,9 @@ 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`動作は変更された設定で計算するために使います。" +msgstr "" +"`ask`動作は現在の設定を読み取るために使い、`local`動作は変更された設定で計算" +"するために使います。" #. type: Plain text #: text/chapter11.md:186 @@ -5677,7 +5868,9 @@ msgstr "" 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`オブジェクトを変更し、ユーザーの権限を昇格させることもできます。" +msgstr "" +"`local`動作を使うと、計算の実行中に `Permissions`オブジェクトを変更し、ユー" +"ザーの権限を昇格させることもできます。" #. type: Fenced code block (haskell) #: text/chapter11.md:205 @@ -5886,8 +6079,11 @@ msgid "" "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`値の何れかが真であるかどうかを追跡するのに使えます。" +"よくある使い方としては型`String`もしくは`Array String`でログを累算していくと" +"いうものなどがありますが、`Writer`モナドはこれよりもっと一般的なものです。\n" +"累算するのに任意のモノイドの値を使うことができるので、`Additive Int`モノイド" +"を使って整数の合計を追跡するのに使ったり、`Disj Boolean`モノイドを使って途中" +"の`Boolean`値の何れかが真であるかどうかを追跡するのに使えます。" #. type: Plain text #: text/chapter11.md:282 @@ -5923,7 +6119,8 @@ msgid "" "String` monoid. Consider our previous implementation of the _greatest common " "divisor_ function:" msgstr "" -"例として、`Array String`モノイドを使用して、既存の関数にログを追加してみましょう。\n" +"例として、`Array String`モノイドを使用して、既存の関数にログを追加してみま" +"しょう。\n" "*最大公約数*関数の以前の実装を考えてみます。" #. type: Fenced code block (haskell) @@ -6019,7 +6216,9 @@ msgstr "" 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`は累算されたログと結果の両方を返します。" +msgstr "" +"ちょうど `State`モナドの場合と同じように、 `execWriter`が累算されたログだけを" +"返すのに対して、 `runWriter`は累算されたログと結果の両方を返します。" #. type: Plain text #: text/chapter11.md:333 @@ -6058,7 +6257,8 @@ msgid "" "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`が偶数なら`n / 2`、`n`が奇数なら`3 * n + 1`です。\n" +"(普通)*コラッツ*関数は自然数`n`上で定義され、`n`が偶数なら`n / 2`、`n`が奇" +"数なら`3 * n + 1`です。\n" "例えば`10`で始まるコラッツ数列は以下です。" #. type: Plain text @@ -6104,8 +6304,10 @@ msgid "" "examples of so-called _monad transformers_. The equivalent monad " "transformers are called `StateT`, `ReaderT`, and `WriterT`, respectively." msgstr "" -"上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*の例となっています。\n" -"対応する各モナド変換子はそれぞれ`StateT`、`ReaderT`、`WriterT`という名前です。" +"上の3つのモナド、`State`、`Reader`、`Writer`は、何れもいわゆる*モナド変換子*" +"の例となっています。\n" +"対応する各モナド変換子はそれぞれ`StateT`、`ReaderT`、`WriterT`という名前で" +"す。" #. type: Plain text #: text/chapter11.md:362 @@ -6142,7 +6344,8 @@ msgid "" "its own benefits and limitations." msgstr "" "ただし`Effect`モナドがこの問題を部分的に解決することは既に見ました。\n" -"モナド変換子はまた違った解決策を提供しますが、これらの各手法には利点と制約があります。" +"モナド変換子はまた違った解決策を提供しますが、これらの各手法には利点と制約が" +"あります。" #. type: Plain text #: text/chapter11.md:366 @@ -6257,7 +6460,9 @@ msgstr "" msgid "" "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)`は、エラーで失敗する可能性があり、変更可能な状態を使える計算を表しています。" +msgstr "" +"構築したモナド`StateT String (Either String)`は、エラーで失敗する可能性があ" +"り、変更可能な状態を使える計算を表しています。" #. type: Plain text #: text/chapter11.md:403 @@ -6268,7 +6473,9 @@ msgid "" "Monad.Trans` module defines the `MonadTrans` type class, which captures " "those type constructors which are monad transformers, as follows:" msgstr "" -"外側の`StateT String`モナドの動作(`get`、`put`、`modify`)は直接使えますが、梱包されているモナド (`Either String`) の作用を使うためには、これらの関数をモナド変換子まで「持ち上げ」る必要があります。\n" +"外側の`StateT String`モナドの動作(`get`、`put`、`modify`)は直接使えますが、" +"梱包されているモナド (`Either String`) の作用を使うためには、これらの関数をモ" +"ナド変換子まで「持ち上げ」る必要があります。\n" "`Control.Monad.Trans`モジュールは`MonadTrans`型クラスを定義しています。\n" "これはモナド変換子であるそうした型構築子を捕捉します。" @@ -6295,16 +6502,22 @@ msgid "" "type `Either String a`." msgstr "" "このクラスは単一のメンバー`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`の作用を使えます。" +"これは通底する任意のモナド`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:412 msgid "" "For example, the following computation reads the underlying state and then " "throws an error if the state is the empty string:" -msgstr "例えば、次の計算は通底する状態を読み、状態が空文字列であればエラーを投げます。" +msgstr "" +"例えば、次の計算は通底する状態を読み、状態が空文字列であればエラーを投げま" +"す。" #. type: Fenced code block (haskell) #: text/chapter11.md:413 @@ -6338,7 +6551,10 @@ 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`)." -msgstr "状態が空でなければ、この計算は`put`を使って状態を`drop 1 s`(つまり`s`から最初の文字を取り除いたもの)へと更新し、`take 1 s`(`s`の最初の文字)を返します。" +msgstr "" +"状態が空でなければ、この計算は`put`を使って状態を`drop 1 s`(つまり`s`から最" +"初の文字を取り除いたもの)へと更新し、`take 1 s`(`s`の最初の文字)を返しま" +"す。" #. type: Plain text #: text/chapter11.md:429 @@ -6370,8 +6586,10 @@ msgid "" "For example, we can apply `split` twice to read the first two characters " "from a string:" msgstr "" -"これは`StateT`を使わなくても実装できるので、さほど驚くようなことはありません。\n" -"しかし、モナドの中で扱っているので、do記法やアプリカティブコンビネータを使って、小さな計算から大きな計算を構築できます。\n" +"これは`StateT`を使わなくても実装できるので、さほど驚くようなことはありませ" +"ん。\n" +"しかし、モナドの中で扱っているので、do記法やアプリカティブコンビネータを使っ" +"て、小さな計算から大きな計算を構築できます。\n" "例えば、2回`split`を適用すると、文字列から最初の2文字を読めます。" #. type: Fenced code block (text) @@ -6393,10 +6611,12 @@ msgid "" "built monads for various problems, choose the side-effects we need, and keep " "the expressiveness of do notation and applicative combinators." msgstr "" -"`split`関数とその他沢山の動作を使えば基本的な構文解析ライブラリを構築できます。\n" +"`split`関数とその他沢山の動作を使えば基本的な構文解析ライブラリを構築できま" +"す。\n" "実際、これは`parsing`ライブラリで採用されている手法です。\n" "これがモナド変換子の力なのです。\n" -"必要な副作用を選択し、do記法とアプリカティブコンビネータで表現力を維持しながら、様々な問題のための特注のモナドを作成できるのです。" +"必要な副作用を選択し、do記法とアプリカティブコンビネータで表現力を維持しなが" +"ら、様々な問題のための特注のモナドを作成できるのです。" #. type: Title ## #: text/chapter11.md:447 @@ -6442,9 +6662,11 @@ msgid "" "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" +"`MonadError`クラスは`e`型のエラーを投げたり捕えたりに対応するモナドを捕捉し、" +"`ExceptT e`モナド変換子のインスタンスが提供されます。\n" "`Either e`モナドの`Left`と同じように、`throwError`動作では失敗を示せます。\n" -"`catchError`動作では`throwError`を使ってエラーが投げられた後に処理を継続できます。" +"`catchError`動作では`throwError`を使ってエラーが投げられた後に処理を継続でき" +"ます。" #. type: Plain text #: text/chapter11.md:464 @@ -6491,7 +6713,8 @@ msgid "" "computations in the `Writer` monad should be lifted using `lift`:" msgstr "" "試しに`ExceptT`を使って`Writer`モナドを包んでみましょう。\n" -"ここでもモナド変換子`ExceptT e`の動作を直接使うことも自由にできますが、`Writer`モナドの計算は`lift`を使って持ち上げるべきです。" +"ここでもモナド変換子`ExceptT e`の動作を直接使うことも自由にできますが、" +"`Writer`モナドの計算は`lift`を使って持ち上げるべきです。" #. type: Fenced code block (haskell) #: text/chapter11.md:472 @@ -6547,7 +6770,8 @@ msgstr "" msgid "" "Note that only those log messages that were written before the error was " "thrown get appended to the log." -msgstr "なお、エラーが投げられる前に書き出されるログ文言だけがログに追記されます。" +msgstr "" +"なお、エラーが投げられる前に書き出されるログ文言だけがログに追記されます。" #. type: Title ## #: text/chapter11.md:493 @@ -6565,9 +6789,12 @@ msgid "" "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" +"これまで見てきたように、モナド変換子を使って既存のモナドを土台に新しいモナド" +"を構築できます。\n" +"何かのモナド変換子`t1`とモナド`m`について、その適用`t1 m`もまたモナドになりま" +"す。\n" +"つまり、*2つめの*モナド変換子`t2`を結果`t1 m`に適用すると、3つ目のモナド`t2 " +"(t1 m)`を作れます。\n" "このようにしてモナド変換子の*スタック*を構築できます。\n" "これは構成されるモナドによって提供される副作用を組み合わせるものです。" @@ -6582,9 +6809,13 @@ msgid "" "transforming the `Identity` monad with `StateT`, `ReaderT`, and `WriterT`, " "respectively." msgstr "" -"実際には、通底するモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さもなくば`Data.Identity`モジュールで定義されている`Identity`モナドになります。\n" -"`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換はモナド変換子の作用だけを提供します。\n" -"`State`、`Reader`、`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`、`ReaderT`、`WriterT`で変換することによって実装されています。" +"実際には、通底するモナド`m`は、ネイティブの副作用が必要なら`Effect`モナド、さ" +"もなくば`Data.Identity`モジュールで定義されている`Identity`モナドになりま" +"す。\n" +"`Identity`モナドは何の新しい副作用も追加しませんから、`Identity`モナドの変換" +"はモナド変換子の作用だけを提供します。\n" +"`State`、`Reader`、`Writer`モナドは、`Identity`モナドをそれぞれ`StateT`、" +"`ReaderT`、`WriterT`で変換することによって実装されています。" #. type: Plain text #: text/chapter11.md:500 @@ -6595,8 +6826,10 @@ msgid "" "effects of mutable state, accumulating a log, and pure errors." msgstr "" "3つの副作用が組み合わっている例を見てみましょう。\n" -"`Identity`モナドをスタックの底にして、`StateT`、`WriterT`、`ExceptT`作用を使います。\n" -"このモナド変換子スタックは、可変状態、ログの蓄積、そして純粋なエラーの副作用を提供します。" +"`Identity`モナドをスタックの底にして、`StateT`、`WriterT`、`ExceptT`作用を使" +"います。\n" +"このモナド変換子スタックは、可変状態、ログの蓄積、そして純粋なエラーの副作用" +"を提供します。" #. type: Plain text #: text/chapter11.md:502 @@ -6660,8 +6893,10 @@ msgid "" "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" +"なお、モナド変換子スタックに現れる順序で副作用を取り除いていかなければなりま" +"せん。\n" +"最初に`StateT`型構築子を取り除くために`runStateT`を、それから`runtWriteT`、" +"`runExceptT`を使います。\n" "最後に`unwrap`を使用して`Identity`モナド中で計算します。" #. type: Fenced code block (text) @@ -6714,9 +6949,13 @@ msgid "" "the first error, as we saw earlier when we transformed `Writer` with " "`ExceptT`." msgstr "" -"これは、`ExceptT`モナド変換子が提供する副作用と`WriterT`モナド変換子が提供する副作用との関係によるものです。\n" -"これはモナド変換子スタックが構成されている順序を変更することで対処できます。\n" -"スタックの最上部に`ExceptT`変換子を移動すると、先ほど`Writer`を`ExceptT`に変換したときに見たように、最初のエラーまでに書かれた全ての文言がログに含まれるようになります。" +"これは、`ExceptT`モナド変換子が提供する副作用と`WriterT`モナド変換子が提供す" +"る副作用との関係によるものです。\n" +"これはモナド変換子スタックが構成されている順序を変更することで対処できま" +"す。\n" +"スタックの最上部に`ExceptT`変換子を移動すると、先ほど`Writer`を`ExceptT`に変" +"換したときに見たように、最初のエラーまでに書かれた全ての文言がログに含まれる" +"ようになります。" #. type: Plain text #: text/chapter11.md:545 @@ -6727,9 +6966,12 @@ msgid "" "`WriterT` and a second time over `StateT`. This is fine for small monad " "transformer stacks but quickly becomes inconvenient." msgstr "" -"このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、`lift`関数を複数回使わなければならないということです。\n" -"例えば`throwError`の呼び出しは、1回目は`WriteT`へ、2回目は`StateT`へ、と2回持ちあげなければなりません。\n" -"小さなモナド変換子スタックならなんとかなりますが、そのうちすぐに不便になるでしょう。" +"このコードの問題の1つは、複数のモナド変換子の上まで計算を持ち上げるために、" +"`lift`関数を複数回使わなければならないということです。\n" +"例えば`throwError`の呼び出しは、1回目は`WriteT`へ、2回目は`StateT`へ、と2回持" +"ちあげなければなりません。\n" +"小さなモナド変換子スタックならなんとかなりますが、そのうちすぐに不便になるで" +"しょう。" #. type: Plain text #: text/chapter11.md:547 @@ -6826,7 +7068,9 @@ msgstr "型クラスが助けに来たぞっ" 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`モナドの動作には次のような型が与えられていました。" +msgstr "" +"本章の最初で扱った `State`モナドを見てみると、 `State`モナドの動作には次のよ" +"うな型が与えられていました。" #. type: Fenced code block (haskell) #: text/chapter11.md:575 @@ -6888,9 +7132,13 @@ msgid "" "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`のインスタンスであれば、`lift`を使う必要なく`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:594 @@ -6900,7 +7148,8 @@ msgid "" "for each of the major transformers, allowing us to abstract over monads that " "support their operations." msgstr "" -"当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子についても、同じことが言えます。\n" +"当然ですが、これまで扱ってきた`ReaderT`、`WriterT`、`ExceptT`変換子について" +"も、同じことが言えます。\n" "`transformers`では主な各変換子について型クラスが定義されています。\n" "これによりそれらの操作に対応するモナドの上に抽象化できるのです。" @@ -6913,9 +7162,11 @@ msgid "" "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" +"上の`split`関数の場合、構築したモナドスタックは各型クラス`MonadState`、" +"`MonadWriter`、`MonadError`のインスタンスです。\n" "つまり`lift`は全く呼び出す必要がないのです。\n" -"まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、`tell`、`throwError`をそのまま使用できます。" +"まるでモナドスタック自体に定義されていたかのように、動作`get`、`put`、" +"`tell`、`throwError`をそのまま使用できます。" #. type: Fenced code block (haskell) #: text/chapter11.md:597 @@ -6931,8 +7182,10 @@ msgid "" "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:603 @@ -7008,7 +7261,8 @@ msgid "" "computation _zero-or-more_ times. The `some` combinator is similar but " "requires at least the first computation to succeed." msgstr "" -"`many`コンビネータは計算を*ゼロ回以上*繰り返し実行するために`Alternative`型クラスを使います。\n" +"`many`コンビネータは計算を*ゼロ回以上*繰り返し実行するために`Alternative`型ク" +"ラスを使います。\n" "`some`コンビネータも似ていますが、最低1回は計算が成功する必要があります。" #. type: Plain text @@ -7103,7 +7357,8 @@ msgid "" msgstr "" "以前本書中で配列内包表記を押さえたとき、`guard`関数を導入しました。\n" "これは欲しくない結果を取り除けるのに使えました。\n" -"実際には`guard`関数はもっと一般的で、`MonadPlus`のインスタンスである任意のモナドに対して使えます。" +"実際には`guard`関数はもっと一般的で、`MonadPlus`のインスタンスである任意のモ" +"ナドに対して使えます。" #. type: Fenced code block (haskell) #: text/chapter11.md:658 @@ -7135,7 +7390,8 @@ msgid "" msgstr "" "ここで、文字列が大文字でない場合に失敗するよう、`guard`を使用しています。\n" "なお、このコードは前に見た配列内包表記とよく似ています。\n" -"このように`MonadPlus`を使うことは、*モナド内包表記*の構築と呼ばれることがあります。" +"このように`MonadPlus`を使うことは、*モナド内包表記*の構築と呼ばれることがあり" +"ます。" #. type: Title ## #: text/chapter11.md:670 @@ -7163,7 +7419,10 @@ 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 "これにより、まずもし最初の文字が大文字なら複数の大文字に照合し、さもなくばもし最初の文字が小文字なら複数の小文字に照合する、という構文解析器を定義できます。" +msgstr "" +"これにより、まずもし最初の文字が大文字なら複数の大文字に照合し、さもなくばも" +"し最初の文字が小文字なら複数の小文字に照合する、という構文解析器を定義できま" +"す。" #. type: Fenced code block (text) #: text/chapter11.md:680 @@ -7174,7 +7433,8 @@ msgstr "> upperOrLower = some upper <|> some lower\n" #. type: Plain text #: text/chapter11.md:685 msgid "This parser will match characters until the case changes:" -msgstr "この構文解析器は、大文字と小文字が切り替わるまで、文字に照合し続けます。" +msgstr "" +"この構文解析器は、大文字と小文字が切り替わるまで、文字に照合し続けます。" #. type: Fenced code block (text) #: text/chapter11.md:686 @@ -7240,8 +7500,10 @@ msgid "" "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" -"標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器を、ほんの数行のコードで書くことができました。" +"繰り返しになりますが、これはモナド変換子が齎す再利用性の威力を示していま" +"す。\n" +"標準的な抽象化を再利用することで、宣言型スタイルのバックトラック構文解析器" +"を、ほんの数行のコードで書くことができました。" #. type: Bullet: ' 1. ' #: text/chapter11.md:721 @@ -7250,8 +7512,10 @@ msgid "" "the `string` parser. Verify that the new implementation type checks, and " "convince yourself it should." msgstr "" -"(簡単)`string`構文解析器の実装から`lift`関数の呼び出しを取り除いてください。\n" -"新しい実装の型検査が通ることを確認し、そうなることを納得するまで確かめましょう。" +"(簡単)`string`構文解析器の実装から`lift`関数の呼び出しを取り除いてくださ" +"い。\n" +"新しい実装の型検査が通ることを確認し、そうなることを納得するまで確かめましょ" +"う。" #. type: Bullet: ' 1. ' #: text/chapter11.md:721 @@ -7260,8 +7524,10 @@ msgid "" "parser `asFollowedByBs` that recognizes strings consisting of several copies " "of the string `\"a\"` followed by several copies of the string `\"b\"`." msgstr "" -"(普通)`string`構文解析器と`some`コンビネータを使って構文解析器`asFollowedByBs`を書いてください。\n" -"これは文字列`\"a\"`の連続と、それに続く文字列`\"b\"`の連続からなる文字列を認識するものです。" +"(普通)`string`構文解析器と`some`コンビネータを使って構文解析器" +"`asFollowedByBs`を書いてください。\n" +"これは文字列`\"a\"`の連続と、それに続く文字列`\"b\"`の連続からなる文字列を認" +"識するものです。" #. type: Bullet: ' 1. ' #: text/chapter11.md:721 @@ -7310,8 +7576,10 @@ msgid "" "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*モナドに組み合わさり、より単純に`RWS`モナドともされます。\n" +"モナド変換子のとある特定の組み合わせは頻出なので、`transformers`パッケージ内" +"の単一のモナド変換子として提供されています。\n" +"`Reader`、`Writer`、`State`のモナドは、*Reader-Writer-State*モナドに組み合わ" +"さり、より単純に`RWS`モナドともされます。\n" "このモナドは`RWST`モナド変換子という名前の、対応するモナド変換子を持ちます。" #. type: Plain text @@ -7343,7 +7611,8 @@ msgid "" "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 "" -"なお、`RWS`モナドは基底のモナドを`Identity`に設定することで独自のモナド変換子として定義されています。\n" +"なお、`RWS`モナドは基底のモナドを`Identity`に設定することで独自のモナド変換子" +"として定義されています。\n" "`Identity`は副作用を提供しないのでした。" #. type: Plain text @@ -7379,8 +7648,10 @@ msgid "" "is running in debug mode. These options will be set from the command line " "when we come to run our monad transformer." msgstr "" -"プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義されています。\n" -"モナド変換子を実行するとなると、これらのオプションがコマンドラインから設定されます。" +"プレイヤー名と、ゲームがデバッグモードで動作しているか否かを示すフラグが定義" +"されています。\n" +"モナド変換子を実行するとなると、これらのオプションがコマンドラインから設定さ" +"れます。" #. type: Plain text #: text/chapter11.md:753 @@ -7430,8 +7701,10 @@ msgid "" msgstr "" "`GameState`型は2つの新しいデータ構造を使っています。\n" "`Map`と`Set`はそれぞれ整列されたマップと整列された集合を表します。\n" -"`items`属性は、ゲーム平面上の座標からその位置にあるゲームアイテムの集合への対応付けです。\n" -"`player`属性はプレイヤーの現在の座標を格納し、`inventory`属性は現在プレイヤーが保有するゲームアイテムの集合を格納します。" +"`items`属性は、ゲーム平面上の座標からその位置にあるゲームアイテムの集合への対" +"応付けです。\n" +"`player`属性はプレイヤーの現在の座標を格納し、`inventory`属性は現在プレイヤー" +"が保有するゲームアイテムの集合を格納します。" #. type: Plain text #: text/chapter11.md:769 @@ -7440,7 +7713,8 @@ msgid "" "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`型クラスの任意の型を使えます。\n" +"`Map`と`Set`のデータ構造はキーによって整列され、このキーには`Ord`型クラスの任" +"意の型を使えます。\n" "つまりデータ構造中のキーは完全に順序付けされます。" #. type: Plain text @@ -7448,7 +7722,9 @@ msgstr "" msgid "" "We will see how the `Map` and `Set` structures are used as we write the " "actions for our game." -msgstr "ゲームの動作を書く上で`Map`と`Set`構造をどのように使っていくのかを見ていきます。" +msgstr "" +"ゲームの動作を書く上で`Map`と`Set`構造をどのように使っていくのかを見ていきま" +"す。" #. type: Plain text #: text/chapter11.md:773 @@ -7480,8 +7756,11 @@ msgid "" "`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" -"このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モナドは結果からコンソールにテキストを出力するような観測可能な副作用へと変換するために使っています。" +"`Reader`、`Writer`、`State`モナドの動作を再利用することで、`Game`モナドで定義" +"されている単純な動作を組み合わせてゲームを構築していきます。\n" +"このアプリケーションの最上位では`Game`モナドで純粋に計算しており、`Effect`モ" +"ナドは結果からコンソールにテキストを出力するような観測可能な副作用へと変換す" +"るために使っています。" #. type: Plain text #: text/chapter11.md:783 @@ -7491,7 +7770,8 @@ msgid "" "defined as follows:" msgstr "" "このゲームで最も簡単な動作の1つは `has`動作です。\n" -"この動作はプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調べます。\n" +"この動作はプレイヤーの持ち物に特定のゲームアイテムが含まれているかどうかを調" +"べます。\n" "これは次のように定義されます。" #. type: Fenced code block (haskell) @@ -7508,8 +7788,10 @@ msgid "" "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:791 @@ -7520,7 +7802,8 @@ msgid "" "current game state:" msgstr "" "他にも`pickUp`動作があります。\n" -"現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加します。\n" +"現在の位置にゲームアイテムがある場合、プレイヤーの持ち物にそのアイテムを追加" +"します。\n" "これには`MonadWriter`と`MonadState`型クラスの動作を使っています。\n" "一番最初に現在のゲームの状態を読み取ります。" @@ -7578,7 +7861,9 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:pickup_Just}}\n" msgid "" "In this case, we can use `put` to update the game state and `tell` to add a " "message to the log:" -msgstr "この場合、`put`を使ってゲームの状態を更新し、`tell`を使ってログに文言を追加できます。" +msgstr "" +"この場合、`put`を使ってゲームの状態を更新し、`tell`を使ってログに文言を追加で" +"きます。" #. type: Fenced code block (haskell) #: text/chapter11.md:812 @@ -7594,7 +7879,8 @@ msgid "" "`MonadWriter` for our `Game` monad transformer stack." msgstr "" "ここで2つの計算のどちらも`lift`が必要ないことに注意してください。\n" -"なぜなら`MonadState`と`MonadWriter`の両方について`Game`モナド変換子スタック用の適切なインスタンスが存在するからです。" +"なぜなら`MonadState`と`MonadWriter`の両方について`Game`モナド変換子スタック用" +"の適切なインスタンスが存在するからです。" #. type: Plain text #: text/chapter11.md:819 @@ -7606,17 +7892,22 @@ msgid "" "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`フィールドを変更しています。\n" +"`put`への引数では、レコード更新を使ってゲームの状態の`items`及び`inventory`" +"フィールドを変更しています。\n" "また、特定のキーの値を変更する`Data.Map`の`update`関数を使っています。\n" -"今回の場合、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、`delete`関数を使って指定したアイテムを集合から取り除いています。\n" -"`insert`を使って新しいアイテムをプレイヤーの持ち物の集合に加えるときにも、`inventory`は更新されます。" +"今回の場合、プレイヤーの現在の位置にあるアイテムの集合を変更するのに、" +"`delete`関数を使って指定したアイテムを集合から取り除いています。\n" +"`insert`を使って新しいアイテムをプレイヤーの持ち物の集合に加えるときにも、" +"`inventory`は更新されます。" #. type: Plain text #: text/chapter11.md:821 msgid "" "Finally, the `pickUp` function handles the remaining cases by notifying the " "user using `tell`:" -msgstr "最後に、`pickUp`関数は`tell`を使ってユーザに通知することにより、残りの場合を処理します。" +msgstr "" +"最後に、`pickUp`関数は`tell`を使ってユーザに通知することにより、残りの場合を" +"処理します。" #. type: Fenced code block (haskell) #: text/chapter11.md:822 @@ -7650,7 +7941,9 @@ msgid "" "same do notation block." msgstr "" "ここでは、ゲームの構成を読み込むために`ask`動作を使用しています。\n" -"繰り返しますが、どの計算でも`lift`する必要がなく、同じdo記法ブロック内で`MonadState`、`MonadReader`、`MonadWriter`型クラスで定義されている動作を使える点に注意してください。" +"繰り返しますが、どの計算でも`lift`する必要がなく、同じdo記法ブロック内で" +"`MonadState`、`MonadReader`、`MonadWriter`型クラスで定義されている動作を使え" +"る点に注意してください。" #. type: Plain text #: text/chapter11.md:835 @@ -7658,7 +7951,8 @@ msgid "" "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 @@ -7669,7 +7963,8 @@ msgid "" "`MonadWriter` type classes." msgstr "" "`Game`モジュールの残りの部分では同様の動作の集合が定義されています。\n" -"各動作は`MonadState`、`MonadReader`、`MonadWriter`型クラスにより定義された動作のみを使っています。" +"各動作は`MonadState`、`MonadReader`、`MonadWriter`型クラスにより定義された動" +"作のみを使っています。" #. type: Title ## #: text/chapter11.md:838 @@ -7682,7 +7977,9 @@ msgstr "計算の実行" msgid "" "Since our game logic runs in the `RWS` monad, it is necessary to run the " "computation to respond to the user's commands." -msgstr "このゲームロジックは`RWS`モナドで動くため、ユーザのコマンドに応答するために計算する必要があります。" +msgstr "" +"このゲームロジックは`RWS`モナドで動くため、ユーザのコマンドに応答するために計" +"算する必要があります。" #. type: Plain text #: text/chapter11.md:843 @@ -7717,7 +8014,9 @@ msgstr "{{#include ../exercises/chapter11/src/Game.purs:game_sig}}\n" 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`:" -msgstr "これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してから、`runRWS`を使って結果の`RWS`を計算します。" +msgstr "" +"これを計算するには、ユーザが入力した単語のリストを文字列の配列として渡してか" +"ら、`runRWS`を使って結果の`RWS`を計算します。" #. type: Fenced code block (haskell) #: text/chapter11.md:852 @@ -7739,8 +8038,10 @@ msgid "" "argument and returns a data structure containing the log, the result, and " "the final state." msgstr "" -"`runRWS`は`runReader`、`runWriter`、`runState`を組み合わせたように見えます。\n" -"引数として大域的な構成及び初期状態を取り、ログ、結果、最終的な状態を含むデータ構造を返します。" +"`runRWS`は`runReader`、`runWriter`、`runState`を組み合わせたように見えま" +"す。\n" +"引数として大域的な構成及び初期状態を取り、ログ、結果、最終的な状態を含むデー" +"タ構造を返します。" #. type: Plain text #: text/chapter11.md:861 @@ -7806,7 +8107,8 @@ msgid "" "argument to the functions which interact with it. An `Interface` can be " "created using the `createConsoleInterface` function:" msgstr "" -"`Interface`型はコンソールの制御子を表しており、コンソールとやり取りする関数への引数として渡されます。\n" +"`Interface`型はコンソールの制御子を表しており、コンソールとやり取りする関数へ" +"の引数として渡されます。\n" "`createConsoleInterface`関数を使用すると`Interface`を作成できます。" #. type: Fenced code block (haskell) @@ -7880,8 +8182,10 @@ msgid "" "run the `game` action (in the `RWS` monad), passing the game environment and " "current game state." msgstr "" -"この動作が最初に行うことは、`Data.String`モジュールの `split`関数を使用して、ユーザーの入力を単語に分割することです。\n" -"それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`モナドで)`game`動作を実行しています。" +"この動作が最初に行うことは、`Data.String`モジュールの `split`関数を使用して、" +"ユーザーの入力を単語に分割することです。\n" +"それから、ゲームの環境と現在のゲームの状態を渡し、 `runRWS`を使用して(`RWS`" +"モナドで)`game`動作を実行しています。" #. type: Plain text #: text/chapter11.md:907 @@ -7893,16 +8197,21 @@ 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" -"最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新し、`prompt`動作を使ってプロンプトを再び表示しています。" +"純粋な計算であるゲームロジックを実行するには、画面に全てのログ文言を出力し" +"て、ユーザに次のコマンドのためのプロンプトを表示する必要があります。\n" +"`for_`動作が(`List String`型の)ログを走査し、コンソールにその内容を出力する" +"ために使われています。\n" +"最後に`setLineHandler`を使って行制御関数を更新することでゲームの状態を更新" +"し、`prompt`動作を使ってプロンプトを再び表示しています。" #. type: Plain text #: text/chapter11.md:909 msgid "" "The `runGame` function finally attaches the initial line handler to the " "console interface and displays the initial prompt:" -msgstr "`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付けて、初期プロンプトを表示します。" +msgstr "" +"`runGame`関数は最終的にコンソールインターフェイスに最初の行制御子を取り付け" +"て、初期プロンプトを表示します。" #. type: Fenced code block (haskell) #: text/chapter11.md:910 @@ -7929,8 +8238,10 @@ msgid "" "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" -"このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用しています。" +"(難しい)`RWS`モナドの ` Writer`コンポーネントは、エラー文言とお知らせ文言の" +"2つの種類の文言のために使われています。\n" +"このため、コードの幾つかの箇所では、エラーの場合を扱うためにcase式を使用して" +"います。" #. type: Plain text #: text/chapter11.md:920 @@ -8013,7 +8324,10 @@ msgid "" "module provides several other options." msgstr "" "最初の引数は`optparse`ライブラリを設定するために使用されます。\n" -"今回の場合、アプリケーションが引数なしで走らされたときは、(「missing argument」エラーを表示する代わりに)`OP.prefs OP.showHelpOnEmpty`を使って使用方法の文言を表示するように設定していますが、`Options.Applicative.Builder`モジュールには他にも幾つかの選択肢を提供しています。" +"今回の場合、アプリケーションが引数なしで走らされたときは、(「missing " +"argument」エラーを表示する代わりに)`OP.prefs OP.showHelpOnEmpty`を使って使用" +"方法の文言を表示するように設定していますが、`Options.Applicative.Builder`モ" +"ジュールには他にも幾つかの選択肢を提供しています。" #. type: Plain text #: text/chapter11.md:940 @@ -8080,9 +8394,12 @@ msgid "" "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`の構成に、チートモードを有効にする新しいコマンドラインフラグ`-c`を追加してください。\n" -"チートモードが有効になっていない場合、前の演習の`cheat`コマンドは禁止されます。" +"(普通)`GameEnvironment`レコードに新しい真偽値のプロパティ`cheatMode`を追加" +"してください。\n" +"また、`optparse`の構成に、チートモードを有効にする新しいコマンドラインフラグ" +"`-c`を追加してください。\n" +"チートモードが有効になっていない場合、前の演習の`cheat`コマンドは禁止されま" +"す。" #. type: Plain text #: text/chapter11.md:966 @@ -8092,7 +8409,8 @@ msgid "" "and the `Effect` monad to build a front-end using the console." msgstr "" "この章ではこれまで学んできた技術を実践的に実演しました。\n" -"モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロントエンドを構築するための`Effect`モナドがそれです。" +"モナド変換子を使用したゲームの純粋な仕様の構築、コンソールを使用したフロント" +"エンドを構築するための`Effect`モナドがそれです。" #. type: Plain text #: text/chapter11.md:968 @@ -8117,10 +8435,13 @@ msgid "" "and `MonadPlus` to build useful monads by combining standard monad " "transformers." msgstr "" -"モナド変換子によって命令型のスタイルで安全なコードを書けることが分かりました。\n" +"モナド変換子によって命令型のスタイルで安全なコードを書けることが分かりまし" +"た。\n" "このスタイルでは型システムによって作用が追跡されています。\n" -"加えて、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供し、これによりコードの再利用が可能になりました。\n" -"標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のような標準的な抽象化を使用して、役に立つモナドを構築できました。" +"加えて、型クラスはモナドが提供する動作へと抽象化する強力な方法を提供し、これ" +"によりコードの再利用が可能になりました。\n" +"標準的なモナド変換子を組み合わせることにより、`Alternative`や`MonadPlus`のよ" +"うな標準的な抽象化を使用して、役に立つモナドを構築できました。" #. type: Plain text #: text/chapter11.md:971 @@ -8130,7 +8451,8 @@ msgid "" "kinded polymorphism and multi-parameter type classes." msgstr "" "モナド変換子は表現力の高いコードの優れた実演となっています。\n" -"これは高階多相や多変数型クラスなどの高度な型システムの機能を利用することによって記述できるものです。" +"これは高階多相や多変数型クラスなどの高度な型システムの機能を利用することに" +"よって記述できるものです。" #. type: Title # #: text/chapter12.md:1 @@ -8170,8 +8492,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 @@ -8182,9 +8507,11 @@ msgid "" "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" -"ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありません。" +"ほとんどの演習はブラウザを対象にしているので、この章には単体試験はありませ" +"ん。" #. type: Title ## #: text/chapter12.md:18 @@ -8203,7 +8530,8 @@ msgid "" msgstr "" "`Example/Rectangle.purs`ファイルには簡単な導入例が含まれています。\n" "この例ではキャンバスの中心に青い四角形を1つ描画します。\n" -"このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas APIを扱うための`Effect`モナドの動作を含む`Graphics.Canvas`モジュールをインポートします。" +"このモジュールへは、`Effect`モジュールからの`Effect`型と、Canvas APIを扱うた" +"めの`Effect`モナドの動作を含む`Graphics.Canvas`モジュールをインポートします。" #. type: Plain text #: text/chapter12.md:23 @@ -8211,7 +8539,10 @@ msgid "" "The `main` action starts, like in the other modules, by using the " "`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`動作を使ってキャンバスオブジェクトへの参照を取得し、`getContext2D`動作を使ってキャンバスの2D描画文脈にアクセスします。" +msgstr "" +"他のモジュールでも同様ですが、`main`動作は最初に`getCanvasElementById`動作を" +"使ってキャンバスオブジェクトへの参照を取得し、`getContext2D`動作を使ってキャ" +"ンバスの2D描画文脈にアクセスします。" #. type: Plain text #: text/chapter12.md:25 @@ -8238,8 +8569,10 @@ msgid "" "appropriate error message." msgstr "" "*補足*:この`unsafePartial`の呼び出しは必須です。\n" -"これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと照合するためです。\n" -"ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子と照合させ、適切なエラー文言を提供したほうがよいでしょう。" +"これは`getCanvasElementById`の結果のパターン照合部分で、`Just`値構築子のみと" +"照合するためです。\n" +"ここではこれで問題ありませんが、恐らく実際の製品のコードでは`Nothing`値構築子" +"と照合させ、適切なエラー文言を提供したほうがよいでしょう。" #. type: Plain text #: text/chapter12.md:33 @@ -8278,7 +8611,9 @@ msgid "" "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`はキャンバスの状態を管理し、原始的な図形を描画したり、スタイルや色を設定したり、座標変換を適用したりするための手段を提供します。" +msgstr "" +"グラフィックス文脈`ctx`はキャンバスの状態を管理し、原始的な図形を描画したり、" +"スタイルや色を設定したり、座標変換を適用したりするための手段を提供します。" #. type: Plain text #: text/chapter12.md:45 @@ -8287,8 +8622,10 @@ 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" -"より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がより簡単です。" +"話を進めると、`setFillStyle`動作を使うことで塗り潰しスタイルを濃い青に設定で" +"きます。\n" +"より長い16進数記法の`#0000FF`も青には使えますが、単純な色については略記法がよ" +"り簡単です。" #. type: Fenced code block (haskell) #: text/chapter12.md:46 @@ -8302,7 +8639,8 @@ 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" +"`setFillStyle`動作がグラフィックス文脈を引数として取っていることに注意してく" +"ださい。\n" "これは`Graphics.Canvas`ではよくあるパターンです。" #. type: Plain text @@ -8328,9 +8666,11 @@ msgid "" "graphics context and a record that provides the position and size of the " "rectangle:" msgstr "" -"`fillPath`はグラフィックスの文脈と描画するパスを構築する他の動作を引数に取ります。\n" +"`fillPath`はグラフィックスの文脈と描画するパスを構築する他の動作を引数に取り" +"ます。\n" "`rect`動作を使うとパスを構築できます。\n" -"`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを取ります。" +"`rect`はグラフィックスの文脈と矩形の位置及びサイズを格納するレコードを取りま" +"す。" #. type: Fenced code block (haskell) #: text/chapter12.md:60 @@ -8358,7 +8698,9 @@ msgstr "$ spago bundle-app --main Example.Rectangle --to dist/Main.js\n" 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`ファイルを開き、このコードによってキャンバスの中央に青い四角形が描画されていることを確認してみましょう。" +msgstr "" +"それでは `html/index.html`ファイルを開き、このコードによってキャンバスの中央" +"に青い四角形が描画されていることを確認してみましょう。" #. type: Title ## #: text/chapter12.md:72 @@ -8375,7 +8717,8 @@ msgid "" msgstr "" "パスを描画する方法は他にもあります。\n" "`arc`関数は円弧を描画します。\n" -"`moveTo`関数、`lineTo`関数、`closePath`関数は断片的な線分のパスを描画できます。" +"`moveTo`関数、`lineTo`関数、`closePath`関数は断片的な線分のパスを描画できま" +"す。" #. type: Plain text #: text/chapter12.md:77 @@ -8419,7 +8762,9 @@ 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." -msgstr "`x`と`y`プロパティは左上隅の位置を表しており、`w`と`h`のプロパティはそれぞれ幅と高さを表しています。" +msgstr "" +"`x`と`y`プロパティは左上隅の位置を表しており、`w`と`h`のプロパティはそれぞれ" +"幅と高さを表しています。" #. type: Plain text #: text/chapter12.md:92 @@ -8456,7 +8801,9 @@ msgstr "" msgid "" "Here, the `x` and `y` properties represent the center point, `r` is the " "radius, `start` and `end` represent the endpoints of the arc in radians." -msgstr "ここで、`x`と`y`プロパティは弧の中心、`r`は半径、`start`と`end`は弧の両端の角度を弧度法で表しています。" +msgstr "" +"ここで、`x`と`y`プロパティは弧の中心、`r`は半径、`start`と`end`は弧の両端の角" +"度を弧度法で表しています。" #. type: Plain text #: text/chapter12.md:106 @@ -8466,7 +8813,8 @@ msgid "" "circle is flipped vertically since the y-axis increases towards the bottom " "of the canvas:" msgstr "" -"例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰します。\n" +"例えばこのコードは中心が`(300, 300)`に中心があり半径`50`の円弧を塗り潰しま" +"す。\n" "弧は1回転のうち2/3ラジアン分あります。\n" "単位円が上下逆様になっている点に注意してください。\n" "これはy軸がキャンバスの下向きに伸びるためです。" @@ -8499,7 +8847,8 @@ msgid "" "This means we can write row-polymorphic functions acting on either type of " "record." msgstr "" -"`Rectangle`レコード型と`Arc`レコード型の両方共、`Number`型の`x`と`y`というプロパティを含んでいますね。\n" +"`Rectangle`レコード型と`Arc`レコード型の両方共、`Number`型の`x`と`y`というプ" +"ロパティを含んでいますね。\n" "どちらの場合でもこの組は点を表しています。\n" "つまり、何れのレコード型にも作用する行多相な関数を書けます。" @@ -8508,7 +8857,9 @@ msgstr "" msgid "" "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`関数が定義されています。" +msgstr "" +"例えば`Shapes`モジュールでは`x`と`y`のプロパティを変更し図形を並行移動する" +"`translate`関数が定義されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:121 @@ -8550,7 +8901,9 @@ msgstr "" msgid "" "The `translate` function can be used with both the `Rectangle` and `Arc` " "records, as seen in the `Shapes` example." -msgstr "`Shapes`の例からわかるように、`translate`関数は`Rectangle`レコードと`Arc`レコード双方に対して使えます。" +msgstr "" +"`Shapes`の例からわかるように、`translate`関数は`Rectangle`レコードと`Arc`レ" +"コード双方に対して使えます。" #. type: Plain text #: text/chapter12.md:132 @@ -8624,7 +8977,9 @@ msgstr "" msgid "" "(Easy) Experiment with the `strokePath` and `setStrokeStyle` functions in " "each example so far." -msgstr "(簡単)これまでの各例について、`strokePath`関数や`setStrokeStyle`関数を使ってみましょう。" +msgstr "" +"(簡単)これまでの各例について、`strokePath`関数や`setStrokeStyle`関数を使っ" +"てみましょう。" #. type: Bullet: ' 1. ' #: text/chapter12.md:158 @@ -8635,8 +8990,10 @@ msgid "" "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. ' @@ -8729,7 +9086,8 @@ msgid "" "canvas manipulation. The example renders one hundred randomly generated " "circles onto the canvas." msgstr "" -"`Example/Random.purs`ファイルには、`Effect`モナドを使って2種類の副作用を綴じ合わせる例が含まれています。\n" +"`Example/Random.purs`ファイルには、`Effect`モナドを使って2種類の副作用を綴じ" +"合わせる例が含まれています。\n" "1つの副作用は乱数生成で、もう1つはキャンバスの操作です。\n" "この例では無作為に生成された円をキャンバスに100個描画します。" @@ -8738,7 +9096,9 @@ msgstr "" msgid "" "The `main` action obtains a reference to the graphics context as before and " "then sets the stroke and fill styles:" -msgstr "`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗り潰しのスタイルを設定します。" +msgstr "" +"`main`動作ではこれまでのようにグラフィックス文脈への参照を取得し、線描きと塗" +"り潰しのスタイルを設定します。" #. type: Fenced code block (haskell) #: text/chapter12.md:188 @@ -8751,7 +9111,9 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:style}}\n" msgid "" "Next, the code uses the `for_` function to loop over the integers between " "`0` and `100`:" -msgstr "次のコードでは`for_`動作を使って`0`から`100`までの整数について反復しています。" +msgstr "" +"次のコードでは`for_`動作を使って`0`から`100`までの整数について反復していま" +"す。" #. type: Fenced code block (haskell) #: text/chapter12.md:194 @@ -8766,7 +9128,8 @@ msgid "" "numbers distributed between `0` and `1`. These numbers represent the `x` and " "`y` coordinates and the radius of a circle:" msgstr "" -"各繰り返しで、do記法ブロックは`0`と`1`の間に分布する3つの乱数を生成することから始まります。\n" +"各繰り返しで、do記法ブロックは`0`と`1`の間に分布する3つの乱数を生成することか" +"ら始まります。\n" "これらの数はそれぞれ`x`座標、`y`座標、半径`r`を表しています。" #. type: Fenced code block (haskell) @@ -8780,7 +9143,9 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Random.purs:random}}\n" 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`を作成し、最後に現在のスタイルに従って円弧を塗り潰し線描きします。" +msgstr "" +"次のコードでは各円について、これらの変数に基づいて`Arc`を作成し、最後に現在の" +"スタイルに従って円弧を塗り潰し線描きします。" #. type: Fenced code block (haskell) #: text/chapter12.md:206 @@ -8872,14 +9237,18 @@ msgstr "" msgid "" "The `translate` action performs a translation whose components are specified " "by the properties of the `TranslateTransform` record." -msgstr "`translate`動作は`TranslateTransform`レコードのプロパティで指定した大きさだけ平行移動します。" +msgstr "" +"`translate`動作は`TranslateTransform`レコードのプロパティで指定した大きさだけ" +"平行移動します。" #. type: Plain text #: text/chapter12.md:245 msgid "" "The `rotate` action rotates around the origin through some number of radians " "specified by the first argument." -msgstr "`rotate`動作は最初の引数で指定されたラジアンの数値に応じて、原点を中心として回転します。" +msgstr "" +"`rotate`動作は最初の引数で指定されたラジアンの数値に応じて、原点を中心として" +"回転します。" #. type: Plain text #: text/chapter12.md:247 @@ -8905,7 +9274,9 @@ msgstr "" msgid "" "Any shapes rendered after these actions have been invoked will automatically " "have the appropriate transformation applied." -msgstr "これらの動作が呼び出された後に描画される図形は、自動的に適切な座標変換が適用されます。" +msgstr "" +"これらの動作が呼び出された後に描画される図形は、自動的に適切な座標変換が適用" +"されます。" #. type: Plain text #: text/chapter12.md:253 @@ -8915,8 +9286,10 @@ msgid "" "if multiple transformations applied after one another, then their effects " "are actually applied in reverse:" msgstr "" -"実際には、これらの関数の各作用は、文脈の現在の変換行列に対して変換行列を*右から乗算*していきます。\n" -"つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されていきます。" +"実際には、これらの関数の各作用は、文脈の現在の変換行列に対して変換行列を*右か" +"ら乗算*していきます。\n" +"つまり、もしある作用の変換をしていくと、その作用は実際には逆順に適用されてい" +"きます。" #. type: Fenced code block (haskell) #: text/chapter12.md:254 @@ -8941,7 +9314,9 @@ msgstr "" msgid "" "The effect of this sequence of actions is that the scene is rotated, then " "scaled, and finally translated." -msgstr "この一連の動作の作用では、まずシーンが回転され、それから拡大縮小され、最後に平行移動されます。" +msgstr "" +"この一連の動作の作用では、まずシーンが回転され、それから拡大縮小され、最後に" +"平行移動されます。" #. type: Title ## #: text/chapter12.md:265 @@ -8954,7 +9329,9 @@ msgstr "文脈の保存" msgid "" "A common use case is to render some subset of the scene using a " "transformation and then reset the transformation." -msgstr "座標変換を使ってシーンの一部を描画し、それからその変換を元に戻す、という使い方はよくあります。" +msgstr "" +"座標変換を使ってシーンの一部を描画し、それからその変換を元に戻す、という使い" +"方はよくあります。" #. type: Plain text #: text/chapter12.md:270 @@ -8993,7 +9370,10 @@ msgid "" "The `save` action pushes the current state of the context (including the " "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`動作はスタックの一番上の状態をポップし、文脈の状態を復元します。" +msgstr "" +"`save`動作は現在の文脈の状態(現在の変換行列や描画スタイル)をスタックにプッ" +"シュし、`restore`動作はスタックの一番上の状態をポップし、文脈の状態を復元しま" +"す。" #. type: Plain text #: text/chapter12.md:284 @@ -9004,8 +9384,10 @@ msgid "" "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 @@ -9029,7 +9411,10 @@ msgid "" "In the interest of abstracting over common use cases using higher-order " "functions, the `canvas` library provides the `withContext` function, which " "performs some canvas action while preserving the original context state:" -msgstr "こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元の文脈状態を保存しつつ幾つかのキャンバス動作を実行する`withContext`関数が提供されています。" +msgstr "" +"こういったよくある高階関数の使われ方の抽象化として、`canvas`ライブラリでは元" +"の文脈状態を保存しつつ幾つかのキャンバス動作を実行する`withContext`関数が提供" +"されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:295 @@ -9087,7 +9472,9 @@ msgstr "" msgid "" "The `Effect.Ref` module provides a type constructor for global mutable " "references and an associated effect:" -msgstr "`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及びそれに紐付く作用を提供します。" +msgstr "" +"`Effect.Ref`モジュールでは、大域的に変更可能な参照のための型構築子、及びそれ" +"に紐付く作用を提供します。" #. type: Fenced code block (text) #: text/chapter12.md:317 @@ -9119,14 +9506,17 @@ msgstr "" msgid "" "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`を使う例が含まれます。" +msgstr "" +"`Example/Refs.purs`ファイルには `canvas`要素上のマウスクリックを追跡するのに " +"`Ref`を使う例が含まれます。" #. type: Plain text #: text/chapter12.md:329 msgid "" "The code starts by creating a new reference containing the value `0` by " "using the `new` action:" -msgstr "このコードでは最初に`new`動作を使って値`0`を含む新しい参照を作成しています。" +msgstr "" +"このコードでは最初に`new`動作を使って値`0`を含む新しい参照を作成しています。" #. type: Fenced code block (haskell) #: text/chapter12.md:330 @@ -9139,7 +9529,9 @@ msgstr "{{#include ../exercises/chapter12/src/Example/Refs.purs:clickCount}}\n" msgid "" "Inside the click event handler, the `modify` action is used to update the " "click count, and the updated value is returned." -msgstr "クリックイベント制御子の内部では、`modify`動作を使用してクリック数を更新し、更新された値が返されています。" +msgstr "" +"クリックイベント制御子の内部では、`modify`動作を使用してクリック数を更新し、" +"更新された値が返されています。" #. type: Fenced code block (haskell) #: text/chapter12.md:336 @@ -9166,7 +9558,10 @@ msgid "" "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`を使用しており、それから一連の変換を適用しています(変換が下から上に適用されることを思い出してください)。" +msgstr "" +"この動作では元の変換を保存するために`withContext`を使用しており、それから一連" +"の変換を適用しています(変換が下から上に適用されることを思い出してくださ" +"い)。" #. type: Bullet: '- ' #: text/chapter12.md:352 @@ -9230,7 +9625,10 @@ msgid "" "(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`作用を使用して、マウスがクリックされたときに、キャンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してください。" +msgstr "" +"(普通)`Random`作用と`Dom`作用を使用して、マウスがクリックされたときに、キャ" +"ンバスに無作為な位置、色、半径の円を描画するアプリケーションを作成してくださ" +"い。" #. type: Bullet: ' 1. ' #: text/chapter12.md:366 @@ -9239,7 +9637,8 @@ msgid "" "point with specified coordinates. _Hint_: use a translation to first " "translate the scene to the origin." msgstr "" -"(普通)指定された座標の点を中心として回転させることでシーンを変換する関数を書いてください。\n" +"(普通)指定された座標の点を中心として回転させることでシーンを変換する関数を" +"書いてください。\n" "*手掛かり*:変換を使い、最初にシーンを原点まで平行移動しましょう。" #. type: Title ## @@ -9266,8 +9665,10 @@ msgid "" "process is iterated some number of times, starting with the initial sequence " "of letters." msgstr "" -"1つのL-Systemは*アルファベット*、つまりアルファベット由来の文字の初期の並びと、*生成規則*の集合で定義されます。\n" -"各生成規則は、アルファベットの文字を取り、それを置き換える文字の並びを返します。\n" +"1つのL-Systemは*アルファベット*、つまりアルファベット由来の文字の初期の並び" +"と、*生成規則*の集合で定義されます。\n" +"各生成規則は、アルファベットの文字を取り、それを置き換える文字の並びを返しま" +"す。\n" "この処理は文字の初期の並びから始まり、複数回繰り返されます。" #. type: Plain text @@ -9276,7 +9677,9 @@ msgid "" "If each letter of the alphabet is associated with some instruction to " "perform on the canvas, the L-system can be rendered by following the " "instructions in order." -msgstr "もしアルファベットの各文字がキャンバス上で実行される命令と対応付けられていれば、その指示に順番に従うことでL-Systemを描画できます。" +msgstr "" +"もしアルファベットの各文字がキャンバス上で実行される命令と対応付けられていれ" +"ば、その指示に順番に従うことでL-Systemを描画できます。" #. type: Plain text #: text/chapter12.md:376 @@ -9285,7 +9688,8 @@ msgid "" "`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) @@ -9405,9 +9809,11 @@ msgid "" "Well, it needs to take values like `initial` and `productions` as arguments, " "as well as a function that can render a letter of the alphabet to the canvas." msgstr "" -"これで、この形式の仕様を受け取ってキャンバスに描画する関数`lsystem`を実装できます。\n" +"これで、この形式の仕様を受け取ってキャンバスに描画する関数`lsystem`を実装でき" +"ます。\n" "`lsystem`はどのような型を持っているべきでしょうか。\n" -"`initial`や`productions`のような値だけでなく、アルファベットの文字をキャンバスに描画できる関数を引数に取る必要があります。" +"`initial`や`productions`のような値だけでなく、アルファベットの文字をキャンバ" +"スに描画できる関数を引数に取る必要があります。" #. type: Plain text #: text/chapter12.md:422 @@ -9446,7 +9852,8 @@ msgid "" "right in the case of the letter `R`, and moving forward in the case of a " "letter `F`." msgstr "" -"3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行することによって*解釈*する関数を表します。\n" +"3番目の引数は、アルファベットの文字を取り、キャンバス上の幾つかの動作を実行す" +"ることによって*解釈*する関数を表します。\n" "この例では、文字`L`は左回転、文字`R`で右回転、文字`F`は前進を意味します。" #. type: Plain text @@ -9496,10 +9903,13 @@ msgid "" "function should work for any type of state, so we will represent it using " "the type variable `s`." msgstr "" -"次に気付くこととしては、「左回転」と「右回転」のような命令を実装するためには、幾つかの状態を管理する必要があります。\n" -"具体的に言えば、その時点でパスが動いている方向を状態として持たなければなりません。\n" +"次に気付くこととしては、「左回転」と「右回転」のような命令を実装するために" +"は、幾つかの状態を管理する必要があります。\n" +"具体的に言えば、その時点でパスが動いている方向を状態として持たなければなりま" +"せん。\n" "計算を通じて状態を渡すように関数を変更する必要があります。\n" -"ここでも`lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数`s`を使用してそれを表しています。" +"ここでも`lsystem`関数は状態がどんな型でも動作したほうがよいので、型変数`s`を" +"使用してそれを表しています。" #. type: Plain text #: text/chapter12.md:450 @@ -9675,7 +10085,8 @@ msgid "" "`concatMap` allowed us to communicate our ideas concisely." msgstr "" "これだけです。\n" -"`foldM`や`concatMap`のような高階関数を使うと、アイデアを簡潔に表現できるのです。" +"`foldM`や`concatMap`のような高階関数を使うと、アイデアを簡潔に表現できるので" +"す。" #. type: Plain text #: text/chapter12.md:510 @@ -9687,7 +10098,8 @@ msgid "" msgstr "" "しかし、話はこれで終わりではありません。\n" "ここで与えた型は、実際はまだ特殊化されすぎています。\n" -"この定義ではキャンバスの操作が実装のどこにも使われていないことに注目してください。\n" +"この定義ではキャンバスの操作が実装のどこにも使われていないことに注目してくだ" +"さい。\n" "それに、全く`Effecta`モナドの構造を利用していません。\n" "実際には、この関数は*どんな*モナド`m`についても動作します。" @@ -9715,9 +10127,12 @@ msgid "" "or multiple return values. The reader is encouraged to try writing L-systems " "that use these various types of side-effect." msgstr "" -"この型で書かれていることは、この解釈関数はモナド`m`が持つ任意の副作用を完全に自由に持つことができる、ということだと理解できます。\n" -"キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれませんし、失敗や複数の戻り値に対応しているかもしれません。\n" -"こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めします。" +"この型で書かれていることは、この解釈関数はモナド`m`が持つ任意の副作用を完全に" +"自由に持つことができる、ということだと理解できます。\n" +"キャンバスに描画したり、またはコンソールに情報を出力したりするかもしれません" +"し、失敗や複数の戻り値に対応しているかもしれません。\n" +"こういった様々な型の副作用を使ったL-Systemを記述してみることを読者にお勧めし" +"ます。" #. type: Plain text #: text/chapter12.md:520 @@ -9732,7 +10147,8 @@ msgstr "" "この関数は実装からデータを分離することの威力を示す良い例となっています。\n" "この手法の利点は、複数の異なる方法でデータを解釈できることです。\n" "さらに`lsystem`を2つの小さな関数へと分解できます。\n" -"1つ目は`concatMap`の適用の繰り返しを使って文を構築するもの、2つ目は`foldM`を使って文を解釈するものです。\n" +"1つ目は`concatMap`の適用の繰り返しを使って文を構築するもの、2つ目は`foldM`を" +"使って文を解釈するものです。\n" "これは読者の演習として残しておきます。" #. type: Plain text @@ -9774,7 +10190,9 @@ msgstr "{{#include ../exercises/chapter12/src/Example/LSystem.purs:interpretLR}} 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:" -msgstr "文字`F`(前進)を解釈するには、次のようにパスの新しい位置を計算し、線分を描画し、状態を更新します。" +msgstr "" +"文字`F`(前進)を解釈するには、次のようにパスの新しい位置を計算し、線分を描画" +"し、状態を更新します。" #. type: Fenced code block (haskell) #: text/chapter12.md:535 @@ -9791,13 +10209,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`動作を使用するだけです。" +msgstr "" +"このL-Systemを描画するには、次のような`strokePath`動作を使用するだけです。" #. type: Fenced code block (haskell) #: text/chapter12.md:543 @@ -9864,7 +10285,9 @@ msgid "" "`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. ' @@ -9983,7 +10406,8 @@ msgid "" "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 APIを使う方法について学びました。\n" +"この章では、`canvas`ライブラリを使用することにより、PureScriptからHTML5 " +"Canvas APIを使う方法について学びました。\n" "また、これまで学んできた多くの手法からなる実用的な実演を見ました。\n" "マップや畳み込み、レコードと行多相、副作用を扱うための`Effect`モナドです。" @@ -10025,7 +10449,9 @@ msgid "" "This approach is taken in the `drawing` package, and it brings the " "flexibility of manipulating the scene as data in various ways before " "rendering." -msgstr "この手法は`drawing`パッケージで取られており、描画前に様々な方法でシーンをデータとして操作できる柔軟性を齎しています。" +msgstr "" +"この手法は`drawing`パッケージで取られており、描画前に様々な方法でシーンをデー" +"タとして操作できる柔軟性を齎しています。" #. type: Plain text #: text/chapter12.md:612 @@ -10033,7 +10459,10 @@ msgid "" "For examples of games rendered to the canvas, see the \"Behavior\" and " "\"Signal\" recipes in the [cookbook](https://github.com/JordanMartinez/" "purescript-cookbook/blob/master/README.md#recipes)." -msgstr "キャンバスに描画されるゲームの例については[cookbook](https://github.com/JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の「Behavior」と「Signal」のレシピを見てください。" +msgstr "" +"キャンバスに描画されるゲームの例については[cookbook](https://github.com/" +"JordanMartinez/purescript-cookbook/blob/master/README.md#recipes)の" +"「Behavior」と「Signal」のレシピを見てください。" #. type: Title # #: text/chapter13.md:1 @@ -10146,7 +10575,8 @@ msgid "" "the appropriate values. However, everything we need to know about the " "`merge` function can be summarized by this property:" msgstr "" -"典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成し、結果が正しい値と等しいことを確認することでテストを実施します。\n" +"典型的なテストスイートでは、手作業でこのような小さなテスト項目を幾つも作成" +"し、結果が正しい値と等しいことを確認することでテストを実施します。\n" "しかし、`merge`関数について知る必要があるものは全て、この性質に要約できます。" #. type: Bullet: '- ' @@ -10191,9 +10621,12 @@ msgid "" "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個の無作為なテスト項目を生成しても、ライブラリはこの性質を反証できません。" +"このコードを実行すると、`quickcheck`は無作為な入力`xs`と`ys`を生成してこの関" +"数に渡すことで、主張した性質を反証しようとします。\n" +"何らかの入力に対して関数が`false`を返した場合、性質は正しくなく、ライブラリは" +"エラーを発生させます。\n" +"幸いなことに、次のように100個の無作為なテスト項目を生成しても、ライブラリはこ" +"の性質を反証できません。" #. type: Fenced code block (text) #: text/chapter13.md:46 @@ -10241,7 +10674,9 @@ msgstr "" msgid "" "As we can see, this error message is not very helpful, but it can be " "improved with a little work." -msgstr "見ての通りこのエラー文言ではあまり役に立ちませんが、少し工夫するだけで改良できます。" +msgstr "" +"見ての通りこのエラー文言ではあまり役に立ちませんが、少し工夫するだけで改良で" +"きます。" #. type: Title ## #: text/chapter13.md:65 @@ -10280,7 +10715,9 @@ msgstr "" msgid "" "This time, if we modify the code to introduce a bug, we see our improved " "error message after the first failed test case:" -msgstr "このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗したときに改良されたエラー文言が表示されます。" +msgstr "" +"このとき、もしバグを混入するようにコードを変更すると、最初のテスト項目が失敗" +"したときに改良されたエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter13.md:80 @@ -10327,7 +10764,8 @@ msgstr "" msgid "" "(Easy) Add an appropriate error message to the remaining property for " "`merge`." -msgstr "(簡単)`merge`の残りの性質に対して、適切なエラー文言を追加してください。" +msgstr "" +"(簡単)`merge`の残りの性質に対して、適切なエラー文言を追加してください。" #. type: Title ## #: text/chapter13.md:95 @@ -10357,7 +10795,9 @@ msgstr "mergePoly :: forall a. Ord a => Array a -> Array a -> Array a\n" msgid "" "If we modify our original test to use `mergePoly` in place of `merge`, we " "see the following error message:" -msgstr "`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエラー文言が表示されます。" +msgstr "" +"`merge`の代わりに `mergePoly`を使うように元のテストを変更すると、次のようなエ" +"ラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter13.md:105 @@ -10385,8 +10825,10 @@ msgid "" "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" +"このような場合、型註釈を使ってコンパイラが特定の型を推論するように強制できま" +"す。\n" "例えば`Array Int`などです。" #. type: Fenced code block (haskell) @@ -10444,7 +10886,9 @@ msgstr "" msgid "" "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`を持っています。" +msgstr "" +"ここで、`ints`関数が不明な型の曖昧さを解消するために使われているため、`xs`と" +"`ys`は型`Array Int`を持っています。" #. type: Bullet: ' 1. ' #: text/chapter13.md:141 @@ -10452,7 +10896,9 @@ msgid "" "(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`を書き、`mergePoly`をその型でテストする性質を追加してください。" +msgstr "" +"(簡単)`xs`と`ys`の型を`Array Boolean`に強制する関数`bools`を書き、" +"`mergePoly`をその型でテストする性質を追加してください。" #. type: Bullet: ' 1. ' #: text/chapter13.md:141 @@ -10462,8 +10908,10 @@ msgid "" "appropriate error message. Your property should use a helper function to fix " "any polymorphic type arguments to either `Int` or `Boolean`." msgstr "" -"(普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエラー文言を含めてQuickCheckの性質を書いてください。\n" -"その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定しなければいけません。" +"(普通)標準関数から(例えば`arrays`パッケージから)1つ関数を選び、適切なエ" +"ラー文言を含めてQuickCheckの性質を書いてください。\n" +"その性質は、補助関数を使って多相型引数を `Int`か `Boolean`のどちらかに固定し" +"なければいけません。" #. type: Title ## #: text/chapter13.md:142 @@ -10476,7 +10924,9 @@ msgstr "任意のデータの生成" msgid "" "Now we will see how the `quickcheck` library can randomly generate test " "cases for our properties." -msgstr "それでは`quickcheck`ライブラリが性質に対するテスト項目をどのように無作為に生成できているのかを見ていきます。" +msgstr "" +"それでは`quickcheck`ライブラリが性質に対するテスト項目をどのように無作為に生" +"成できているのかを見ていきます。" #. type: Plain text #: text/chapter13.md:147 @@ -10531,8 +10981,10 @@ msgid "" "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 @@ -10563,7 +11015,8 @@ msgid "" "action is inferred as `Gen Int`." msgstr "" "ここでは、0から255までの間の整数値であるような型`Byte`を定義しています。\n" -"`Arbitrary`インスタンスは`map`演算子を使って、`intToByte`関数を`arbitrary`動作まで持ち上げています。\n" +"`Arbitrary`インスタンスは`map`演算子を使って、`intToByte`関数を`arbitrary`動" +"作まで持ち上げています。\n" "`arbitrary`動作内部の型は`Gen Int`と推論されます。" #. type: Plain text @@ -10589,8 +11042,10 @@ msgid "" "a newtype representing sorted arrays and write an `Arbitrary` instance that " "generates sorted data:" msgstr "" -"このテストでは、任意の配列`xs`と`ys`を生成しますが、`merge`は整列済みの入力を期待しているので、これらを整列しておかなければなりません。\n" -"一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する`Arbitrary`インスタンスを書くこともできます。" +"このテストでは、任意の配列`xs`と`ys`を生成しますが、`merge`は整列済みの入力を" +"期待しているので、これらを整列しておかなければなりません。\n" +"一方で、整列された配列を表すnewtypeを作成し、整列されたデータを生成する" +"`Arbitrary`インスタンスを書くこともできます。" #. type: Fenced code block (haskell) #: text/chapter13.md:180 @@ -10636,9 +11091,12 @@ msgid "" "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 @@ -10686,7 +11144,8 @@ msgid "" "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) @@ -10736,8 +11195,10 @@ msgid "" "example, we can test that the `member` test always returns `true` after " "inserting a value:" msgstr "" -"型`a`用に使える`Arbitary`インスタンスがあるなら、テストする性質の引数の型として`Tree a`を使えます。\n" -"例えば、`member`による木の確認については、値を挿入した後は常に`true`を返すことをテストできます。" +"型`a`用に使える`Arbitary`インスタンスがあるなら、テストする性質の引数の型とし" +"て`Tree a`を使えます。\n" +"例えば、`member`による木の確認については、値を挿入した後は常に`true`を返すこ" +"とをテストできます。" #. type: Fenced code block (haskell) #: text/chapter13.md:237 @@ -10776,7 +11237,9 @@ msgstr "" msgid "" "(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 "(難しい)木に挿入された値は、どれだけ沢山の挿入があった後でも、その木の構成要素であることを主張する性質を書いてください。" +msgstr "" +"(難しい)木に挿入された値は、どれだけ沢山の挿入があった後でも、その木の構成" +"要素であることを主張する性質を書いてください。" #. type: Title ## #: text/chapter13.md:249 @@ -10793,7 +11256,8 @@ msgid "" "is a higher-order function." msgstr "" "`Merge`モジュールは`merge`関数の別の一般化も定義しています。\n" -"`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を判定します。\n" +"`mergeWith`関数は追加の関数を引数として取り、統合される要素の順序を判定しま" +"す。\n" "つまり`mergeWith`は高階関数です。" #. type: Plain text @@ -10803,7 +11267,8 @@ msgid "" "merge two arrays already in length-increasing order. The result should also " "be in length-increasing order:" msgstr "" -"例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列を統合できます。\n" +"例えば`length`関数を最初の引数として渡し、既に長さの昇順になっている2つの配列" +"を統合できます。\n" "その結果もまた長さの昇順になっているでしょう。" #. type: Fenced code block (haskell) @@ -10833,7 +11298,8 @@ msgid "" "for all three arguments, including the first argument, which is a function." msgstr "" "このような関数をテストするにはどうしたらいいでしょうか。\n" -"理想的には、関数である最初の引数を含めた3つの引数全てについて、値を生成したいところです。" +"理想的には、関数である最初の引数を含めた3つの引数全てについて、値を生成したい" +"ところです。" #. type: Plain text #: text/chapter13.md:268 @@ -10862,9 +11328,11 @@ msgid "" "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`の関数の結果の乱数生成器を取ります。\n" +"`coarbitrary`関数は、型`t`の関数の引数と、型`r`の関数の結果の乱数生成器を取り" +"ます。\n" "この関数引数を使って乱数生成器を*かき乱し*ます。\n" -"つまり、関数の引数を使って乱数生成器の無作為な出力を変更し、結果としているのです。" +"つまり、関数の引数を使って乱数生成器の無作為な出力を変更し、結果としているの" +"です。" #. type: Plain text #: text/chapter13.md:277 @@ -10872,7 +11340,9 @@ msgid "" "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`の関数を与える型クラスインスタンスが存在します。" +msgstr "" +"また、もし関数の定義域が`Coarbitrary`で値域が`Arbitrary`なら、`Arbitrary`の関" +"数を与える型クラスインスタンスが存在します。" #. type: Fenced code block (haskell) #: text/chapter13.md:278 @@ -10888,7 +11358,8 @@ msgid "" "randomly, modifying our tests to take account of the new argument." msgstr "" "実際のところ、引数として関数を取るような性質を記述できます。\n" -"`mergeWith`関数の場合では、新しい引数を考慮するようにテストを修正すると、最初の引数を無作為に生成できます。" +"`mergeWith`関数の場合では、新しい引数を考慮するようにテストを修正すると、最初" +"の引数を無作為に生成できます。" #. type: Plain text #: text/chapter13.md:285 @@ -10902,8 +11373,10 @@ msgid "" msgstr "" "結果が整列されていることは保証できません。\n" "`Ord`インスタンスを持っているとさえ限らないのです。\n" -"しかし、引数として渡す関数`f`に従って結果が整列されていることは期待されます。\n" -"更に、2つの入力配列が`f`に従って整列されている必要がありますので、`sortBy`関数を使って関数`f`が適用されたあとの比較に基づいて`xs`と`ys`を整列します。" +"しかし、引数として渡す関数`f`に従って結果が整列されていることは期待されま" +"す。\n" +"更に、2つの入力配列が`f`に従って整列されている必要がありますので、`sortBy`関" +"数を使って関数`f`が適用されたあとの比較に基づいて`xs`と`ys`を整列します。" #. type: Fenced code block (haskell) #: text/chapter13.md:286 @@ -10972,7 +11445,8 @@ msgid "" "arguments are higher-order functions, and so on." msgstr "" "つまり値や関数だけに制限されません。\n" -"*高階関数*や、引数が高階関数であるような関数やその他諸々もまた、無作為に生成できるのです。" +"*高階関数*や、引数が高階関数であるような関数やその他諸々もまた、無作為に生成" +"できるのです。" #. type: Title ## #: text/chapter13.md:316 @@ -11016,7 +11490,8 @@ msgid "" "of type `Tree a`. If the input value is a `Leaf`, then we will return the " "generator unchanged:" msgstr "" -"型`Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があります。\n" +"型`Tree a`の値が与えられたときに、乱数発生器をかき乱す関数を記述する必要があ" +"ります。\n" "入力値が`Leaf`であれば、そのままにしておく生成器を返します。" #. type: Fenced code block (haskell) @@ -11057,7 +11532,8 @@ msgid "" "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" +"これで、木を引数にとるような関数を引数に含む性質を自由に書くことができるよう" +"になりました。\n" "例えば`Tree`モジュールでは関数`anywhere`が定義されています。\n" "これは述語が引数のどんな部分木についても満たされるかを調べます。" @@ -11122,9 +11598,11 @@ msgid "" "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" +"通常、テストの目的ではテストスイートの`main`動作に`quickCheck`関数の呼び出し" +"が含まれています。\n" "しかし`quickCheck`関数には亜種があり、`quickCheckPure`という名前です。\n" -"副作用を使わない代わりに、入力として乱数の種を取ってテスト結果の配列を返す純粋な関数です。" +"副作用を使わない代わりに、入力として乱数の種を取ってテスト結果の配列を返す純" +"粋な関数です。" #. type: Plain text #: text/chapter13.md:367 @@ -11172,8 +11650,10 @@ msgid "" "cases to generate, and the property to test. If all tests pass, you should " "see an array of `Success` data constructors printed to the console." msgstr "" -"`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を取ります。\n" -"もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出力されます。" +"`quickCheckPure`は乱数の種、生成するテスト項目数、テストする性質の3つの引数を" +"取ります。\n" +"もし全てのテスト項目が成功したら、`Success`データ構築子の配列がコンソールに出" +"力されます。" #. type: Plain text #: text/chapter13.md:386 @@ -11181,7 +11661,9 @@ msgid "" "`quickCheckPure` might be useful in other situations, such as generating " "random input data for performance benchmarks or sample form data for web " "applications." -msgstr "`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションのフォームデータ例を無作為に生成するというような状況で便利かもしれません。" +msgstr "" +"`quickCheckPure`は、性能ベンチマークの入力データ生成や、webアプリケーションの" +"フォームデータ例を無作為に生成するというような状況で便利かもしれません。" #. type: Bullet: ' 1. ' #: text/chapter13.md:392 @@ -11259,7 +11741,9 @@ msgstr "`spago test`を使ってQuickCheckのテストを自動化する方法 msgid "" "We saw how to write properties as functions and how to use the `` " "operator to improve error messages." -msgstr "性質を関数として書く方法とエラー文言を改良する``演算子の使い方を説明しました。" +msgstr "" +"性質を関数として書く方法とエラー文言を改良する``演算子の使い方を説明しまし" +"た。" #. type: Bullet: '- ' #: text/chapter13.md:408 @@ -11267,7 +11751,9 @@ 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 " "properties." -msgstr "`Arbitrary`と`Coarbitrary`型クラスによって定型的なテストコードの自動生成を可能にする方法や、高階な性質のテストを可能にする方法を見ました。" +msgstr "" +"`Arbitrary`と`Coarbitrary`型クラスによって定型的なテストコードの自動生成を可" +"能にする方法や、高階な性質のテストを可能にする方法を見ました。" #. type: Bullet: '- ' #: text/chapter13.md:408 @@ -11302,7 +11788,8 @@ msgid "" "have already seen several examples of domain-specific languages in this book:" msgstr "" "領域特化言語とは、特定の問題領域での開発に適した言語のことです。\n" -"構文及び機能は、その領域内の考え方を表現するに使われるコードの読みやすさを最大化すべく選択されます。\n" +"構文及び機能は、その領域内の考え方を表現するに使われるコードの読みやすさを最" +"大化すべく選択されます。\n" "本書の中では、既に領域特化言語の例を幾つか見てきています。" #. type: Bullet: '- ' @@ -11311,7 +11798,9 @@ msgid "" "The `Game` monad and its associated actions, developed in chapter 11, " "constitute a domain-specific language for the domain of _text adventure game " "development_." -msgstr "第11章で開発された`Game`モナドと関連する動作は、*テキストアドベンチャーゲーム開発*という領域に対しての領域特化言語を構成しています。" +msgstr "" +"第11章で開発された`Game`モナドと関連する動作は、*テキストアドベンチャーゲーム" +"開発*という領域に対しての領域特化言語を構成しています。" #. type: Bullet: '- ' #: text/chapter14.md:11 @@ -11320,7 +11809,8 @@ msgid "" "language for the domain of _generative testing_. Its combinators enable a " "particularly expressive notation for test properties." msgstr "" -"第13章で扱った`quickcheck`パッケージは、*生成的テスティング*の領域に向けた領域特化言語です。\n" +"第13章で扱った`quickcheck`パッケージは、*生成的テスティング*の領域に向けた領" +"域特化言語です。\n" "このコンビネータはテストの性質に対して特に表現力の高い記法を可能にします。" #. type: Plain text @@ -11331,8 +11821,10 @@ msgid "" "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 @@ -11343,7 +11835,8 @@ msgid "" "in small steps." msgstr "" "ここでの実行例はHTML文書を作成するための領域特化言語です。\n" -"正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装を徐々に改善しつつ進めていきます。" +"正しいHTML文書を記述するための型安全な言語を開発することが目的で、素朴な実装" +"を徐々に改善しつつ進めていきます。" #. type: Plain text #: text/chapter14.md:19 @@ -11418,7 +11911,8 @@ msgid "" msgstr "" "`Element`型はHTMLの要素を表します。\n" "各要素は要素名、属性の対の配列と、内容で構成されます。\n" -"内容のプロパティには`Maybe`型を適切に使い、要素が開いている(他の要素やテキストを含む)か閉じているかを示します。" +"内容のプロパティには`Maybe`型を適切に使い、要素が開いている(他の要素やテキス" +"トを含む)か閉じているかを示します。" #. type: Plain text #: text/chapter14.md:46 @@ -11556,8 +12050,10 @@ msgid "" "constructors_, which construct data known to be correct." msgstr "" "最初に導入する手法は単純ですがとても効果的です。\n" -"モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリストを使ってデータ構築子`Element`、`Content`、`Attribute`を隠蔽します。\n" -"そして正しいことが分かっているデータを構築する、いわゆる*スマート構築子*だけをエクスポートします。" +"モジュールの使用者にデータの表現を露出する代わりに、モジュールエクスポートリ" +"ストを使ってデータ構築子`Element`、`Content`、`Attribute`を隠蔽します。\n" +"そして正しいことが分かっているデータを構築する、いわゆる*スマート構築子*だけ" +"をエクスポートします。" #. type: Plain text #: text/chapter14.md:95 @@ -11592,7 +12088,8 @@ msgid "" "to be able to create by applying the `element` function:" msgstr "" "次にHTML要素のためのスマート構築子を作成します。\n" -"この要素は利用者が`element`関数を適用して作成できるようになってほしいものです。" +"この要素は利用者が`element`関数を適用して作成できるようになってほしいもので" +"す。" #. type: Fenced code block (haskell) #: text/chapter14.md:107 @@ -11680,7 +12177,8 @@ msgid "" "constructors." msgstr "" "型構築子とそれに紐付くデータ構築子。\n" -"型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定されます。" +"型名とそれに続くエクスポートされるデータ構築子の括弧で囲まれたリストで指定さ" +"れます。" #. type: Plain text #: text/chapter14.md:141 @@ -11688,8 +12186,10 @@ msgid "" "Here, we export the `Element` _type_, but we do not export its data " "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 @@ -11712,7 +12212,9 @@ msgstr "既にライブラリに幾つもの大きな改良が加わっている 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要素は表現できません(勿論ライブラリが提供する要素名に制限されています)。" +msgstr "" +"不正な名前を持つHTML要素は表現できません(勿論ライブラリが提供する要素名に制" +"限されています)。" #. type: Bullet: '- ' #: text/chapter14.md:148 @@ -11727,7 +12229,8 @@ msgid "" "and provide the following smart constructors:" msgstr "" "`Content`型にとても簡単にこの手法を適用できます。\n" -"単にエクスポートリストから`Content`型のデータ構築子を取り除き、次のスマート構築子を提供します。" +"単にエクスポートリストから`Content`型のデータ構築子を取り除き、次のスマート構" +"築子を提供します。" #. type: Fenced code block (haskell) #: text/chapter14.md:151 @@ -11961,9 +12464,11 @@ msgid "" "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 @@ -11979,7 +12484,9 @@ msgstr "" msgid "" "(Medium) Some HTML attributes, such as `checked` and `disabled`, do not " "require values and may be rendered as _empty attributes_:" -msgstr "(普通)`checked`や`disabled`といったHTML属性は値を要求せず、*空の属性*として書き出せます。" +msgstr "" +"(普通)`checked`や`disabled`といったHTML属性は値を要求せず、*空の属性*として" +"書き出せます。" #. type: Plain text #: text/chapter14.md:257 @@ -12252,7 +12759,8 @@ msgid "" "Write an instance of `IsValue` for your type. Modify the `width` and " "`height` attributes to use your new type." msgstr "" -"(簡単)ピクセルまたはパーセントの何れかの長さを表すデータ型を作成してください。\n" +"(簡単)ピクセルまたはパーセントの何れかの長さを表すデータ型を作成してくださ" +"い。\n" "その型について`IsValue`のインスタンスを書いてください。\n" "この新しい型を使うように`width`と`height`属性を変更してください。" @@ -12263,7 +12771,10 @@ msgid "" "`true` and `false`, we can use a phantom type to encode whether an " "`AttributeKey` represents an _empty attribute_, such as `disabled` or " "`checked`." -msgstr "(難しい)真偽値`true`、`false`用の最上位の表現を定義することで、幻影型を使って`AttributeKey`が`disabled`や`checked`のような*空の属性*を表現しているかどうかをエンコードできます。" +msgstr "" +"(難しい)真偽値`true`、`false`用の最上位の表現を定義することで、幻影型を使っ" +"て`AttributeKey`が`disabled`や`checked`のような*空の属性*を表現しているかどう" +"かをエンコードできます。" #. type: Plain text #: text/chapter14.md:361 @@ -12299,8 +12810,10 @@ msgid "" "notation. This will allow us to structure our HTML documents in a form in " "which the nesting of elements becomes clearer – instead of this:" msgstr "" -"APIに施す最後の変更では、`Content`型をモナドにしてdo記法を使えるようにするために、*Freeモナド*と呼ばれる構造を使っていきます。\n" -"これによって入れ子になった要素がわかりやすくなるような形式でHTML文書を構造化できます。\n" +"APIに施す最後の変更では、`Content`型をモナドにしてdo記法を使えるようにするた" +"めに、*Freeモナド*と呼ばれる構造を使っていきます。\n" +"これによって入れ子になった要素がわかりやすくなるような形式でHTML文書を構造化" +"できます。\n" "以下の代わりに……" #. type: Fenced code block (haskell) @@ -12359,7 +12872,8 @@ msgid "" "actions." msgstr "" "しかし、do記法だけがFreeモナドの恩恵ではありません。\n" -"Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複数の解釈*を持たせることさえできます。" +"Freeモナドがあれば、モナドの動作の*表現*をその*解釈*から分離し、同じ動作に*複" +"数の解釈*を持たせることさえできます。" #. type: Plain text #: text/chapter14.md:394 @@ -12368,8 +12882,10 @@ msgid "" "Free` module. We can find out some basic information about it using PSCi, as " "follows:" msgstr "" -"`Free`モナドは`free`ライブラリの`Control.Monad.Free`モジュールで定義されています。\n" -"PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができます。" +"`Free`モナドは`free`ライブラリの`Control.Monad.Free`モジュールで定義されてい" +"ます。\n" +"PSCiを使うと、次のようにFreeモナドについての基本的な情報を見ることができま" +"す。" #. type: Fenced code block (text) #: text/chapter14.md:395 @@ -12392,7 +12908,8 @@ msgid "" "and returns another type constructor. In fact, the `Free` monad can be used " "to turn any `Functor` into a `Monad`!" msgstr "" -"`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示しています。\n" +"`Free`の種は、引数として型構築子を取り、別の型構築子を返すことを示していま" +"す。\n" "実はなんと、`Free`モナドを使えば任意の`Functor`を`Monad`にできるのです。" #. type: Plain text @@ -12404,7 +12921,8 @@ msgid "" "be `elem` and `text`. We can simply modify our `Content` type as follows:" msgstr "" "モナドの動作の*表現*の定義から始めます。\n" -"これには対応したい各モナド動作について、1つのデータ構築子を持つ`Functor`を作成する必要があります。\n" +"これには対応したい各モナド動作について、1つのデータ構築子を持つ`Functor`を作" +"成する必要があります。\n" "今回の場合、2つのモナドの動作は`elem`と`text`になります。\n" "`Content`型を次のように変更するだけでできます。" @@ -12438,8 +12956,10 @@ msgid "" "in each data constructor." msgstr "" "ここで、この`ContentF`型構築子は以前の`Content`データ型とよく似ています。\n" -"しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引数として取るように変更されています。\n" -"`Functor`インスタンスでは、単に各データ構築子で型`a`の値に関数`f`を適用します。" +"しかし、ここでは型引数`a`を取り、それぞれのデータ構築子は型`a`の値を追加の引" +"数として取るように変更されています。\n" +"`Functor`インスタンスでは、単に各データ構築子で型`a`の値に関数`f`を適用しま" +"す。" #. type: Plain text #: text/chapter14.md:419 @@ -12466,8 +12986,10 @@ msgid "" "`Content` data constructor, we restrict our users to only using the monadic " "actions we provide." msgstr "" -"型同義語の代わりに`newtype`を使用して、使用者に対してライブラリの内部表現を露出することを避けられます。\n" -"`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使用者に制限しています。" +"型同義語の代わりに`newtype`を使用して、使用者に対してライブラリの内部表現を露" +"出することを避けられます。\n" +"`Content`データ構築子を隠すことで、提供しているモナドの動作だけを使うことを使" +"用者に制限しています。" #. type: Plain text #: text/chapter14.md:427 @@ -12513,8 +13035,10 @@ msgid "" "`liftF` function provided by the `Control.Monad.Free` module. Here is its " "type:" msgstr "" -"また、`Content`モナドについての新しいモナドの動作になるよう、`elem`と`text`関数を変更する必要があります。\n" -"これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えます。\n" +"また、`Content`モナドについての新しいモナドの動作になるよう、`elem`と`text`関" +"数を変更する必要があります。\n" +"これには`Control.Monad.Free`モジュールで提供されている `liftF`関数が使えま" +"す。\n" "以下がその型です。" #. type: Fenced code block (haskell) @@ -12530,7 +13054,8 @@ msgid "" "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" +"`liftF`により、何らかの型`a`について、型`f a`の値からFreeモナドの動作を構築で" +"きるようになります。\n" "今回の場合、`ContentF`型構築子のデータ構築子をそのまま使えます。" #. type: Fenced code block (haskell) @@ -12622,8 +13147,10 @@ msgid "" "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" -"実際、ら`m`は安全な*末尾再帰モナド*に対応してため、スタックオーバーフローを心配する必要はありません。" +"*補足*:厳密には、より強い`MonadRec`制約を満たすモナド`m`に制限されていま" +"す。\n" +"実際、ら`m`は安全な*末尾再帰モナド*に対応してため、スタックオーバーフローを心" +"配する必要はありません。" #. type: Plain text #: text/chapter14.md:481 @@ -12641,7 +13168,9 @@ msgid "" "Our new `render` method starts by delegating to a helper function, " "`renderElement`, and using `execWriter` to run our computation in the " "`Writer` monad:" -msgstr "新しい`render`メソッドが開始すると、補助関数 `renderElement`に移譲し、`execWriter`を使って`Writer`モナドで計算します。" +msgstr "" +"新しい`render`メソッドが開始すると、補助関数 `renderElement`に移譲し、" +"`execWriter`を使って`Writer`モナドで計算します。" #. type: Fenced code block (haskell) #: text/chapter14.md:484 @@ -12675,7 +13204,9 @@ msgstr "" msgid "" "The definition of `renderElement` is straightforward, using the `tell` " "action from the `Writer` monad to accumulate several small strings:" -msgstr "`renderElement`の定義は直感的で、複数の小さな文字列を累算するために`Writer`モナドの`tell`動作を使っています。" +msgstr "" +"`renderElement`の定義は直感的で、複数の小さな文字列を累算するために`Writer`モ" +"ナドの`tell`動作を使っています。" #. type: Fenced code block (haskell) #: text/chapter14.md:499 @@ -12781,7 +13312,8 @@ msgstr " renderContentItem :: ContentF (Content Unit) -> Writer String (Con msgid "" "We can implement this function by pattern matching on the two data " "constructors of `ContentF`:" -msgstr "`ContentF`の2つのデータ構築子でパターン照合すればこの関数を実装できます。" +msgstr "" +"`ContentF`の2つのデータ構築子でパターン照合すればこの関数を実装できます。" #. type: Fenced code block (haskell) #: text/chapter14.md:541 @@ -12808,7 +13340,8 @@ msgid "" "represents the remainder of the interpreted computation. We can complete " "each case by returning the `rest` action." msgstr "" -"それぞれの場合において、式`rest`は型`Content Unit`を持っており、解釈された計算の残りを表しています。\n" +"それぞれの場合において、式`rest`は型`Content Unit`を持っており、解釈された計" +"算の残りを表しています。\n" "`rest`動作を返すことでそれぞれの場合を完成できます。" #. type: Plain text @@ -12856,9 +13389,11 @@ msgid "" "the new action using `liftF`. Update the interpretation `renderContentItem` " "to interpret your new constructor appropriately." msgstr "" -"(普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメントを出力する新しい動作`comment`に対応してください。\n" +"(普通)`ContentF`型に新しいデータ構築子を追加して、生成されたHTMLにコメント" +"を出力する新しい動作`comment`に対応してください。\n" "`liftF`を使ってこの新しい動作を実装してください。\n" -"新しい構築子を適切に解釈するように、解釈`renderContentItem`を更新してください。" +"新しい構築子を適切に解釈するように、解釈`renderContentItem`を更新してくださ" +"い。" #. type: Title ## #: text/chapter14.md:573 @@ -12873,15 +13408,19 @@ 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 that returns a non-trivial result." -msgstr "非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナドを構築する威力をお見せしましょう。" +msgstr "" +"非自明な結果を返す新しいモナド動作でこの言語を拡張することで、Freeモナドを構" +"築する威力をお見せしましょう。" #. type: Plain text #: text/chapter14.md:580 @@ -12892,8 +13431,10 @@ msgid "" "document: once at the anchor's definition and once in each hyperlink. " "However, this approach has some basic issues:" msgstr "" -"*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を生成したいとします。\n" -"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めれば、これは達成できます。\n" +"*アンカー*を使用して文書の様々な節へのハイパーリンクが含まれているHTML文書を" +"生成したいとします。\n" +"手作業でアンカーの名前を生成して文書中で少なくとも2回それらを含めれば、これは" +"達成できます。\n" "1つはアンカーの定義自身に、もう1つは各ハイパーリンクにあります。\n" "しかし、この手法には基本的な問題が幾つかあります。" @@ -12913,7 +13454,9 @@ msgid "" "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 "開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい一意な名前を生成するためのモナド動作を提供できます。" +msgstr "" +"開発者が誤ちを犯すことを防ぐために、アンカー名を表す新しい型を導入し、新しい" +"一意な名前を生成するためのモナド動作を提供できます。" #. type: Plain text #: text/chapter14.md:587 @@ -12949,7 +13492,9 @@ msgstr "" msgid "" "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`型クラスのインスタンスを定義します。" +msgstr "" +"次に、属性値に`Name`を使えるよう、新しい型に`IsValue`型クラスのインスタンスを" +"定義します。" #. type: Fenced code block (haskell) #: text/chapter14.md:599 @@ -13111,8 +13656,10 @@ msgid "" "as a type synonym to keep our type signatures short:" msgstr "" "最後に、新しい動作を解釈させるように解釈関数を更新する必要があります。\n" -"以前は計算を解釈するために`Writer String`モナドを使っていましたが、このモナドは新しい名前を生成できないので、何か他のものに切り替えなければなりません。\n" -"`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせられます。\n" +"以前は計算を解釈するために`Writer String`モナドを使っていましたが、このモナド" +"は新しい名前を生成できないので、何か他のものに切り替えなければなりません。\n" +"`WriterT`モナド変換子を`State`モナドと一緒に使うと、必要な作用を組み合わせら" +"れます。\n" "型注釈が短く保たれるよう、この解釈モナドを型同義語として定義できます。" #. type: Fenced code block (haskell) @@ -13139,7 +13686,8 @@ msgid "" "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`と`WriterT`モナドはそれらの動作を抽象化するのに同じ型クラスの構成要素" +"を使うので、どの動作も変更する必要がありません。\n" "必要なのは、`Writer String`への参照全てを`Interp`で置き換えることだけです。\n" "しかし、計算に使われる制御子は変更する必要があります。\n" "単なる`execWriter`の代わりに、`evalState`も使う必要があります。" @@ -13197,7 +13745,8 @@ msgid "" "element and the target of a hyperlink:" msgstr "" "以上をもって、この新しい機能をPSCiで試せます。\n" -"これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンクのリンク先の両方として使います。" +"これには`Content`モナドの内部で一意な名前を生成し、要素の名前とハイパーリンク" +"のリンク先の両方として使います。" #. type: Fenced code block (text) #: text/chapter14.md:684 @@ -13240,7 +13789,9 @@ msgstr "" msgid "" "You can verify that multiple calls to `newName` do, in fact, result in " "unique names." -msgstr "複数回の`newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめられます。" +msgstr "" +"複数回の`newName`の呼び出しの結果が、実際に一意な名前になっていることも確かめ" +"られます。" #. type: Bullet: ' 1. ' #: text/chapter14.md:711 @@ -13256,7 +13807,9 @@ msgstr "" 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`を返す新しい動作を作ってください。" +msgstr "" +"`p`や`img`のような(返る型が`Element`の)関数を`elem`動作と結合して、型" +"`Content Unit`を返す新しい動作を作ってください。" #. type: Bullet: ' - ' #: text/chapter14.md:711 @@ -13274,7 +13827,8 @@ msgid "" "instead of a type synonym. You should not export the data constructor for " "your `newtype`." msgstr "" -"(普通)型同義語の代わりに`newtype`を使って`Content`モナドの実装を隠してください。\n" +"(普通)型同義語の代わりに`newtype`を使って`Content`モナドの実装を隠してくだ" +"さい。\n" "`newtype`用のデータ構築子はエクスポートすべきではありません。" #. type: Bullet: ' 1. ' @@ -13324,7 +13878,9 @@ msgid "" "We used _smart constructors_ to hide the details of our data representation, " "only permitting the user to create documents that were _correct-by-" "construction_." -msgstr "*スマート構築子*を使ってデータ表現の詳細を隠し、利用者には*構築により正しい*文書だけを作ることを許しました。" +msgstr "" +"*スマート構築子*を使ってデータ表現の詳細を隠し、利用者には*構築により正しい*" +"文書だけを作ることを許しました。" #. type: Bullet: '- ' #: text/chapter14.md:728 @@ -13350,8 +13906,10 @@ msgid "" "extended this representation to support a new monadic action and interpreted " "the monadic computations using standard monad transformers." msgstr "" -"*Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変えました。\n" -"それからこの表現を新しいモナド動作に対応するよう拡張し、標準的なモナド変換子を使ってモナドの計算を解釈しました。" +"*Freeモナド*を使って内容の集まりの配列表現をdo記法に対応したモナドな表現に変" +"えました。\n" +"それからこの表現を新しいモナド動作に対応するよう拡張し、標準的なモナド変換子" +"を使ってモナドの計算を解釈しました。" #. type: Plain text #: text/chapter14.md:730 @@ -13371,8 +13929,10 @@ msgid "" "introduction to some simple techniques and illustrates the power of working " "in a language with expressive types." msgstr "" -"関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野です。\n" -"それでも、幾つかの単純な技法に対して役に立つ導入を提供し、表現力豊かな型を持つ言語で作業することの威力を示すことができていれば幸いです。" +"関数型プログラミング言語による領域特化言語の実装は活発に研究されている分野で" +"す。\n" +"それでも、幾つかの単純な技法に対して役に立つ導入を提供し、表現力豊かな型を持" +"つ言語で作業することの威力を示すことができていれば幸いです。" #. type: Title # #: text/chapter2.md:1 @@ -13389,8 +13949,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 @@ -13460,7 +14022,9 @@ msgstr "演習を解く" msgid "" "Now that you've installed the necessary development tools, clone this book's " "repo." -msgstr "ここまでで必要な開発ツールをインストールできているので、本書のリポジトリをクローンしてください。" +msgstr "" +"ここまでで必要な開発ツールをインストールできているので、本書のリポジトリをク" +"ローンしてください。" #. type: Fenced code block (sh) #: text/chapter2.md:23 @@ -13480,10 +14044,15 @@ msgid "" "rendered markdown, and you probably don't need this clutter in your local " "repo):" msgstr "" -"本書のリポジトリにはPureScriptのコード例と各章に付属する演習のための単体テストが含まれます。\n" -"演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準備ができます。\n" +"本書のリポジトリにはPureScriptのコード例と各章に付属する演習のための単体テス" +"トが含まれます。\n" +"演習の解法を白紙に戻すために必要な初期設定があり、この設定をすることで解く準" +"備ができます。\n" "この工程は`resetSolutions.sh`スクリプトを使えば簡単にできます。\n" -"また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくと良いでしょう(これらのアンカーはコード片を本書のMarkdownから書き出した媒体に複製するために使われており、自分のローカルリポジトリではこのアンカーで散らかっていないほうが良いでしょう)。" +"また`removeAnchors.sh`スクリプトで全てのアンカーコメントを取り除いておくと良" +"いでしょう(これらのアンカーはコード片を本書のMarkdownから書き出した媒体に複" +"製するために使われており、自分のローカルリポジトリではこのアンカーで散らかっ" +"ていないほうが良いでしょう)。" #. type: Fenced code block (sh) #: text/chapter2.md:29 @@ -13547,9 +14116,12 @@ msgid "" "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" -"前の方の章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い詰めなくて大丈夫です。" +"なお、(`src/Euler.purs`にある)`answer`関数は任意の整数以下の3と5の倍数を見" +"付けるように変更されています。\n" +"(`test/Main.purs`にある)この`answer`関数のためのテストスートははじめの手引" +"きの冒頭にあるテストよりも網羅的です。\n" +"前の方の章を読んでいる間はこのテストフレームワークの仕組みを理解しようと思い" +"詰めなくて大丈夫です。" #. type: Plain text #: text/chapter2.md:57 @@ -13559,7 +14131,8 @@ msgid "" "can check your work against the provided test suite." msgstr "" "本書の残りの部分には多くの演習が含まれます。\n" -"`Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、提供されているテストスートを使って確認できます。" +"`Test.MySolutions`モジュール (`test/MySolutions.purs`) に自分の解法を書けば、" +"提供されているテストスートを使って確認できます。" #. type: Plain text #: text/chapter2.md:59 @@ -13782,9 +14355,14 @@ msgid "" "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" -"こうした演習の敷居を下げることに繋がる読者のフィードバックのお陰で本書が改善されています。" +"この先の章にはもっと沢山の演習があり、それらに取り組むうちに内容を学ぶ助けに" +"なっているでしょう。\n" +"演習のどこかでお手上げになったら、本書の[困ったときは](chapter1.ja." +"md#getting-help)の節に挙げられているコミュニティの資料のどれかに手を伸ばした" +"り、[本書のリポジトリ](https://github.com/purescript-contrib/purescript-book/" +"issues)でイシューを報告したりできます。\n" +"こうした演習の敷居を下げることに繋がる読者のフィードバックのお陰で本書が改善" +"されています。" #. type: Plain text #: text/chapter2.md:136 @@ -13797,11 +14375,14 @@ msgid "" "elegant solution (that only requires knowledge of the covered content), " "please send us a PR." msgstr "" -"章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べられます。\n" +"章の全ての演習を解いたら、`no-peeking/Solutions.purs`にあるものと解答とを比べ" +"られます。\n" "カンニングはせず、演習を誠実に自力で解く労力を割いてください。\n" -"そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるようにしてください。\n" +"そしてたとえ行き詰まったにしても、まずはコミュニティメンバーに尋ねてみるよう" +"にしてください。\n" "ネタバレをするよりも小さな手掛かりをあげたいからです。\n" -"もっとエレガントな解法(とはいえ本書で押さえられている知識のみで済むもの)を見つけたときはPRを送ってください。" +"もっとエレガントな解法(とはいえ本書で押さえられている知識のみで済むもの)を" +"見つけたときはPRを送ってください。" #. type: Plain text #: text/chapter2.md:137 @@ -13875,12 +14456,20 @@ 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 "" + +#. 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, provided by the `lists` package, which can be " "installed using Spago. It contains a few functions that we will need for " @@ -13891,25 +14480,33 @@ msgstr "" "モジュールには連結リストを使うために必要な幾つかの関数が含まれています。" #. 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`モジュールは、省略可能な値を扱うためのデータ型と関数を定義しています。" +msgstr "" +"`Data.Maybe`モジュールは、省略可能な値を扱うためのデータ型と関数を定義してい" +"ます。" #. type: Plain text -#: text/chapter3.md:26 +#: text/chapter3.md:27 +#, fuzzy +#| 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." 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 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:" @@ -13918,7 +14515,7 @@ msgstr "" "コマンドでSpagoを使用して構築できます。" #. type: Fenced code block (text) -#: text/chapter3.md:29 +#: text/chapter3.md:30 #, no-wrap msgid "" "$ cd chapter3\n" @@ -13928,13 +14525,13 @@ 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 corresponding to JavaScript's " "primitive types: numbers, strings, and booleans. These are defined in the " @@ -13942,12 +14539,15 @@ msgid "" "`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" -"これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポートされます。\n" -"それぞれ`Number`、`String`、`Boolean`と呼ばれており、PSCiで簡単な値の型を表示するのに`:type`コマンドを使うと確認できます。" +"JavaScriptの原始型に対応する組み込みデータ型として、PureScriptでは数値型と文" +"字列型、真偽型の3つが定義されています。\n" +"これらは`Prim`モジュールで定義されており、全てのモジュールに暗黙にインポート" +"されます。\n" +"それぞれ`Number`、`String`、`Boolean`と呼ばれており、PSCiで簡単な値の型を表示" +"するのに`:type`コマンドを使うと確認できます。" #. type: Fenced code block (text) -#: text/chapter3.md:38 +#: text/chapter3.md:39 #, no-wrap msgid "" "$ spago repl\n" @@ -13973,7 +14573,7 @@ msgstr "" "Boolean\n" #. type: Plain text -#: text/chapter3.md:52 +#: text/chapter3.md:53 msgid "" "PureScript defines other built-in types: integers, characters, arrays, " "records, and functions." @@ -13982,7 +14582,7 @@ msgstr "" "義されています。" #. 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:" @@ -13990,7 +14590,7 @@ msgstr "" "小数点以下を省くと整数になり、型 `Number`の浮動小数点数の値と区別されます。" #. type: Fenced code block (text) -#: text/chapter3.md:55 +#: text/chapter3.md:56 #, no-wrap msgid "" "> :type 1\n" @@ -14000,7 +14600,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:" @@ -14008,7 +14608,7 @@ msgstr "" "二重引用符を使用する文字列直値とは異なり、文字直値は一重引用符で囲みます。" #. type: Fenced code block (text) -#: text/chapter3.md:62 +#: text/chapter3.md:63 #, no-wrap msgid "" "> :type 'a'\n" @@ -14018,7 +14618,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:" @@ -14027,7 +14627,7 @@ msgstr "" "PureScriptの配列の全ての要素は同じ型を持つ必要があります。" #. type: Fenced code block (text) -#: text/chapter3.md:69 +#: text/chapter3.md:70 #, no-wrap msgid "" "> :type [1, 2, 3]\n" @@ -14049,7 +14649,7 @@ msgstr "" "Could not match type Int with type Boolean.\n" #. type: Plain text -#: text/chapter3.md:81 +#: text/chapter3.md:82 msgid "" "The last example shows an error from the type checker, which failed to " "_unify_ (i.e., make equal) the types of the two elements." @@ -14058,7 +14658,7 @@ msgstr "" "配列の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:" @@ -14067,7 +14667,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" @@ -14085,17 +14685,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 with the type `String` and an `interests` field with the type `Array " "String`, i.e., an array of `String`s." msgstr "" -"この型が示しているのは指定されたオブジェクトが2つの*フィールド*を持っているということです。\n" -"それぞれ`String`型のフィールド`name`と`Array String`型のフィールド`interests`で、後者は`String`の配列ということです。" +"この型が示しているのは指定されたオブジェクトが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:" @@ -14104,7 +14706,7 @@ msgstr "" "できます。" #. type: Fenced code block (text) -#: text/chapter3.md:97 +#: text/chapter3.md:98 #, no-wrap msgid "" "> author.name\n" @@ -14120,45 +14722,27 @@ 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 +#, fuzzy +#| msgid "" +#| "Functions can be defined at the top-level of a file by specifying " +#| "arguments before the equals sign:" 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 "ファイルの最上位では、等号の直前に引数を指定することで関数を定義できます。" +"ファイルの最上位では、等号の直前に引数を指定することで関数を定義できます。" #. type: Fenced code block (haskell) -#: text/chapter3.md:118 -#, no-wrap +#: text/chapter3.md:108 +#, fuzzy, no-wrap +#| msgid "" +#| "add :: Int -> Int -> Int\n" +#| "add x y = x + y\n" msgid "" +"import Prelude -- bring the (+) operator into scope\n" +"\n" "add :: Int -> Int -> Int\n" "add x y = x + y\n" msgstr "" @@ -14166,21 +14750,29 @@ msgstr "" "add x y = x + y\n" #. type: Plain text -#: text/chapter3.md:124 +#: text/chapter3.md:116 msgid "" "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" +"代えて、バックスラッシュ文字に続けて空白文字で区切られた引数名のリストを書く" +"ことで、関数をインラインでも定義できます。\n" +"PSCiで複数行の宣言を入力するには、`:paste`コマンドを使用して「貼り付けモー" +"ド」に入ります。\n" "このモードでは、*Control-D*キーシーケンスを使って宣言を終了します。" #. type: Fenced code block (text) -#: text/chapter3.md:125 -#, no-wrap +#: text/chapter3.md:117 +#, fuzzy, no-wrap +#| msgid "" +#| "> :paste\n" +#| "… add :: Int -> Int -> Int\n" +#| "… add = \\x y -> x + y\n" +#| "… ^D\n" msgid "" +"> import Prelude\n" "> :paste\n" "… add :: Int -> Int -> Int\n" "… add = \\x y -> x + y\n" @@ -14192,7 +14784,7 @@ msgstr "" "… ^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:" @@ -14201,7 +14793,7 @@ msgstr "" "て書くことで、関数をこれらの引数に*適用* (apply) できます。" #. type: Fenced code block (text) -#: text/chapter3.md:134 +#: text/chapter3.md:127 #, no-wrap msgid "" "> add 10 20\n" @@ -14211,113 +14803,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 we can substitute any types for `a`, `b`, and " -"`c`, and `flip` will work with those types." -msgstr "" -"この`forall`キーワードは、`flip`が*全称量化された型*を持つことを示しています。\n" -"つまり`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`と選んだとします。\n" -"その場合、`flip`の型を次のように*特殊化*できます。" - -#. 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 use `flip` as if it had " -"this type already:" -msgstr "" -"量化された型を特殊化したいということをコードで示す必要はありません。\n" -"特殊化は自動的に行われます。\n" -"例えば、あたかも既にその型の`flip`を持っていたかのように、`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 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" -"もし引数が逆になっているとうまくいかないでしょう。" - -#. 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, " @@ -14330,21 +14822,25 @@ msgstr "" "ドのまとまりを示すために使われているということです。" #. type: Plain text -#: text/chapter3.md:177 +#: text/chapter3.md:137 +#, fuzzy +#| msgid "" +#| "If a declaration spans multiple lines, then any lines except the first " +#| "must be indented past the indentation level of the first line." 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 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" @@ -14354,12 +14850,12 @@ msgstr "" " y + z\n" #. type: Plain text -#: text/chapter3.md:186 +#: 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" @@ -14369,14 +14865,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つ*の宣言であると構文解析します。" +msgstr "" +"後者では、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 " @@ -14388,7 +14886,7 @@ msgstr "" "次は正しいコードです。" #. type: Fenced code block (text) -#: text/chapter3.md:196 +#: text/chapter3.md:156 #, no-wrap msgid "" "> :paste\n" @@ -14402,12 +14900,12 @@ msgstr "" "… ^D\n" #. type: Plain text -#: text/chapter3.md:204 +#: 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" @@ -14421,23 +14919,34 @@ msgstr "" "… ^D\n" #. type: Plain text -#: text/chapter3.md:213 +#: text/chapter3.md:173 +#, fuzzy +#| msgid "" +#| "Certain PureScript keywords (such as `where`, `of` and `let`) introduce a " +#| "new block of code, in which declarations must be further-indented:" 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`)は新たなコードのま" "とまりを導入しますが、そのコードのまとまり内の宣言はそれより深く字下げされて" "いる必要があります。" #. type: Fenced code block (haskell) -#: text/chapter3.md:214 -#, no-wrap +#: text/chapter3.md:174 +#, fuzzy, no-wrap +#| msgid "" +#| "example x y z = foo + bar\n" +#| " where\n" +#| " foo = x * y\n" +#| " bar = y * z\n" 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" @@ -14445,31 +14954,47 @@ msgstr "" " bar = y * z\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 +#, fuzzy, no-wrap +#| msgid "" +#| "example x y z = foo + bar\n" +#| " where\n" +#| " foo = x * y\n" +#| " bar = y * z\n" 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 = foo + bar\n" +" where\n" +" foo = x * y\n" +" bar = y * z\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`だけ" -"は、この規則の唯一の例外になっています。" #. 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 " @@ -14480,13 +15005,13 @@ 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 " "equivalent to the type on the right of the equals symbol: a record type with " @@ -14496,22 +15021,24 @@ msgid "" msgstr "" "これは`Entry`という*型同義語*を定義しています。\n" "型`Entry`は等号の右辺と等価ということです。\n" -"レコードの型は`firstName`、`lastName`、`phone`という3つのフィールドからなります。\n" -"2つの名前のフィールドは型`String`を持ち、`address`は以下で定義された型`Address`を持ちます。" +"レコードの型は`firstName`、`lastName`、`phone`という3つのフィールドからなりま" +"す。\n" +"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, " "which will be represented simply as a linked list of entries:" @@ -14520,13 +15047,13 @@ 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 "{{#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` differs from `Array Entry`, which represents an " "_array_ of entries." @@ -14535,35 +15062,38 @@ msgstr "" "後者は項目の*配列*を表しています。" #. 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`は*型構築子*の一例になっています。\n" -"`List`そのものは型ではなく、何らかの型 `a`があるとき `List a`が型になっています。\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 " "of entries." msgstr "" -"なお、ちょうど関数適用と同じように、型構築子は他の型に並置するだけで適用されます。\n" -"実際、型`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:" @@ -14572,7 +15102,7 @@ msgstr "" "今まで見たことのない種類のエラーが表示されるでしょう。" #. type: Fenced code block (text) -#: text/chapter3.md:257 +#: text/chapter3.md:228 #, no-wrap msgid "" "> import Data.List\n" @@ -14584,7 +15114,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 " @@ -14595,7 +15125,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`." @@ -14604,7 +15134,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 "" @@ -14613,7 +15143,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 "" @@ -14621,7 +15151,7 @@ msgstr "" "す。" #. type: Fenced code block (text) -#: text/chapter3.md:271 +#: text/chapter3.md:242 #, no-wrap msgid "" "> :kind Number\n" @@ -14645,7 +15175,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." @@ -14654,13 +15184,132 @@ 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 "" + +#. 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 +#, 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 +#, fuzzy +#| msgid "" +#| "The keyword `forall` here indicates that `flip` has a _universally " +#| "quantified type_. It means we can substitute any types for `a`, `b`, and " +#| "`c`, and `flip` will work with those types." +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`キーワードは、`flip`が*全称量化された型*を持つことを示していま" +"す。\n" +"つまり`a`や`b`や`c`をどの型に置き換えても良く、`flip`はその型で動作するので" +"す。" + +#. type: Plain text +#: text/chapter3.md:279 +#, fuzzy +#| 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" +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`、`c`を`String`と選んだとします。\n" +"その場合、`flip`の型を次のように*特殊化*できます。" + +#. type: Fenced code block (text) +#: text/chapter3.md:280 +#, fuzzy, no-wrap +#| msgid "log :: String -> Effect Unit\n" +msgid "Int -> String -> Int\n" +msgstr "log :: String -> Effect Unit\n" + +#. type: Plain text #: text/chapter3.md:285 +#, fuzzy +#| 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 `flip` as if it " +#| "had this type already:" +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" +"例えば、あたかも既にその型の`flip`を持っていたかのように、`flip`を使えます。" + +#. 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 +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 #, 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 " @@ -14671,34 +15320,37 @@ msgid "" msgstr "" "それでは最初に、文字列で住所録の項目を表現する関数を書いてみましょう。\n" "まずは関数に型を与えることから始めます。\n" -"型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくようにすると良いでしょう。\n" -"実際、最上位の宣言に型註釈が含まれていないと、PureScriptコンパイラが警告を出します。\n" +"型の定義は省略できますが、ドキュメントとしても役立つので型を書いておくように" +"すると良いでしょう。\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 that takes an " "`Entry` as an argument and returns a `String`. Here is the code for " "`showEntry`:" msgstr "" -"この型シグネチャが言っているのは、`showEntry`は引数として`Entry`を取り`String`を返す関数であるということです。\n" +"この型シグネチャが言っているのは、`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 " @@ -14710,25 +15362,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 " @@ -14739,12 +15391,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 "" @@ -14752,7 +15404,7 @@ msgstr "" "使います。" #. type: Fenced code block (text) -#: text/chapter3.md:319 +#: text/chapter3.md:336 #, no-wrap msgid "" "$ spago repl\n" @@ -14764,7 +15416,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." @@ -14773,18 +15425,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" @@ -14796,14 +15448,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" @@ -14817,13 +15469,13 @@ 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 representing an empty address book: an empty list." @@ -14832,13 +15484,13 @@ 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 "{{#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:" @@ -14847,21 +15499,23 @@ 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, an `AddressBook` as a second argument, and returns a new " "`AddressBook`." -msgstr "この型シグネチャに書かれているのは、最初の引数として`Entry`、第2引数として`AddressBook`を取り、新しい`AddressBook`を返すということです。" +msgstr "" +"この型シグネチャに書かれているのは、最初の引数として`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 " @@ -14878,7 +15532,7 @@ msgstr "" "そのため可能な限り純粋関数や不変なデータにする方が好ましいのです。" #. 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:" @@ -14887,15 +15541,22 @@ msgstr "" "この関数の型を見るには、PSCiを起動し `:type`コマンドを使います。" #. type: Fenced code block (text) -#: text/chapter3.md:368 -#, no-wrap +#: text/chapter3.md:385 +#, fuzzy, no-wrap +#| msgid "" +#| "$ spago repl\n" +#| "\n" +#| "> import Data.List\n" +#| "> :type Cons\n" +#| "\n" +#| "forall a. a -> List a -> List a\n" msgid "" "$ 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" msgstr "" "$ spago repl\n" "\n" @@ -14905,35 +15566,36 @@ msgstr "" "forall a. 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`, 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 " @@ -14945,76 +15607,179 @@ 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 " "create the result." msgstr "" -"こうすると、等号の左側にある2つの引数`entry`と`book`がスコープに導入されます。\n" +"こうすると、等号の左側にある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 +#, fuzzy +#| msgid "" +#| "Functions in PureScript take exactly one argument. While it looks like " +#| "the `insertEntry` function takes two arguments, it is an example of a " +#| "_curried function_." msgid "" "Functions in PureScript take exactly one argument. While it looks like the " "`insertEntry` function takes two arguments, it is an example of a _curried " -"function_." +"function_. In PureScript, all functions are considered curried." msgstr "" "PureScriptでは、関数は常に1つの引数だけを取ります。\n" -"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。" +"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一" +"例なのです。" #. type: Plain text -#: text/chapter3.md:404 +#: 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 "" + +#. 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 "" + +#. type: Fenced code block (haskell) +#: text/chapter3.md:424 +#, fuzzy, no-wrap +#| msgid "" +#| "add :: Int -> Int -> Int\n" +#| "add x y = x + y\n" +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" + +#. 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 "" + +#. type: Plain text +#: text/chapter3.md:443 #, no-wrap -msgid "The `->` operator in the type of `insertEntry` associates to the right, which means that the compiler parses the type as\n" +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 +#, fuzzy, no-wrap +#| msgid "" +#| "> :paste\n" +#| "… add :: Int -> Int -> Int\n" +#| "… add = \\x y -> x + y\n" +#| "… ^D\n" +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" +"… add :: Int -> Int -> Int\n" +"… add = \\x y -> x + y\n" +"… ^D\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 "" + +#. type: Plain text +#: text/chapter3.md:464 +#, fuzzy, no-wrap +#| msgid "The `->` operator in the type of `insertEntry` associates to the right, which means that the compiler parses the type as\n" +msgid "The `->` operator (in the type signature) associates to the right, which means that the compiler parses the type as\n" msgstr "`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。\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 +#, fuzzy +#| msgid "" +#| "That is, `insertEntry` is a function that 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`." msgid "" -"That is, `insertEntry` is a function that 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`を取り、新しい関数を返します。\n" -"今度はこの関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。" +"今度はこの関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返しま" +"す。" #. type: Plain text -#: text/chapter3.md:412 +#: text/chapter3.md:472 msgid "" "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`を*部分適用*できたりするということです。\n" +"これはつまり、最初の引数だけを与えて`insertEntry`を*部分適用*できたりするとい" +"うことです。\n" "PSCiで結果の型が見られます。" #. type: Fenced code block (text) -#: text/chapter3.md:413 +#: text/chapter3.md:473 #, no-wrap msgid "" "> :type insertEntry entry\n" @@ -15026,7 +15791,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:" @@ -15035,7 +15800,7 @@ msgstr "" "この結果の関数に2つ目の引数も適用できます。" #. type: Fenced code block (text) -#: text/chapter3.md:421 +#: text/chapter3.md:481 #, no-wrap msgid "" "> :type (insertEntry entry) emptyBook\n" @@ -15045,7 +15810,7 @@ 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 " "equivalent:" @@ -15054,7 +15819,7 @@ msgstr "" "以下は等価です。" #. type: Fenced code block (text) -#: text/chapter3.md:428 +#: text/chapter3.md:488 #, no-wrap msgid "" "> :type insertEntry entry emptyBook\n" @@ -15064,15 +15829,17 @@ msgstr "" "AddressBook\n" #. type: Plain text -#: text/chapter3.md:434 +#: text/chapter3.md:494 msgid "" "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 "これは関数適用が左に結合するためで、なぜ空白で区切った引数を次々に関数に指定するだけでいいのかの説明にもなっています。" +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" msgstr "" @@ -15081,7 +15848,7 @@ msgstr "" "左右の被演算子はそれぞれ関数の引数の型と返り値の型です。\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 " @@ -15094,12 +15861,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" @@ -15109,7 +15876,7 @@ 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 " @@ -15118,12 +15885,14 @@ msgid "" "argument `book` from both sides:" msgstr "" "もし式の右辺に明示的に括弧をつけるなら、`(Cons entry) book`となります。\n" -"つまり`insertEntry entry`はその引数が単に関数`(Cons entry)`に渡されるような関数だということです。\n" -"ところがこの2つの関数はどんな入力についても同じ結果を返すので、となると同じ関数ではないですか。\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" @@ -15133,44 +15902,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, 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 "" -"この処理は*イータ変換*と呼ばれ、(その他の技法を併用して)*ポイントフリー形式*へと関数を書き換えるのに使えます。\n" +"この処理は*イータ変換*と呼ばれ、(その他の技法を併用して)*ポイントフリー形式" +"*へと関数を書き換えるのに使えます。\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 the point-free form is better in general." msgstr "" -"`insertEntry`の場合、イータ変換によって「`insertEntry`は単にリストにおけるconsだ」となり、とても明快な関数の定義になりました。\n" -"しかし、一般にポイントフリー形式のほうがいいのかどうかには議論の余地があります。" +"`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 " @@ -15181,13 +15953,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, " @@ -15200,13 +15972,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:" @@ -15215,18 +15987,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" @@ -15246,24 +16018,26 @@ 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." msgstr "" -"最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索し適切な`Entry`を返すものです。\n" -"これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログラミングで鍵となる考え方のよい応用例になるでしょう。" +"最小限の住所録アプリケーションの実装で必要になる最後の関数は、名前で人を検索" +"し適切な`Entry`を返すものです。\n" +"これは小さな関数を組み合わせることでプログラムを構築するという、関数型プログ" +"ラミングで鍵となる考え方のよい応用例になるでしょう。" #. type: Plain text -#: text/chapter3.md:500 +#: text/chapter3.md:560 msgid "" "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 " @@ -15273,7 +16047,7 @@ msgstr "" "そうすれば結果のリストの先頭(つまり最初)の要素を返せます。" #. 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` " @@ -15283,19 +16057,30 @@ msgstr "" "まずPSCiを開いて`filter`関数と`head`関数の型を探してみましょう。" #. type: Fenced code block (text) -#: text/chapter3.md:503 -#, no-wrap +#: text/chapter3.md:563 +#, fuzzy, no-wrap +#| msgid "" +#| "$ spago repl\n" +#| "\n" +#| "> import Data.List\n" +#| "> :type filter\n" +#| "\n" +#| "forall a. (a -> Boolean) -> List a -> List a\n" +#| "\n" +#| "> :type head\n" +#| "\n" +#| "forall a. List a -> Maybe a\n" msgid "" "$ 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" msgstr "" "$ spago repl\n" "\n" @@ -15309,13 +16094,13 @@ msgstr "" "forall a. 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. " @@ -15327,7 +16112,7 @@ msgstr "" "第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 " "before: `Maybe a`. `Maybe a` represents an optional value of type `a`, and " @@ -15335,12 +16120,14 @@ msgid "" "in languages like JavaScript. We will see it again in more detail in later " "chapters." msgstr "" -"`head`は引数としてリストを取り、 `Maybe a`という今までに見たことがない型を返します。\n" -"`Maybe 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:" @@ -15349,7 +16136,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" @@ -15361,20 +16148,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 "関数の引数として姓名を渡す必要があるだろうということは分かっています。" #. 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:" @@ -15383,29 +16170,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, 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" +"この型シグネチャで書かれているのは、`findEntry`が姓と名前の2つの文字列及び" +"`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" @@ -15419,12 +16207,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`." @@ -15433,7 +16221,7 @@ 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` " "functions: first, the list of entries is filtered, and the `head` function " @@ -15443,7 +16231,7 @@ msgstr "" "まず項目のリストを絞り込み、その結果に`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 " @@ -15461,23 +16249,24 @@ 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 unnecessary to " "specify a type signature for `filterEntry`. However, doing so is recommended " "as a form of documentation." msgstr "" -"なお、最上位での宣言と同じように、必ずしも`filterEntry`の型シグネチャを指定しなくても構いません。\n" +"なお、最上位での宣言と同じように、必ずしも`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 functions discussed so far used _prefix_ function application, where " "the function name was put _before_ the arguments. For example, when using " @@ -15486,16 +16275,17 @@ msgid "" msgstr "" "これまでお話しした関数のほとんどは*前置*関数適用でした。\n" "関数名が引数の*前*に置かれていたということです。\n" -"例えば`insertEntry`関数を使って`Entry` (`john`) を空の`AddressBook`に追加する場合、以下のように書けます。" +"例えば`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/" @@ -15505,38 +16295,44 @@ msgid "" "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/documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれています。\n" -"`filterEntry`の定義中の`==`演算子がそうで、2つの引数の*間*に置かれています。\n" -"PureScriptのソースコードでこうした中置演算子は隠れた*前置*の実装への中置別称として定義されています。\n" +"しかし本章には*中置*[2引数演算子](https://github.com/purescript/" +"documentation/blob/master/language/Syntax.md#binary-operators)の例も含まれて" +"います。\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 "" "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`で置き換えられます。\n" +"したがって`filterEntry`中の`entry.firstName == firstName`は`eq entry." +"firstName firstName`で置き換えられます。\n" "この節の後のほうで中置演算子を定義する例にもう少し触れます。" #. type: Plain text -#: text/chapter3.md:578 +#: text/chapter3.md:638 msgid "" "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" @@ -15546,7 +16342,7 @@ 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 " "is \"eight mod three\", which you can achieve by wrapping a prefix function " @@ -15557,7 +16353,7 @@ msgstr "" "バックスラッシュ (\\`) の中に前置関数を包むとそのように書けます。" #. type: Fenced code block (text) -#: text/chapter3.md:586 +#: text/chapter3.md:646 #, no-wrap msgid "" "> 8 `mod` 3\n" @@ -15567,7 +16363,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:" @@ -15576,7 +16372,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" @@ -15586,7 +16382,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 " @@ -15597,7 +16393,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" @@ -15607,7 +16403,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]" @@ -15623,37 +16419,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 "" "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 "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." @@ -15662,18 +16458,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 " @@ -15687,17 +16483,18 @@ msgstr "" "があります。" #. type: Plain text -#: text/chapter3.md:634 +#: text/chapter3.md:694 msgid "" "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" @@ -15711,7 +16508,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 "" @@ -15722,7 +16519,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:" @@ -15731,20 +16528,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:" @@ -15752,7 +16549,7 @@ msgstr "" "名前の短い中置演算子を前置関数として使いたければ括弧で囲むことができます。" #. type: Fenced code block (text) -#: text/chapter3.md:654 +#: text/chapter3.md:714 #, no-wrap msgid "" "> 8 + 3\n" @@ -15768,7 +16565,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 " @@ -15785,7 +16582,7 @@ msgstr "" "に束縛しているので、もはや別に無名とも言えなくなっていますが)。" #. type: Fenced code block (text) -#: text/chapter3.md:664 +#: text/chapter3.md:724 #, no-wrap msgid "" "> add3 = (3 + _)\n" @@ -15797,14 +16594,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" @@ -15826,13 +16623,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 " @@ -15842,7 +16639,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 " @@ -15854,13 +16651,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" @@ -15869,13 +16666,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`:" @@ -15884,7 +16681,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" @@ -15894,18 +16691,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` " @@ -15915,18 +16712,19 @@ msgstr "" "いう `findEntry`関数のわかりやすい定義を与えます。" #. type: Plain text -#: text/chapter3.md:713 +#: text/chapter3.md:773 msgid "" "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 "" -"どちらの定義のほうが分かりやすいかの判断はお任せしますが、このように関数を部品として捉えるとしばしば有用です。\n" +"どちらの定義のほうが分かりやすいかの判断はお任せしますが、このように関数を部" +"品として捉えるとしばしば有用です。\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 " @@ -15940,7 +16738,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_ " @@ -15954,7 +16752,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 `_.` " @@ -15967,18 +16765,19 @@ msgstr "" "が与えられた通りの住所に等しいかを判定する関数です。" #. type: Bullet: ' 1. ' -#: text/chapter3.md:721 +#: text/chapter3.md:781 msgid "" "(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" +"(普通)名前が`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 " @@ -15988,59 +16787,67 @@ msgid "" "first element in each set of duplicates (closest to the list head) is the " "one that is kept." msgstr "" -"(難しい)「重複」している住所録の項目を削除する関数`removeDuplicates`を書いてみましょう。\n" -"項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複していると考えます。\n" +"(難しい)「重複」している住所録の項目を削除する関数`removeDuplicates`を書い" +"てみましょう。\n" +"項目が同じ姓名を共有していれば`address`フィールドに関係なく、項目が重複してい" +"ると考えます。\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 and " "learned how to:" -msgstr "この章では関数型プログラミングの新しい概念を幾つか押さえ、以下の方法を学びました。" +msgstr "" +"この章では関数型プログラミングの新しい概念を幾つか押さえ、以下の方法を学びま" +"した。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "" "Use the interactive mode PSCi to experiment with functions and test ideas." -msgstr "対話的モードのPSCiを使用して、関数で実験したり思いついたことを試したりする。" +msgstr "" +"対話的モードのPSCiを使用して、関数で実験したり思いついたことを試したりする。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "Use types as both a correctness tool and an implementation tool." msgstr "正確さのための道具として、また実装のための道具として型を使う。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "Use curried functions to represent functions of multiple arguments." msgstr "多引数の関数を表現するためにカリー化された関数を使う。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "Create programs from smaller components by composition." msgstr "合成により小さな部品からプログラムを作る。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: text/chapter3.md:793 msgid "Structure code neatly using `where` expressions." msgstr "`where`式を使ってコードを手際良く構造化する。" #. type: Bullet: '- ' -#: text/chapter3.md:733 +#: 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 "" "Use techniques like eta conversion and function composition to refactor code " "into a clear specification." -msgstr "イータ変換や関数合成のような技法を使ってより分かりやすい仕様にリファクタする。" +msgstr "" +"イータ変換や関数合成のような技法を使ってより分かりやすい仕様にリファクタす" +"る。" #. type: Plain text -#: text/chapter3.md:734 +#: text/chapter3.md:794 msgid "In the following chapters, we'll build on these ideas." msgstr "次の章からは、これらの考えかたに基づいて進めていきます。" @@ -16057,8 +16864,10 @@ msgid "" "structure algorithms. Recursion is a basic technique used in functional " "programming, which we will use throughout this book." msgstr "" -"この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて見ていきましょう。\n" -"再帰は関数型プログラミングの基本的な手法であり、本書全体にわたって使われます。" +"この章では、アルゴリズムを構造化するときに再帰関数をどのように使うかについて" +"見ていきましょう。\n" +"再帰は関数型プログラミングの基本的な手法であり、本書全体にわたって使われます。" #. type: Plain text #: text/chapter4.md:8 @@ -16079,8 +16888,10 @@ msgid "" "this chapter to write functions that compute properties of the files " "represented by a model of a filesystem." msgstr "" -"この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用います。\n" -"この章で学ぶ技術を応用し、ファイルシステムのモデルにより表現されるファイルのプロパティを計算する関数を書きます。" +"この章では、仮想的なファイルシステムを操作する関数のライブラリを動機付けに用" +"います。\n" +"この章で学ぶ技術を応用し、ファイルシステムのモデルにより表現されるファイルの" +"プロパティを計算する関数を書きます。" #. type: Plain text #: text/chapter4.md:14 @@ -16154,7 +16965,9 @@ msgid "" "partial solutions." msgstr "" "再帰は*分割統治*戦略と密接な関係があります。\n" -"分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部分に分割してそれぞれの部分について問題を解き、部分毎の答えから最終的な答えを組み立てるということです。" +"分割統治とはすなわち、何らかの入力としての問題を解くにあたり、入力を小さな部" +"分に分割してそれぞれの部分について問題を解き、部分毎の答えから最終的な答えを" +"組み立てるということです。" #. type: Plain text #: text/chapter4.md:30 @@ -16179,7 +16992,8 @@ msgid "" "problem to a subproblem – computing the factorial of a smaller integer. When " "we reach zero, the answer is immediate." msgstr "" -"このように、問題を部分問題へ分割することによって階乗関数の計算方法が見てとれます。\n" +"このように、問題を部分問題へ分割することによって階乗関数の計算方法が見てとれ" +"ます。\n" "より小さい数の階乗を計算していくということです。\n" "ゼロに到達すると、答えは直ちに求まります。" @@ -16271,9 +17085,11 @@ msgid "" "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" +"この関数では配列が空かどうかで分岐するために`if ... then ... else`式を使って" +"います。\n" "この`null`関数は空の配列で`true`を返します。\n" -"空の配列の長さはゼロであり、空でない配列の長さは尾鰭の長さより1大きいというわけです。" +"空の配列の長さはゼロであり、空でない配列の長さは尾鰭の長さより1大きいというわ" +"けです。" #. type: Plain text #: text/chapter4.md:67 @@ -16284,10 +17100,12 @@ msgid "" "`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`に包んで返します。\n" +"`tail`関数は与えられた配列から最初の要素を除いたものを`Maybe`に包んで返しま" +"す。\n" "配列が空であれば(つまり尾鰭がなければ)`Nothing`が返ります。\n" "`fromMaybe`関数は既定値と`Maybe`値を取ります。\n" -"後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返します。" +"後者が`Nothing`であれば既定値を返し、そうでなければ`Just`に包まれた値を返しま" +"す。" #. type: Plain text #: text/chapter4.md:69 @@ -16295,14 +17113,18 @@ msgid "" "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で配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえませんが、次の演習を完遂するための手掛かりとしては充分でしょう。" +msgstr "" +"JavaScriptで配列の長さを調べるのには、この例はどう見ても実用的な方法とはいえ" +"ませんが、次の演習を完遂するための手掛かりとしては充分でしょう。" #. type: Bullet: ' 1. ' #: text/chapter4.md:74 msgid "" "(Easy) Write a recursive function `isEven` that returns `true` if and only " "if its input is an even integer." -msgstr "(簡単)入力が偶数であるとき、かつそのときに限り`true`に返す再帰関数`isEven`を書いてみましょう。" +msgstr "" +"(簡単)入力が偶数であるとき、かつそのときに限り`true`に返す再帰関数`isEven`" +"を書いてみましょう。" #. type: Bullet: ' 2. ' #: text/chapter4.md:74 @@ -16312,7 +17134,8 @@ msgid "" "`Data.Array`) can be used to find the first element in a non-empty array." msgstr "" "(普通)配列内の偶数の整数を数える再帰関数`countEven`を書いてみましょう。\n" -"*手掛かり*:`head`関数(これも`Data.Array`モジュールから手に入ります)を使うと、空でない配列の最初の要素を見つけられます。" +"*手掛かり*:`head`関数(これも`Data.Array`モジュールから手に入ります)を使う" +"と、空でない配列の最初の要素を見つけられます。" #. type: Title ## #: text/chapter4.md:75 @@ -16330,7 +17153,8 @@ msgid "" msgstr "" "`map`関数は配列に対する再帰関数の一例です。\n" "配列の各要素に順番に関数を適用し、配列の要素を変換するのに使われます。\n" -"そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存されます。" +"そのため、配列の*内容*は変更されますが、その*形状*(ここでは「長さ」)は保存" +"されます。" #. type: Plain text #: text/chapter4.md:80 @@ -16339,7 +17163,8 @@ msgid "" "function is an example of a more general pattern of shape-preserving " "functions which transform a class of type constructors called _functors_." msgstr "" -"本書の後半で*型クラス*の内容を押さえるとき、`map`関数が形状を保存する関数のより一般的な様式の一例であることを見ていきます。\n" +"本書の後半で*型クラス*の内容を押さえるとき、`map`関数が形状を保存する関数のよ" +"り一般的な様式の一例であることを見ていきます。\n" "この関数は*関手*と呼ばれる型構築子のクラスを変換するものです。" #. type: Plain text @@ -16430,10 +17255,13 @@ msgstr "それでは`map`の型を見てみましょう。" #. type: Fenced code block (text) #: text/chapter4.md:113 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> :type map\n" +#| "forall a b f. Functor f => (a -> b) -> f a -> f b\n" 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" @@ -16451,8 +17279,9 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:120 -#, no-wrap -msgid "forall a b. (a -> b) -> Array a -> Array b\n" +#, fuzzy, 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 "forall a b. (a -> b) -> Array a -> Array b\n" #. type: Plain text @@ -16599,8 +17428,10 @@ msgid "" "array from an existing array, keeping only those elements which match a " "predicate function." msgstr "" -"`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供しています。\n" -"この関数は、述語関数に照合する要素のみを残し、既存の配列から新しい配列を作成する機能を提供します。" +"`Data.Array`モジュールでは他にも、よく`map`と一緒に使われる関数`filter`も提供" +"しています。\n" +"この関数は、述語関数に照合する要素のみを残し、既存の配列から新しい配列を作成" +"する機能を提供します。" #. type: Plain text #: text/chapter4.md:173 @@ -16695,12 +17526,20 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:194 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> import Data.Array\n" +#| "\n" +#| "> :type concat\n" +#| "forall a. Array (Array a) -> Array a\n" +#| "\n" +#| "> concat [[1, 2, 3], [4, 5], [6]]\n" +#| "[1, 2, 3, 4, 5, 6]\n" 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" @@ -16721,8 +17560,10 @@ msgid "" "values (possibly of a different type), `concatMap` takes a function from " "values to arrays of values." msgstr "" -"関連する関数として、`concat`と`map`を組み合わせた`concatMap`と呼ばれる関数もあります。\n" -"`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それに対して`concatMap`は値から値の配列への関数を取ります。" +"関連する関数として、`concat`と`map`を組み合わせた`concatMap`と呼ばれる関数も" +"あります。\n" +"`map`は(相異なる型の可能性がある)値からの値への関数を引数に取りますが、それ" +"に対して`concatMap`は値から値の配列への関数を取ります。" #. type: Plain text #: text/chapter4.md:207 @@ -16731,12 +17572,20 @@ msgstr "実際に動かして見てみましょう。" #. type: Fenced code block (text) #: text/chapter4.md:208 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> import Data.Array\n" +#| "\n" +#| "> :type concatMap\n" +#| "forall a b. (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" 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" @@ -17014,7 +17863,8 @@ msgid "" "expression on the right whose type is an array." msgstr "" "配列の要素を名前に束縛する式。\n" -"これは後ろ向きの矢印`<-`で示されており、左側には名前が、右側には配列の型を持つ式があります。" +"これは後ろ向きの矢印`<-`で示されており、左側には名前が、右側には配列の型を持" +"つ式があります。" #. type: Bullet: '- ' #: text/chapter4.md:304 @@ -17024,7 +17874,8 @@ msgid "" "last line, `pure [i, j]`." msgstr "" "名前に配列の要素を束縛しない式。\n" -"`do`の*結果*はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されています。" +"`do`の*結果*はこの種類の式の一例であり、最後の行の`pure [i, j]`に示されていま" +"す。" #. type: Bullet: '- ' #: text/chapter4.md:304 @@ -17121,12 +17972,17 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:334 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> import Control.Alternative\n" +#| "\n" +#| "> :type guard\n" +#| "forall m. Alternative m => Boolean -> m Unit\n" 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" @@ -17180,7 +18036,8 @@ msgid "" "returns an array with a single element. If the expression evaluates to " "`false`, then its result is empty." msgstr "" -"つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返すのです。\n" +"つまり、`guard`が`true`に評価される式を渡された場合、単一の要素を持つ配列を返" +"すのです。\n" "もし式が`false`と評価された場合は、その結果は空です。" #. type: Plain text @@ -17235,7 +18092,8 @@ msgid "" "Use the `guard` function in an array comprehension." msgstr "" "(普通)関数`triples :: Int -> Array (Array Int)`を書いてください。\n" -"この関数は数値`n`を取り、構成要素(値`a`、`b`、`c`)がそれぞれ`n`以下であるような全てのピタゴラスの3つ組 (pythagorean triples) を返します。\n" +"この関数は数値`n`を取り、構成要素(値`a`、`b`、`c`)がそれぞれ`n`以下であるよ" +"うな全てのピタゴラスの3つ組 (pythagorean triples) を返します。\n" "*ピタゴラスの3つ組*は`a² + b² = c²`であるような数値の配列`[a, b, c]`です。\n" "*手掛かり*:配列内包表記で`guard`関数を使ってください。" @@ -17248,9 +18106,12 @@ msgid "" "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" +"(難しい)`factors`関数を使用して、`n`の[素因数分解](https://www.mathsisfun." +"com/prime-factorization.html)を求める関数`primeFactors`を定義してみましょ" +"う。\n" "`n`の素因数分解とは、積が`n`であるような素数の配列のことです。\n" -"*手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してください。\n" +"*手掛かり*:1より大きい整数について、問題を2つの部分問題に分解してくださ" +"い。\n" "最初の因数を探し、それから残りの因数を探すのです。" #. type: Title ## @@ -17264,7 +18125,9 @@ msgstr "畳み込み" msgid "" "Left and right folds over arrays provide another class of interesting " "functions that can be implemented using recursion." -msgstr "配列における左右の畳み込みは、再帰を用いて実装できる別の興味深い一揃いの関数を提供します。" +msgstr "" +"配列における左右の畳み込みは、再帰を用いて実装できる別の興味深い一揃いの関数" +"を提供します。" #. type: Plain text #: text/chapter4.md:375 @@ -17277,15 +18140,23 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:376 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> import Data.Foldable\n" +#| "\n" +#| "> :type foldl\n" +#| "forall a b f. 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" 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" @@ -17297,22 +18168,34 @@ msgstr "" #. type: Plain text #: text/chapter4.md:387 +#, fuzzy +#| msgid "" +#| "These types are more general than we are interested in right now. For " +#| "this chapter, we can assume that PSCi has given the following (more " +#| "specific) answer:" msgid "" "These types are more general than we are interested in right now. For this " -"chapter, we can assume that PSCi has given the following (more specific) " -"answer:" +"chapter, we can simplify and assume the following (more specific) type " +"signatures:" msgstr "" "これらの型は、現在興味があるものよりも一般化されています。\n" -"この章では、PSCiは以下の(より具体的な)答えをくれていると考えておきましょう。" +"この章では、PSCiは以下の(より具体的な)答えをくれていると考えておきましょ" +"う。" #. type: Fenced code block (text) #: text/chapter4.md:388 -#, no-wrap -msgid "" -"> :type foldl\n" +#, fuzzy, no-wrap +#| msgid "" +#| "> :type foldl\n" +#| "forall a b. (b -> a -> b) -> b -> Array a -> b\n" +#| "\n" +#| "> :type foldr\n" +#| "forall a b. (a -> b -> b) -> b -> Array a -> b\n" +msgid "" +"-- 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" @@ -17393,7 +18276,8 @@ msgid "" "illustrate the difference. Instead of the addition function, let's use " "string concatenation to build a string:" msgstr "" -"違いを説明するために、畳み込み関数の選択が大事になってくる例も書きましょう。\n" +"違いを説明するために、畳み込み関数の選択が大事になってくる例も書きましょ" +"う。\n" "加算関数の代わりに、文字列連結を使用して文字列を構築しましょう。" #. type: Fenced code block (text) @@ -17452,7 +18336,8 @@ msgid "" "overflow errors if our inputs are too large." msgstr "" "再帰はアルゴリズムを指定する強力な手法ですが、問題も抱えています。\n" -"JavaScriptで再帰関数を評価するとき、入力が大き過ぎるとスタックオーバーフローでエラーを起こす可能性があるのです。" +"JavaScriptで再帰関数を評価するとき、入力が大き過ぎるとスタックオーバーフロー" +"でエラーを起こす可能性があるのです。" #. type: Plain text #: text/chapter4.md:441 @@ -17497,14 +18382,17 @@ msgid "" "recursion." msgstr "" "これは問題です。\n" -"関数型プログラミングの標準的な手法として再帰を採用しようとするなら、境界がない再帰がありうるときでも扱える方法が必要です。" +"関数型プログラミングの標準的な手法として再帰を採用しようとするなら、境界がな" +"い再帰がありうるときでも扱える方法が必要です。" #. type: Plain text #: text/chapter4.md:460 msgid "" "PureScript provides a partial solution to this problem through _tail " "recursion optimization_." -msgstr "PureScriptは*末尾再帰最適化*の形でこの問題に対する部分的な解決策を提供しています。" +msgstr "" +"PureScriptは*末尾再帰最適化*の形でこの問題に対する部分的な解決策を提供してい" +"ます。" #. type: Plain text #: text/chapter4.md:462 @@ -17527,7 +18415,8 @@ msgstr "" "末尾再帰最適化を可能にする上で鍵となる観点は以下となります。\n" "*末尾位置*にある関数の再帰的な呼び出しは*ジャンプ*に置き換えられます。\n" "このジャンプではスタックフレームが確保されません。\n" -"関数が戻るより前の最後の呼び出しであるとき、呼び出しが*末尾位置*にあるといいます。\n" +"関数が戻るより前の最後の呼び出しであるとき、呼び出しが*末尾位置*にあるといい" +"ます。\n" "なぜ先の例でスタックオーバーフローが見られたのかはこれが理由です。\n" "`f`の再帰呼び出しが末尾位置*でなかったからです。" @@ -17560,7 +18449,8 @@ msgid "" "Notice that the recursive call to `factorialTailRec` is the last thing in " "this function – it is in tail position." msgstr "" -"`factorialTailRec`への再帰呼び出しがこの関数の最後にある点に注目してください。\n" +"`factorialTailRec`への再帰呼び出しがこの関数の最後にある点に注目してくださ" +"い。\n" "つまり末尾位置にあるのです。" #. type: Title ## @@ -17577,7 +18467,8 @@ msgid "" "additional parameter added to a function that _accumulates_ a return value, " "as opposed to using the return value to accumulate the result." msgstr "" -"末尾再帰ではない関数を末尾再帰関数に変える一般的な方法は、*累算器引数*を使用することです。\n" +"末尾再帰ではない関数を末尾再帰関数に変える一般的な方法は、*累算器引数*を使用" +"することです。\n" "累算器引数は関数に追加される余剰の引数で、返り値を*累算*するものです。\n" "これは結果を累算するために返り値を使うのとは対照的です。" @@ -17634,7 +18525,8 @@ msgstr "" "ここでは補助関数`length'`に委譲しています。\n" "この関数は末尾再帰です。\n" "その唯一の再帰呼び出しは、最後の場合の末尾位置にあります。\n" -"つまり、生成されるコードは*whileループ*となり、大きな入力でもスタックが溢れません。" +"つまり、生成されるコードは*whileループ*となり、大きな入力でもスタックが溢れま" +"せん。" #. type: Plain text #: text/chapter4.md:498 @@ -17644,16 +18536,19 @@ msgid "" "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'`が基本的に累算器引数を使って追加の状態を保持していることに注目してください。\n" +"`lengthTailRec`の実装を理解する上では、補助関数`length'`が基本的に累算器引数" +"を使って追加の状態を保持していることに注目してください。\n" "追加の状態とは、部分的な結果です。\n" -"0から始まり、入力の配列中の全ての各要素について1ずつ足されて大きくなっていきます。" +"0から始まり、入力の配列中の全ての各要素について1ずつ足されて大きくなっていき" +"ます。" #. type: Plain text #: text/chapter4.md:500 msgid "" "Note also that while we might think of the accumulator as a \"state\", there " "is no direct mutation." -msgstr "なお、累算器を「状態」と考えることもできますが、直接には変更されていません。" +msgstr "" +"なお、累算器を「状態」と考えることもできますが、直接には変更されていません。" #. type: Title ## #: text/chapter4.md:501 @@ -17673,10 +18568,14 @@ msgid "" "are well-understood, and as such, communicate the _intent_ of the algorithm " "much better than explicit recursion." msgstr "" -"末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けられるので、全ての関数をこの形で書こうとする誘惑にかられます。\n" -"しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書くことができることを忘れがちです。\n" -"`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、コードの単純さという利点があります。\n" -"これらの部品はよく知られており、だからこそ明示的な再帰よりもアルゴリズムの*意図*がより良く伝わるのです。" +"末尾再帰を使用して再帰関数を記述できれば末尾再帰最適化の恩恵を受けられるの" +"で、全ての関数をこの形で書こうとする誘惑にかられます。\n" +"しかし、多くの関数は配列やそれに似たデータ構造に対する折り畳みとして直接書く" +"ことができることを忘れがちです。\n" +"`map`や`fold`のような組み合わせの部品を使って直接アルゴリズムを書くことには、" +"コードの単純さという利点があります。\n" +"これらの部品はよく知られており、だからこそ明示的な再帰よりもアルゴリズムの*意" +"図*がより良く伝わるのです。" #. type: Plain text #: text/chapter4.md:506 @@ -17742,7 +18641,8 @@ msgid "" "(Medium) Write a function `fibTailRec` which is the same as `fib` but in " "tail recursive form. _Hint_: Use an accumulator parameter." msgstr "" -"(普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`を書いてください。\n" +"(普通)末尾再帰の形式を取っていること以外は`fib`と同じような関数`fibTailRec`" +"を書いてください。\n" "*手掛かり*:累算器引数を使ってください。" #. type: Bullet: ' 4. ' @@ -17763,7 +18663,8 @@ msgid "" "work with a model of a filesystem. We will use maps, folds, and filters to " "work with a predefined API." msgstr "" -"この節ではこれまで学んだことを応用してファイルシステムのモデルを扱う関数を書きます。\n" +"この節ではこれまで学んだことを応用してファイルシステムのモデルを扱う関数を書" +"きます。\n" "事前に定義されたAPIを扱う上でマップ、畳み込み、及びフィルタを使用します。" #. type: Plain text @@ -17877,7 +18778,8 @@ msgid "" "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`モジュールだけで作業します。" @@ -17893,7 +18795,8 @@ msgid "" "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" +"それでは、ディレクトリの中身を含めた全てのファイルを深く列挙する関数を書いて" +"みましょう。\n" "この関数は以下のような型を持つでしょう。" #. type: Fenced code block (haskell) @@ -17913,7 +18816,8 @@ msgid "" msgstr "" "再帰を使ってこの関数を定義できます。\n" "`ls`を使うとディレクトリ直下の子が列挙されます。\n" -"それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返ります。\n" +"それぞれの子について再帰的に`allFiles`を適用すると、それぞれパスの配列が返り" +"ます。\n" "`concatMap`を使うと、`allFiles`を適用して平坦化するまでを一度にできます。" #. type: Plain text @@ -18071,9 +18975,12 @@ msgid "" "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" -"また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関数、及びこれらの概念を組み合わせた配列内包表記を導入しました。\n" -"最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。" +"この章ではアルゴリズムを簡潔に表現するためにPureScriptでの再帰の基本を押さえ" +"ました。\n" +"また、独自の中置演算子や、マップ、絞り込みや畳み込みなどの配列に対する標準関" +"数、及びこれらの概念を組み合わせた配列内包表記を導入しました。\n" +"最後に、スタックオーバーフローエラーを回避するために末尾再帰を使用することの" +"重要性、累算器引数を使用して末尾再帰形に関数を変換する方法を示しました。" #. type: Title # #: text/chapter5.md:1 @@ -18088,8 +18995,10 @@ msgid "" "pattern matching. We will also briefly cover an interesting feature of the " "PureScript type system: row polymorphism." msgstr "" -"この章では、代数的データ型とパターン照合という、2つの新しい概念を導入します。\n" -"また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱います。" +"この章では、代数的データ型とパターン照合という、2つの新しい概念を導入しま" +"す。\n" +"また、行多相というPureScriptの型システムの興味深い機能についても簡単に取り扱" +"います。" #. type: Plain text #: text/chapter5.md:8 @@ -18098,8 +19007,10 @@ msgid "" "the developer to write compact functions, which express potentially complex " "ideas by breaking their implementation down into multiple cases." msgstr "" -"パターン照合は関数型プログラミングにおける一般的な手法であり、開発者が簡潔に関数を書けるようになります。\n" -"関数の実装を複数の場合に分解することにより、水面下の複雑なアイディアが表現されるのです。" +"パターン照合は関数型プログラミングにおける一般的な手法であり、開発者が簡潔に" +"関数を書けるようになります。\n" +"関数の実装を複数の場合に分解することにより、水面下の複雑なアイディアが表現さ" +"れるのです。" #. type: Plain text #: text/chapter5.md:10 @@ -18108,7 +19019,8 @@ msgid "" "enables a similar level of expressiveness in the language of types – they " "are closely related to pattern matching." msgstr "" -"代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等の水準の表現力を可能にしています。\n" +"代数的データ型はPureScriptの型システムの機能であり、型のある言語において同等" +"の水準の表現力を可能にしています。\n" "パターン照合とも密接に関連しています。" #. type: Plain text @@ -18116,7 +19028,9 @@ msgstr "" msgid "" "The chapter's goal will be to write a library to describe and manipulate " "simple vector graphics using algebraic types and pattern matching." -msgstr "この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラフィックスを記述し操作するためのライブラリを書くことです。" +msgstr "" +"この章の目的は、代数的データ型やパターン照合を使用して、単純なベクターグラ" +"フィックスを記述し操作するためのライブラリを書くことです。" #. type: Plain text #: text/chapter5.md:16 @@ -18133,7 +19047,8 @@ msgid "" "a type `Picture` for collections of shapes, along with functions for working " "with those types." msgstr "" -"`Data.Picture`モジュールは簡単な図形を表すデータ型`Shape`やその図形の集合である型`Picture`を定義します。\n" +"`Data.Picture`モジュールは簡単な図形を表すデータ型`Shape`やその図形の集合であ" +"る型`Picture`を定義します。\n" "また、これらの型を扱うための関数もあります。" #. type: Plain text @@ -18141,7 +19056,9 @@ msgstr "" msgid "" "The module imports the `Data.Foldable` module, which provides functions for " "folding data structures:" -msgstr "このモジュールでは、データ構造を畳込む関数を提供する`Data.Foldable`モジュールもインポートします。" +msgstr "" +"このモジュールでは、データ構造を畳込む関数を提供する`Data.Foldable`モジュール" +"もインポートします。" #. type: Fenced code block (haskell) #: text/chapter5.md:21 @@ -18174,7 +19091,8 @@ msgid "" msgstr "" "こうすると型や関数をモジュール内で使用できるようになりますが、\n" "`Number.max`のように*修飾名*を使ったときに限定されます。\n" -"重複したインポートを避けたり、どのモジュールからインポートされたのかを明らかにするのに役立ちます。" +"重複したインポートを避けたり、どのモジュールからインポートされたのかを明らか" +"にするのに役立ちます。" #. type: Plain text #: text/chapter5.md:34 @@ -18197,7 +19115,8 @@ msgid "" "greatest common divisor of two integers using pattern matching:" msgstr "" "例を見ることから始めましょう。\n" -"パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになります。" +"パターン照合を使用して2つの整数の最大公約数を計算する関数は、次のようになりま" +"す。" #. type: Fenced code block (haskell) #: text/chapter5.md:39 @@ -18215,8 +19134,10 @@ msgid "" "like a mathematical function specification." msgstr "" "このアルゴリズムはユークリッドの互除法と呼ばれています。\n" -"その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が見つかるでしょう。\n" -"パターン照合の利点の1つは、コードを場合分けして定義でき、数学関数の仕様に似た単純で宣言型なコードを定義できることです。" +"その定義をオンラインで検索すると、恐らく上記のコードによく似た数学の方程式が" +"見つかるでしょう。\n" +"パターン照合の利点の1つは、コードを場合分けして定義でき、数学関数の仕様に似た" +"単純で宣言型なコードを定義できることです。" #. type: Plain text #: text/chapter5.md:46 @@ -18230,11 +19151,15 @@ msgid "" "returned. Each case is tried in order, and the first case whose patterns " "match their inputs determines the return value." msgstr "" -"パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作します。\n" +"パターン照合を使用して書かれた関数は、条件と結果の組み合わせによって動作しま" +"す。\n" "この定義の各行は*選択肢*や*場合*と呼ばれています。\n" -"等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ以上のパターンで構成されています。\n" -"場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなければならない条件を表現しています。\n" -"それぞれの場合は上からこの順番に試されていき、最初にパターンが入力に照合した場合が返り値を決定します。" +"等号の左辺の式は*パターン*と呼ばれており、それぞれの場合は空白で区切られた1つ" +"以上のパターンで構成されています。\n" +"場合の集まりは、等号の右側の式が評価され値が返される前に、引数が満たさなけれ" +"ばならない条件を表現しています。\n" +"それぞれの場合は上からこの順番に試されていき、最初にパターンが入力に照合した" +"場合が返り値を決定します。" #. type: Plain text #: text/chapter5.md:48 @@ -18275,8 +19200,10 @@ msgid "" "different ways to choose names from the input arguments." msgstr "" "なお、パターンでは値を名前に束縛できます。\n" -"この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛しています。\n" -"様々な種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力の引数から名前を選ぶ様々な方法に対応することがわかるでしょう。" +"この例の各行では `n`や`m`という名前の何れかまたは両方に入力された値を束縛して" +"います。\n" +"様々な種類のパターンについて学んでいくうちに、それぞれの種類のパターンが入力" +"の引数から名前を選ぶ様々な方法に対応することがわかるでしょう。" #. type: Title ## #: text/chapter5.md:55 @@ -18316,7 +19243,9 @@ msgstr "`Number`、`String`、`Char`、そして`Boolean`といった直値" msgid "" "Wildcard patterns, indicated with an underscore (`_`), match any argument " "and do not bind any names." -msgstr "どんな引数とも照合するが名前に束縛はしない、アンダースコア (`_`) で表されるワイルドカードパターン" +msgstr "" +"どんな引数とも照合するが名前に束縛はしない、アンダースコア (`_`) で表されるワ" +"イルドカードパターン" #. type: Plain text #: text/chapter5.md:68 @@ -18356,7 +19285,8 @@ msgid "" "the constraints imposed by the patterns. Here is the Euclidean algorithm " "rewritten to use a guard:" msgstr "" -"ガードとは、パターンにより課された制約に加えて満たされなくてはいけない真偽値の式です。\n" +"ガードとは、パターンにより課された制約に加えて満たされなくてはいけない真偽値" +"の式です。\n" "ガードを使用してユークリッドのアルゴリズムを書き直すと、次のようになります。" #. type: Fenced code block (haskell) @@ -18373,9 +19303,11 @@ msgid "" "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引数よりも厳密に大きいという条件を課しています。\n" +"この場合、3行目ではガードを使用して、最初の引数が第2引数よりも厳密に大きいと" +"いう条件を課しています。\n" "最後の行でのガードは式`otherwise`を使っています。\n" -"これはキーワードのようにも見えますが、実際はただの`Prelude`にある普通の束縛です。" +"これはキーワードのようにも見えますが、実際はただの`Prelude`にある普通の束縛で" +"す。" #. type: Fenced code block (text) #: text/chapter5.md:89 @@ -18427,12 +19359,14 @@ msgid "" "cases. If it takes a long time to complete or crashes with an error about " "the call stack, try adding more corner cases." msgstr "" -"(普通)\\\\( (1 + x) ^ n \\\\)を多項式展開した式にある\\\\( x ^ k \\\\)の項の係数を求める関数`binomial`を書いてください。\n" +"(普通)\\\\( (1 + x) ^ n \\\\)を多項式展開した式にある\\\\( x ^ k \\\\)の項" +"の係数を求める関数`binomial`を書いてください。\n" "これは`n`要素の集合から`k`要素の部分集合を選ぶ方法の数と同じです。\n" "数式\\\\( n! / k! (n - k)! \\\\)を使ってください。\n" "ここで \\\\( ! \\\\) は前に書いた階乗関数です。\n" "*手掛かり*:パターン照合を使って特殊な場合を取り扱ってください。\n" -"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、特殊な場合を更に追加してみてください。" +"長い時間が掛かったりコールスタックのエラーでクラッシュしたりしたら、特殊な場" +"合を更に追加してみてください。" #. type: Bullet: '1. ' #: text/chapter5.md:104 @@ -18473,7 +19407,9 @@ msgstr "{{#include ../exercises/chapter5/src/ChapterExamples.purs:isEmpty}}\n" msgid "" "Here is another function that matches arrays of length five, binding each of " "its five elements differently:" -msgstr "次の関数では、長さ5の配列と照合し、配列の5つの要素をそれぞれ違った方法で束縛しています。" +msgstr "" +"次の関数では、長さ5の配列と照合し、配列の5つの要素をそれぞれ違った方法で束縛" +"しています。" #. type: Fenced code block (haskell) #: text/chapter5.md:115 @@ -18489,7 +19425,8 @@ msgid "" "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" +"最初のパターンは、第1要素と第2要素がそれぞれ0と1であるような、5要素の配列にの" +"み照合します。\n" "その場合、関数は第3要素と第4要素の積を返します。\n" "それ以外の場合は、関数は0を返します。\n" "例えばPSCiで試してみると次のようになります。" @@ -18538,9 +19475,12 @@ msgid "" "operations." msgstr "" "配列の直値パターンでは、固定長の配列と一致させることはできます。\n" -"しかしPureScriptは不特定の長さの配列を照合させる手段は全く提供して*いません*。\n" -"そのような類の方法で不変な配列を分解すると、実行速度が低下する可能性があるためです。\n" -"このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めします。\n" +"しかしPureScriptは不特定の長さの配列を照合させる手段は全く提供して*いません" +"*。\n" +"そのような類の方法で不変な配列を分解すると、実行速度が低下する可能性があるた" +"めです。\n" +"このように照合できるデータ構造が必要な場合は、`Data.List`を使うことをお勧めし" +"ます。\n" "その他の操作について、より優れた漸近性能を提供するデータ構造も存在します。" #. type: Title ## @@ -18569,7 +19509,10 @@ 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`, " "respectively:" -msgstr "例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレコードに照合し、これらのフィールドの値はそれぞれ `x`と `y`という名前に束縛されます。" +msgstr "" +"例えば次のパターンは`first`と`last`という名前のフィールドが含まれた任意のレ" +"コードに照合し、これらのフィールドの値はそれぞれ `x`と `y`という名前に束縛さ" +"れます。" #. type: Fenced code block (haskell) #: text/chapter5.md:147 @@ -18593,12 +19536,17 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter5.md:153 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> showPerson { first: x, last: y } = y <> \", \" <> x\n" +#| "\n" +#| "> :type showPerson\n" +#| "forall r. { first :: String, last :: String | r } -> String\n" 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" @@ -18638,9 +19586,12 @@ msgid "" "fields of type `String`, the function application is well-typed. However, it " "is _not_ valid to call `showPerson` with too _few_ fields:" msgstr "" -"レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま動作するのです。\n" -"レコードに少なくとも型が`String`であるようなフィールド`first`と`last`が含まれていれば、関数適用は正しく型付けされます。\n" -"しかし、フィールドが*不足*していると、`showPerson`の呼び出しは*不正*となります。" +"レコードにそれ以外のフィールドが追加されていても、`showPerson`関数はそのまま" +"動作するのです。\n" +"レコードに少なくとも型が`String`であるようなフィールド`first`と`last`が含まれ" +"ていれば、関数適用は正しく型付けされます。\n" +"しかし、フィールドが*不足*していると、`showPerson`の呼び出しは*不正*となりま" +"す。" #. type: Fenced code block (text) #: text/chapter5.md:172 @@ -18701,8 +19652,10 @@ msgid "" "alternatively reuse the field names themselves and simplify this sort of " "pattern match as follows:" msgstr "" -"`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と`y`という名前の値に束縛していたのでした。\n" -"別の方法として、フィールド名自体を再利用してこのような類のパターン照合を次のように単純化できます。" +"`showPerson`関数は引数内のレコードと照合し、`first`と`last`フィールドを`x`と" +"`y`という名前の値に束縛していたのでした。\n" +"別の方法として、フィールド名自体を再利用してこのような類のパターン照合を次の" +"ように単純化できます。" #. type: Fenced code block (haskell) #: text/chapter5.md:192 @@ -18756,8 +19709,10 @@ msgid "" "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" +"これまでのほとんどの例では配列パターンとレコードパターンの内部で単純なパター" +"ンを使用していました。\n" "しかし特筆すべきこととして、パターンは自由に*入れ子*にできます。\n" "これにより潜在的に複雑なデータ型についての条件を使って関数を定義できます。" @@ -18810,8 +19765,10 @@ msgid "" "already sorted. Note that if the input array does not contain _exactly_ two " "elements, then this function returns it unchanged, even if it's unsorted." msgstr "" -"このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みます。\n" -"なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されていなかったとしても、この関数は単に元のまま変えずに返します。" +"このようにすれば対が既に整列されているときに新しい配列を割り当てなくて済みま" +"す。\n" +"なお、もし入力の配列が*厳密に*2つの要素を含んでいなければ、たとえ整列されてい" +"なかったとしても、この関数は単に元のまま変えずに返します。" #. type: Bullet: '1. ' #: text/chapter5.md:233 @@ -18841,7 +19798,8 @@ msgid "" "singleton, your function should return a provided default value. Your " "function should have type `forall a. a -> Array a -> a`" msgstr "" -"(普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数`fromSingleton`を書いてみましょう。\n" +"(普通)配列直値パターンを使って、1要素の配列の唯一のメンバーを抽出する関数" +"`fromSingleton`を書いてみましょう。\n" "1要素だけを持つ配列でない場合、関数は与えられた既定値を返します。\n" "この関数は`forall a. a -> Array a -> a`という型を持ちます。" @@ -18864,7 +19822,8 @@ msgstr "" "パターンが現れるのは最上位にある関数宣言だけではありません。\n" "`case`式を使う計算中の途中の値に対してパターン照合を使えます。\n" "case式には無名関数に似た便利さがあります。\n" -"関数に名前を与えることがいつも望ましいわけではないように、パターンを使いたいためだけに関数に名前をつけるようなことを避けられるようになります。" +"関数に名前を与えることがいつも望ましいわけではないように、パターンを使いたい" +"ためだけに関数に名前をつけるようなことを避けられるようになります。" #. type: Plain text #: text/chapter5.md:239 @@ -18931,7 +19890,8 @@ msgid "" "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 @@ -18960,7 +19920,8 @@ msgid "" msgstr "" "この関数は単一の場合しか含んでいません。\n" "そしてその場合は単一の入力である`true`にのみ照合します。\n" -"このファイルをコンパイルしてPSCiでそれ以外の値を与えて試すと実行時エラーが発生します。" +"このファイルをコンパイルしてPSCiでそれ以外の値を与えて試すと実行時エラーが発" +"生します。" #. type: Fenced code block (text) #: text/chapter5.md:272 @@ -18979,7 +19940,9 @@ msgstr "" msgid "" "Functions that return a value for any combination of inputs are called " "_total_ functions, and functions that do not are called _partial_." -msgstr "どんな入力の組み合わせに対しても値を返すような関数は*全関数*と呼ばれ、そうでない関数は*部分的*であると呼ばれます。" +msgstr "" +"どんな入力の組み合わせに対しても値を返すような関数は*全関数*と呼ばれ、そうで" +"ない関数は*部分的*であると呼ばれます。" #. type: Plain text #: text/chapter5.md:281 @@ -19008,9 +19971,12 @@ msgid "" "`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 @@ -19077,7 +20043,9 @@ 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 " "a prior case would have matched):" -msgstr "コンパイラは、*冗長*な場合を検出したとき(つまり、その場合より前の方に定義された場合にのみ一致するとき)などにも警告を出します。" +msgstr "" +"コンパイラは、*冗長*な場合を検出したとき(つまり、その場合より前の方に定義さ" +"れた場合にのみ一致するとき)などにも警告を出します。" #. type: Fenced code block (haskell) #: text/chapter5.md:311 @@ -19167,7 +20135,8 @@ msgid "" "to add new operations without breaking modularity." msgstr "" "しかし、この方針は大きな欠点を1つ抱えています。\n" -"`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に把握し、`Shape`インターフェースに定義する必要があるのです。\n" +"`Shape`を抽象的に扱うためには、実行したいと思う可能性のある全ての操作を事前に" +"把握し、`Shape`インターフェースに定義する必要があるのです。\n" "モジュール性を壊さずに新しい操作を追加することが難しくなります。" #. type: Plain text @@ -19177,8 +20146,10 @@ msgid "" "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 "" -"もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決する型安全な方法を提供します。\n" -"モジュール性のある方法で `Shape`に新たな操作を定義しつつ、型安全性を維持できます。" +"もし図形の種類が事前にわかっているなら、代数的データ型はこうした問題を解決す" +"る型安全な方法を提供します。\n" +"モジュール性のある方法で `Shape`に新たな操作を定義しつつ、型安全性を維持でき" +"ます。" #. type: Plain text #: text/chapter5.md:341 @@ -19223,8 +20194,10 @@ msgid "" "constructors doesn't have to be restricted to primitive types: constructors " "can include records, arrays, or even other ADTs." msgstr "" -"代数的データ型 (algebraic data type; ADT) の定義はキーワード`data`から始まり、それに新しい型の名前と任意個の型引数が続きます。\n" -"その型の構築子(これを*データ構築子*と言います)は等号の後に定義され、パイプ文字 (`|`) で区切られます。\n" +"代数的データ型 (algebraic data type; ADT) の定義はキーワード`data`から始ま" +"り、それに新しい型の名前と任意個の型引数が続きます。\n" +"その型の構築子(これを*データ構築子*と言います)は等号の後に定義され、パイプ" +"文字 (`|`) で区切られます。\n" "ADTの構築子が持つデータは原始型に限りません。\n" "構築子にはレコード、配列、また他のADTさえも含められます。" @@ -19264,7 +20237,8 @@ msgid "" "defining ADTs with `data` or type aliases with `type`." msgstr "" "なお、データ定義のどこにも構文`forall a`を使っていません。\n" -"`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義するときは使われません。" +"`forall`構文は関数には必須ですが、`data`によるADTや`type`での型別称を定義する" +"ときは使われません。" #. type: Plain text #: text/chapter5.md:363 @@ -19379,9 +20353,11 @@ msgid "" "into scope using two variable patterns, `c` and `r`. The other cases are " "similar." msgstr "" -"各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できます。\n" +"各構築子はパターンとして使用でき、構築子への引数はそのパターンで束縛できま" +"す。\n" "`showShape`の最初の場合を考えてみましょう。\n" -"もし `Shape`が `Circle`構築子に照合した場合、2つの変数パターン `c`と `r`を使って`Circle`の引数(中心と半径)がスコープに導入されます。\n" +"もし `Shape`が `Circle`構築子に照合した場合、2つの変数パターン `c`と `r`を" +"使って`Circle`の引数(中心と半径)がスコープに導入されます。\n" "その他の場合も同様です。" #. type: Bullet: '1. ' @@ -19399,7 +20375,9 @@ msgstr "" msgid "" "(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`を書いてみましょう。" +msgstr "" +"(普通)原点を中心として`Shape`の大きさを`2.0`倍に拡大する関数" +"`doubleScaleAndCenter`を書いてみましょう。" #. type: Bullet: '1. ' #: text/chapter5.md:397 @@ -19596,10 +20574,13 @@ msgid "" "is idiomatic for them to share the same name. This is the case with `Amp` " "and `Volt` types above." msgstr "" -"この場合`Coulomb`は(引数ゼロの)*型構築子*で、`MakeCoulomb`は*データ構築子*です。\n" -"これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名前には一意性があります。\n" +"この場合`Coulomb`は(引数ゼロの)*型構築子*で、`MakeCoulomb`は*データ構築子*" +"です。\n" +"これらの構築子は異なる名前空間に属しており、`Volt`の例でそうだったように、名" +"前には一意性があります。\n" "これは全てのADTについて言えることです。\n" -"なお、型構築子とデータ構築子には異なる名前を付けられますが、実際には同じ名前を共有するのが普通です。\n" +"なお、型構築子とデータ構築子には異なる名前を付けられますが、実際には同じ名前" +"を共有するのが普通です。\n" "前述の`Amp`と`Volt`の場合がこれです。" #. type: Plain text @@ -19746,7 +20727,9 @@ msgid "" "`bounds` uses the `foldl` function from `Data.Foldable` to traverse the " "array of `Shapes` in a `Picture`, and accumulate the smallest bounding " "rectangle:" -msgstr "`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累算するため、`bounds`には `Data.Foldable`の `foldl`関数を使用しています。" +msgstr "" +"`Picture`内の `Shape`の配列を走査し、最小の外接矩形を累算するため、`bounds`に" +"は `Data.Foldable`の `foldl`関数を使用しています。" #. type: Fenced code block (haskell) #: text/chapter5.md:516 @@ -19774,8 +20757,11 @@ msgid "" "the bounds of a single shape using pattern matching." msgstr "" "累算関数`combine`は`where`ブロックで定義されています。\n" -"`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`を引数に取り、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算しています。\n" -"`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算します。" +"`combine`は`foldl`の再帰呼び出しで計算された外接矩形と、配列内の次の `Shape`" +"を引数に取り、ユーザ定義の演算子`union`を使って2つの外接矩形の和を計算してい" +"ます。\n" +"`shapeBounds`関数は、パターン照合を使用して、単一の図形の外接矩形を計算しま" +"す。" #. type: Bullet: '1. ' #: text/chapter5.md:528 @@ -19826,7 +20812,8 @@ msgid "" "types with new operations." msgstr "" "また、この章ではパターン照合に密接に関連する代数的データ型も紹介しました。\n" -"代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡張する上で、モジュール性のある方法が齎されるのでした。" +"代数的データ型のおかげでデータ構造を簡潔に記述でき、新たな操作でデータ型を拡" +"張する上で、モジュール性のある方法が齎されるのでした。" #. type: Plain text #: text/chapter5.md:536 @@ -19835,7 +20822,8 @@ msgid "" "allows many idiomatic JavaScript functions to be given a type." msgstr "" "最後に*行多相*を扱いました。\n" -"これは強力な抽象化をする型であり、これにより多くの既存のJavaScript関数に型を与えられます。" +"これは強力な抽象化をする型であり、これにより多くの既存のJavaScript関数に型を" +"与えられます。" #. type: Plain text #: text/chapter5.md:537 @@ -19862,7 +20850,8 @@ msgid "" "This chapter will introduce a powerful form of abstraction enabled by " "PureScript's type system – type classes." msgstr "" -"この章では、PureScriptの型システムにより可能になっている強力な抽象化の形式を導入します。\n" +"この章では、PureScriptの型システムにより可能になっている強力な抽象化の形式を" +"導入します。\n" "そう、型クラスです。" #. type: Plain text @@ -19874,7 +20863,8 @@ msgid "" "of the data itself." msgstr "" "データ構造をハッシュ化するためのライブラリを本章の動機付けの例とします。\n" -"データ自体の構造について直接考えることなく複雑な構造のデータのハッシュ値を求める上で、型クラスの仕組みがどのように働くかを見ていきます。" +"データ自体の構造について直接考えることなく複雑な構造のデータのハッシュ値を求" +"める上で、型クラスの仕組みがどのように働くかを見ていきます。" #. type: Plain text #: text/chapter6.md:10 @@ -19991,7 +20981,9 @@ msgstr "" msgid "" "This code declares a new _type class_ called `Show`, which is parameterized " "by the type variable `a`." -msgstr "このコードでは、型変数`a`を引数に取る`Show`という新しい*型クラス*を宣言しています。" +msgstr "" +"このコードでは、型変数`a`を引数に取る`Show`という新しい*型クラス*を宣言してい" +"ます。" #. type: Plain text #: text/chapter6.md:41 @@ -20032,7 +21024,8 @@ msgid "" "type class_." msgstr "" "このコードは `showBool​​ean`という名前の型クラスのインスタンスを宣言します。\n" -"PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインスタンスに名前を付けられます。\n" +"PureScriptでは、生成されたJavaScriptの可読性を良くするために、型クラスインス" +"タンスに名前を付けられます。\n" "このとき、`Boolean`型は*`Show`型クラスに属している*といいます。" #. type: Plain text @@ -20073,7 +21066,9 @@ msgstr "" 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`できます。" +msgstr "" +"この例では様々な原始型の値を `show`しましたが、もっと複雑な型を持つ値も`show`" +"できます。" #. type: Fenced code block (text) #: text/chapter6.md:69 @@ -20108,8 +21103,10 @@ msgid "" "without quotes. Ignore the `unit` print – that will be covered in Chapter 8 " "when we examine `Effect`s, like `log`." msgstr "" -"`show`の出力は、REPLに(あるいは`.purs`ファイルに)貼り戻せば、表示されたものを再作成できるような文字列であるべきです。\n" -"以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出すものであり、引用符なしに文字列が表示されます。\n" +"`show`の出力は、REPLに(あるいは`.purs`ファイルに)貼り戻せば、表示されたもの" +"を再作成できるような文字列であるべきです。\n" +"以下では`logShow`を使っていますが、これは単に`show`と`log`を順に呼び出すもの" +"であり、引用符なしに文字列が表示されます。\n" "`unit`の表示は無視してください。\n" "第8章で`log`のような`Effect`を調べるときに押さえます。" @@ -20142,7 +21139,8 @@ msgstr "" msgid "" "If we try to show a value of type `Data.Either`, we get an interesting error " "message:" -msgstr "型 `Data.Either`の値を表示しようとすると、興味深いエラー文言が表示されます。" +msgstr "" +"型 `Data.Either`の値を表示しようとすると、興味深いエラー文言が表示されます。" #. type: Fenced code block (text) #: text/chapter6.md:97 @@ -20173,7 +21171,8 @@ msgid "" "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がこの型を推論できなかったということです。\n" +"ここでの問題は `show`しようとしている型に対する `Show`インスタンスが存在しな" +"いということではなく、PSCiがこの型を推論できなかったということです。\n" "これは推論された型で*未知の型*`a`とされていることが示しています。" #. type: Plain text @@ -20181,7 +21180,9 @@ msgstr "" msgid "" "We can annotate the expression with a type using the `::` operator, so that " "PSCi can choose the correct type class instance:" -msgstr "`::`演算子を使って式に註釈を付けてPSCiが正しい型クラスインスタンスを選べるようにできます。" +msgstr "" +"`::`演算子を使って式に註釈を付けてPSCiが正しい型クラスインスタンスを選べるよ" +"うにできます。" #. type: Fenced code block (text) #: text/chapter6.md:112 @@ -20441,8 +21442,10 @@ msgid "" "provided to abstract over those operators, so that they can be reused where " "appropriate." msgstr "" -"`Field`型クラスは加算、減算、乗算、除算などの数値演算子に対応した型を示します。\n" -"これらの演算子を抽象化して提供されているので、適切な場合に再利用できるのです。" +"`Field`型クラスは加算、減算、乗算、除算などの数値演算子に対応した型を示しま" +"す。\n" +"これらの演算子を抽象化して提供されているので、適切な場合に再利用できるので" +"す。" #. type: Plain text #: text/chapter6.md:197 @@ -20468,10 +21471,14 @@ msgid "" "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`型クラスは、幾つかのより抽象的な*上位クラス*が組み合わさってできています。\n" -"このため、`Field`の操作の全てを提供しているわけではないが、その一部を提供する型について抽象的に説明できます。\n" -"例えば、自然数の型は加算及び乗算については閉じていますが、減算については必ずしも閉じていません。\n" -"そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタンスですが、`Ring`や`Field`のインスタンスではありません。" +"`Field`型クラスは、幾つかのより抽象的な*上位クラス*が組み合わさってできていま" +"す。\n" +"このため、`Field`の操作の全てを提供しているわけではないが、その一部を提供する" +"型について抽象的に説明できます。\n" +"例えば、自然数の型は加算及び乗算については閉じていますが、減算については必ず" +"しも閉じていません。\n" +"そのため、この型は`Semiring`クラス(これは`Num`の上位クラスです)のインスタン" +"スですが、`Ring`や`Field`のインスタンスではありません。" #. type: Plain text #: text/chapter6.md:205 @@ -20563,8 +21570,10 @@ msgid "" "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" +"ある型にとっての`Monoid`型クラスインスタンスとは、「空」の値から始めて新たな" +"結果に組み合わせ、その型を持つ結果を*累算*する方法を記述するものです。\n" +"例えば、畳み込みを使って何らかのモノイドの値の配列を連結する関数を書けま" +"す。\n" "PSCiで以下の通りです。" #. type: Fenced code block (haskell) @@ -20658,7 +21667,9 @@ msgid "" "when we first encountered folds over arrays." msgstr "" "`f`を配列の型構築子として特殊化すると分かりやすいです。\n" -"この場合、任意の`a`について`f a`を`Array a`に置き換えられますが、そうすると`foldl`と`foldr`の型が、最初に配列に対する畳み込みで見た型になると気付きます。" +"この場合、任意の`a`について`f a`を`Array a`に置き換えられますが、そうすると" +"`foldl`と`foldr`の型が、最初に配列に対する畳み込みで見た型になると気付きま" +"す。" #. type: Plain text #: text/chapter6.md:262 @@ -20699,7 +21710,8 @@ msgid "" msgstr "" "ここでは文字列用のモノイドと`show`関数を選んでいます。\n" "前者は文字列を連結するもので、後者は`Int`を文字列として書き出すものです。\n" -"そうして数の配列を渡すと、それぞれの数を`show`して1つの文字列へと連結した結果を得ました。" +"そうして数の配列を渡すと、それぞれの数を`show`して1つの文字列へと連結した結果" +"を得ました。" #. type: Plain text #: text/chapter6.md:275 @@ -20710,7 +21722,9 @@ msgid "" "types. `Foldable` captures the notion of an _ordered container_." msgstr "" "しかし畳み込み可能な型は配列だけではありません。\n" -"`foldable-traversable`では`Maybe`や`Tuple`のような型にも`Foldable`インスタンスが定義されており、`lists`のような他のライブラリでは、各々のデータ型に対して`Foldable`インスタンスが定義されています。\n" +"`foldable-traversable`では`Maybe`や`Tuple`のような型にも`Foldable`インスタン" +"スが定義されており、`lists`のような他のライブラリでは、各々のデータ型に対して" +"`Foldable`インスタンスが定義されています。\n" "`Foldable`は*順序付きコンテナ*の概念を見据えたものなのです。" #. type: Title ### @@ -20728,9 +21742,11 @@ msgid "" "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では、副作用を伴う関数型プログラミングのスタイルを可能にするための型クラスの集まりも定義されています。\n" +"PureScriptでは、副作用を伴う関数型プログラミングのスタイルを可能にするための" +"型クラスの集まりも定義されています。\n" "`Functor`や`Applicative`、`Monad`といったものです。\n" -"これらの抽象化については後ほど本書で扱いますが、ここでは`Functor`型クラスの定義を見てみましょう。\n" +"これらの抽象化については後ほど本書で扱いますが、ここでは`Functor`型クラスの定" +"義を見てみましょう。\n" "既に`map`関数の形で見たものです。" #. type: Fenced code block (haskell) @@ -20837,7 +21853,8 @@ msgid "" "composition of the two functions over the structure." msgstr "" "第2の法則は*合成律*です。\n" -"構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写すのと同じだ、と言っています。" +"構造を1つの関数で写してから2つめの関数で写すのは、2つの関数の合成で構造を写す" +"のと同じだ、と言っています。" #. type: Plain text #: text/chapter6.md:314 @@ -20925,8 +21942,11 @@ msgid "" "`Data.Newtype` and derive a `Newtype` instance for `Complex`." msgstr "" "(普通)`Semiring`インタンスを`Complex`に定義してください。\n" -"*補足*:[`Data.Newtype`](https://pursuit.purescript.org/packages/purescript-newtype/docs/Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答を作れます。\n" -"もしそうするのでしたら、`Data.Newtype`から`class Newtype`をインポートしたり、`Newtype`インスタンスを`Complex`に導出したりする必要も出てくるでしょう。" +"*補足*:[`Data.Newtype`](https://pursuit.purescript.org/packages/purescript-" +"newtype/docs/Data.Newtype)の`wrap`と`over2`を使ってより簡潔な解答を作れま" +"す。\n" +"もしそうするのでしたら、`Data.Newtype`から`class Newtype`をインポートしたり、" +"`Newtype`インスタンスを`Complex`に導出したりする必要も出てくるでしょう。" #. type: Bullet: '4. ' #: text/chapter6.md:336 @@ -20992,7 +22012,8 @@ msgid "" msgstr "" "型クラスを使うと、関数の型に制約を加えられます。\n" "例を示しましょう。\n" -"`Eq`型クラスインスタンスを使って定義された等値性を使って、3つの値が等しいかどうかを調べる関数を書きたいとします。" +"`Eq`型クラスインスタンスを使って定義された等値性を使って、3つの値が等しいかど" +"うかを調べる関数を書きたいとします。" #. type: Fenced code block (haskell) #: text/chapter6.md:349 @@ -21100,12 +22121,17 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter6.md:380 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> import Prelude\n" +#| "\n" +#| "> :type \\x -> x + x\n" +#| "forall a. Semiring a => a -> a\n" 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" @@ -21279,7 +22305,10 @@ 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 that " "includes an extra element at the front:" -msgstr "(難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持っている)ような型構築子 `f`が与えられたとき、追加の要素を先頭に含める新たなコンテナ型を作れます。" +msgstr "" +"(難しい)順序付きコンテナを定義する(そして `Foldable`のインスタンスを持って" +"いる)ような型構築子 `f`が与えられたとき、追加の要素を先頭に含める新たなコン" +"テナ型を作れます。" #. type: Plain text #: text/chapter6.md:440 @@ -21430,7 +22459,8 @@ msgid "" "elements of a stream:" msgstr "" "任意のストリーム上で動作する関数を記述できます。\n" -"例えば、ストリームの要素に基づいて `Monoid`に結果を累算する関数は次のようになります。" +"例えば、ストリームの要素に基づいて `Monoid`に結果を累算する関数は次のようにな" +"ります。" #. type: Fenced code block (haskell) #: text/chapter6.md:483 @@ -21477,8 +22507,10 @@ msgid "" "consider writing a generic `tail` function on streams using the `Stream` " "class given above:" msgstr "" -"多変数型クラスは非常に便利ですが、紛らわしい型や型推論の問題にも繋がります。\n" -"単純な例として、上記で与えられた`Stream`クラスを使い、ストリームに対して汎用的な`tail`関数を書くことを考えてみましょう。" +"多変数型クラスは非常に便利ですが、紛らわしい型や型推論の問題にも繋がりま" +"す。\n" +"単純な例として、上記で与えられた`Stream`クラスを使い、ストリームに対して汎用" +"的な`tail`関数を書くことを考えてみましょう。" #. type: Fenced code block (haskell) #: text/chapter6.md:500 @@ -21564,7 +22596,8 @@ msgid "" "`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) @@ -21594,10 +22627,16 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter6.md:541 -#, no-wrap +#, fuzzy, no-wrap +#| msgid "" +#| "> :type genericTail\n" +#| "forall stream element. Stream stream element => stream -> Maybe stream\n" +#| "\n" +#| "> genericTail \"testing\"\n" +#| "(Just \"esting\")\n" 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" @@ -21613,7 +22652,9 @@ msgstr "" msgid "" "Functional dependencies can be useful when designing certain APIs using " "multi-parameter type classes." -msgstr "多変数の型クラスを使用して何らかのAPIを設計する場合、関数従属性が便利なことがあります。" +msgstr "" +"多変数の型クラスを使用して何らかのAPIを設計する場合、関数従属性が便利なことが" +"あります。" #. type: Title ## #: text/chapter6.md:551 @@ -21629,7 +22670,8 @@ msgid "" "global properties of our code in the type system." msgstr "" "ゼロ個の型変数を持つ型クラスさえも定義できます。\n" -"これらは関数に対するコンパイル時の表明に対応しており、型システム内においてそのコードの大域的な性質を把握できます。" +"これらは関数に対するコンパイル時の表明に対応しており、型システム内においてそ" +"のコードの大域的な性質を把握できます。" #. type: Plain text #: text/chapter6.md:556 @@ -21640,7 +22682,8 @@ msgid "" "array without wrapping them in a `Maybe`, so they can fail if the array is " "empty:" msgstr "" -"重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあります。\n" +"重要な一例として、前に部分関数についてお話しした際に見た`Partial`クラスがあり" +"ます。\n" "`Data.Array.Partial`に定義されている関数`head`と`tail`を例に取りましょう。\n" "この関数は配列の先頭と尾鰭を`Maybe`に包むことなく取得できます。\n" "そのため配列が空のときに失敗する可能性があります。" @@ -21784,10 +22827,13 @@ msgid "" "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:605 @@ -21800,10 +22846,15 @@ msgid "" "evaluates to `EQ`. This relationship on the level of laws justifies the " "superclass relationship between `Eq` and `Ord`." msgstr "" -"一般に、下位クラスの法則が上位クラスの構成要素に言及しているとき、上位クラス関係を定義するのは筋が通っています。\n" -"例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インスタンスの下で同値であるなら、`compare`関数は`EQ`を返すはずだと推定するのは理に適っています。\n" -"言い換えれば、`a == b`が真であるのは`compare a b`が厳密に`EQ`に評価されるときなのです。\n" -"法則のレベルでのこの関係は、`Eq`と`Ord`の間の上位クラス関係の正当性を示します。" +"一般に、下位クラスの法則が上位クラスの構成要素に言及しているとき、上位クラス" +"関係を定義するのは筋が通っています。\n" +"例えば、任意の`Ord`と`Eq`のインスタンスの対について、もし2つの値が`Eq`インス" +"タンスの下で同値であるなら、`compare`関数は`EQ`を返すはずだと推定するのは理に" +"適っています。\n" +"言い換えれば、`a == b`が真であるのは`compare a b`が厳密に`EQ`に評価されるとき" +"なのです。\n" +"法則のレベルでのこの関係は、`Eq`と`Ord`の間の上位クラス関係の正当性を示しま" +"す。" #. type: Plain text #: text/chapter6.md:607 @@ -21812,7 +22863,8 @@ msgid "" "\"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. ' @@ -21823,7 +22875,8 @@ msgid "" "function in PSCi using `unsafePartial`. _Hint_: Use the `maximum` function " "from `Data.Foldable`." msgstr "" -"(普通)部分関数`unsafeMaximum :: Partial => Array Int -> Int`を定義してください。\n" +"(普通)部分関数`unsafeMaximum :: Partial => Array Int -> Int`を定義してくだ" +"さい。\n" "この関数は空でない整数の配列の最大値を求めます。\n" "`unsafePartial`を使ってPSCiで関数を試してください。\n" "*手掛かり*:`Data.Foldable`の`maximum`関数を使います。" @@ -21833,7 +22886,9 @@ msgstr "" msgid "" "(Medium) The `Action` class is a multi-parameter type class that defines an " "action of one type on another:" -msgstr "(普通)次の `Action`クラスは、ある型の別の型での動作を定義する、多変数型クラスです。" +msgstr "" +"(普通)次の `Action`クラスは、ある型の別の型での動作を定義する、多変数型クラ" +"スです。" #. type: Plain text #: text/chapter6.md:617 @@ -21941,9 +22996,11 @@ msgid "" "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" +"PureScriptは同じインスタンスの複数の実装を許さないため、元の実装を置き換える" +"必要があるでしょう。\n" "*補足*:テストでは4つの実装を押さえています。" #. type: Bullet: '1. ' @@ -22086,7 +23143,8 @@ msgid "" "this should provide the intuition for the following type class:" msgstr "" "最初の性質はちゃんとした型クラスの法則のように見えます。\n" -"その一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型システムによって確実に強制できるようなものではなさそうです。\n" +"その一方で、2番目の性質はよりくだけた規約の条項のようなもので、PureScriptの型" +"システムによって確実に強制できるようなものではなさそうです。\n" "しかし、これは型クラスから次のような直感が得られるでしょう。" #. type: Fenced code block (haskell) @@ -22138,8 +23196,10 @@ msgid "" "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) @@ -22253,10 +23313,12 @@ msgid "" "because there are no values of those types that are equal in the sense of " "`Eq` but not equal identically." msgstr "" -"これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証明するにはどうしたらいいでしょうか。\n" +"これらの `Hashable`インスタンスが先ほどの型クラスの法則を満たしていることを証" +"明するにはどうしたらいいでしょうか。\n" "同じ値が等しいハッシュコードを持っていることを確認する必要があります。\n" "`Int`、`Char`、`String`、`Boolean`のような場合は単純です。\n" -"`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しないからです。" +"`Eq`の意味では同じ値でも厳密には同じではない、というような型の値は存在しない" +"からです。" #. type: Plain text #: text/chapter6.md:739 @@ -22271,11 +23333,16 @@ msgid "" "the `Hashable (Array a)` obeys the type class law as well." msgstr "" "もっと面白い型についてはどうでしょうか。\n" -"`Array`インスタンスの型クラスの法則を証明するにあたっては、配列の長さに関する帰納を使えます。\n" +"`Array`インスタンスの型クラスの法則を証明するにあたっては、配列の長さに関する" +"帰納を使えます。\n" "長さゼロの唯一の配列は `[]`です。\n" -"配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じで配列の残りの部分が等しいとき、またその時に限り等しくなります。\n" -"この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし `Hashable a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を持つことがわかります。\n" -"したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型クラス法則に従います。" +"配列の `Eq`の定義により、任意の2つの空でない配列は、それらの先頭の要素が同じ" +"で配列の残りの部分が等しいとき、またその時に限り等しくなります。\n" +"この帰納的な仮定により、配列の残りの部分は同じハッシュ値を持ちますし、もし " +"`Hashable a`インスタンスがこの法則を満たすなら、先頭の要素も同じハッシュ値を" +"持つことがわかります。\n" +"したがって、2つの配列は同じハッシュ値を持ち、`Hashable (Array a)`も同様に型ク" +"ラス法則に従います。" #. type: Plain text #: text/chapter6.md:741 @@ -22306,9 +23373,12 @@ msgid "" "`nubByEq` function in `Data.Array` should make this task much simpler." msgstr "" "(普通)関数`arrayHasDuplicates`を書いてください。\n" -"この関数はハッシュと値の同値性に基づいて配列が重複する要素を持っているかどうかを調べます。\n" -"まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対が見付かったら`==`で値の同値性を確認してください。\n" -"*手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるでしょう。" +"この関数はハッシュと値の同値性に基づいて配列が重複する要素を持っているかどう" +"かを調べます。\n" +"まずハッシュ同値性を`hashEqual`関数で確認し、それからもし重複するハッシュの対" +"が見付かったら`==`で値の同値性を確認してください。\n" +"*手掛かり*:`Data.Array`の `nubByEq`関数はこの問題をずっと簡単にしてくれるで" +"しょう。" #. type: Bullet: ' 1. ' #: text/chapter6.md:747 @@ -22361,9 +23431,11 @@ msgid "" "and defined our own library based on a type class for computing hash codes." msgstr "" "この章では*型クラス*を導入しました。\n" -"型クラスは型に基づく抽象化で、コードの再利用のために強力な形式化ができます。\n" +"型クラスは型に基づく抽象化で、コードの再利用のために強力な形式化ができま" +"す。\n" "PureScriptの標準ライブラリから標準の型クラスを幾つか見てきました。\n" -"また、ハッシュ値を計算するための型クラスに基づく独自のライブラリを定義しました。" +"また、ハッシュ値を計算するための型クラスに基づく独自のライブラリを定義しまし" +"た。" #. type: Plain text #: text/chapter6.md:761 @@ -22375,9 +23447,11 @@ msgid "" "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" -"そちらではプログラミング言語の性質と型システムがプログラムを論理的に追究するために使われています。\n" +"そちらではプログラミング言語の性質と型システムがプログラムを論理的に追究する" +"ために使われています。\n" "これは重要な考え方で、本書では今後あらゆる箇所で立ち返る話題となるでしょう。" #. type: Title ## @@ -22400,7 +23474,8 @@ msgstr "" "`Applicative`型クラスによって表現される*アプリカティブ関手*です。\n" "名前が難しそうに思えても心配しないでください。\n" "フォームデータの検証という実用的な例を使ってこの概念の動機付けをします。\n" -"アプリカティブ関手の技法があることにより、通常であれば大量の決まり文句の検証を伴うようなコードを、簡潔で宣言的なフォームの記述へと変えられます。" +"アプリカティブ関手の技法があることにより、通常であれば大量の決まり文句の検証" +"を伴うようなコードを、簡潔で宣言的なフォームの記述へと変えられます。" #. type: Plain text #: text/chapter7.md:8 @@ -22470,8 +23545,10 @@ msgid "" "the types in our project and the `Data.AddressBook.Validation` module " "contains validation rules for those types." msgstr "" -"`Data.AddressBook`モジュールにはこのプロジェクトのデータ型とそれらの型に対する`Show`インスタンスが定義されています。\n" -"また、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれています。" +"`Data.AddressBook`モジュールにはこのプロジェクトのデータ型とそれらの型に対す" +"る`Show`インスタンスが定義されています。\n" +"また、`Data.AddressBook.Validation`モジュールにはそれらの型の検証規則が含まれ" +"ています。" #. type: Title ## #: text/chapter7.md:22 @@ -22493,7 +23570,9 @@ msgstr "" msgid "" "The source code for this module defines a function `address` that has the " "following type:" -msgstr "このモジュールのソースコードでは、次の型を持つ`address`関数が定義されています。" +msgstr "" +"このモジュールのソースコードでは、次の型を持つ`address`関数が定義されていま" +"す。" #. type: Fenced code block (haskell) #: text/chapter7.md:28 @@ -22667,10 +23746,13 @@ msgstr "`lift3`の型を見てみるとわかりやすいでしょう。" #. type: Fenced code block (text) #: text/chapter7.md:87 -#, no-wrap +#, fuzzy, 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" 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" @@ -22696,7 +23778,9 @@ msgid "" "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`で包まれた新しい関数へと持ち上げられる、ということです。" +msgstr "" +"この型で書かれているのは、3引数の任意の関数を取り、その関数を引数と返り値が" +"`Maybe`で包まれた新しい関数へと持ち上げられる、ということです。" #. type: Plain text #: text/chapter7.md:101 @@ -22706,8 +23790,10 @@ 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`に対する型クラス制約から`Apply`型クラスを取り除いていました。\n" +"勿論、どんな型構築子`f`についても持ち上げができるわけではないのですが、それで" +"は`Maybe`型を持ち上げができるようにしているものは何なのでしょうか。\n" +"さて、先ほどの型の特殊化では、`f`に対する型クラス制約から`Apply`型クラスを取" +"り除いていました。\n" "`Apply`はPreludeで次のように定義されています。" #. type: Fenced code block (haskell) @@ -22742,8 +23828,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)(中置で`$`)とは異なります。\n" -"幸いにも後者はほぼ常に中置記法として使われるので、名前の衝突については心配ご無用です。" +"なお、この[`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 @@ -22785,7 +23875,10 @@ msgstr "" 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 "この型クラスのインスタンスで書かれているのは、任意の省略可能な値に省略可能な関数を適用でき、その両方が定義されている時に限り結果も定義される、ということです。" +msgstr "" +"この型クラスのインスタンスで書かれているのは、任意の省略可能な値に省略可能な" +"関数を適用でき、その両方が定義されている時に限り結果も定義される、ということ" +"です。" #. type: Plain text #: text/chapter7.md:129 @@ -22886,9 +23979,11 @@ msgid "" "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記法*が同じ目的で使えます。\n" +"この代わりに、お馴染の*do記法*に似た見た目の*アプリカティブdo記法*が同じ目的" +"で使えます。\n" "以下では`lift3`に*アプリカティブdo記法*を使っています。\n" -"なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で`in`が使われています。" +"なお、`ado`が`do`の代わりに使われており、生み出された値を示すために最後の行で" +"`in`が使われています。" #. type: Fenced code block (haskell) #: text/chapter7.md:165 @@ -22974,7 +24069,9 @@ msgid "" "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`は引数のない関数の持ち上げだというように考えられます。" +msgstr "" +"アプリカティブ関手は関数を持ち上げることを可能にする関手だと考えるとすると、" +"`pure`は引数のない関数の持ち上げだというように考えられます。" #. type: Title ## #: text/chapter7.md:200 @@ -23019,7 +24116,9 @@ msgstr "" msgid "" "`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`を使えます。" +msgstr "" +"`pure`は純粋な(副作用がない)値をより大きな言語へと持ち上げますし、関数につ" +"いては上で述べた通り`map`と`apply`を使えます。" #. type: Plain text #: text/chapter7.md:211 @@ -23103,9 +24202,12 @@ msgid "" "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 @@ -23192,7 +24294,8 @@ msgid "" "could indicate which field was incorrect in the response." msgstr "" "引数が不正のときにwebサービスからエラー応答を送り返せるのは良いことです。\n" -"しかし、どのフィールドが不正確なのかを応答で示せると、もっと良くなるでしょう。" +"しかし、どのフィールドが不正確なのかを応答で示せると、もっと良くなるでしょ" +"う。" #. type: Plain text #: text/chapter7.md:269 @@ -23202,8 +24305,10 @@ msgid "" "convert optional inputs into computations which can signal an error using " "`Either String`:" msgstr "" -"`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エラー文言を返せるようになります。\n" -"まずは`Either String`を使い、省略可能な入力からエラーを発信できる計算に変換する演算子を書きましょう。" +"`Meybe`上へ持ち上げる代わりに`Either String`上へ持ち上げるようにすると、エ" +"ラー文言を返せるようになります。\n" +"まずは`Either String`を使い、省略可能な入力からエラーを発信できる計算に変換す" +"る演算子を書きましょう。" #. type: Fenced code block (text) #: text/chapter7.md:270 @@ -23235,7 +24340,9 @@ msgstr "" msgid "" "Now we can lift over `Either String`, providing an appropriate error message " "for each parameter:" -msgstr "これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー文言を提供できるようになります。" +msgstr "" +"これで`Either String`上へ持ち上げることで、それぞれの引数について適切なエラー" +"文言を提供できるようになります。" #. type: Fenced code block (text) #: text/chapter7.md:282 @@ -23287,7 +24394,9 @@ msgstr "" msgid "" "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`の結果のどちらかを返します。" +msgstr "" +"これでこの関数は`Maybe`を使う3つの省略可能な引数を取り、`String`のエラー文言" +"か`String`の結果のどちらかを返します。" #. type: Plain text #: text/chapter7.md:309 @@ -23323,7 +24432,8 @@ msgid "" "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) @@ -23359,7 +24469,9 @@ msgid "" "As an example of working with applicative functors abstractly, this section " "will show how to write a function that generically combines side-effects " "encoded by an applicative functor `f`." -msgstr "抽象的にアプリカティブ関手を扱う例として、この節ではアプリカティブ関手`f`によって表現された副作用を一般的に組み合わせる関数を書く方法を示します。" +msgstr "" +"抽象的にアプリカティブ関手を扱う例として、この節ではアプリカティブ関手`f`に" +"よって表現された副作用を一般的に組み合わせる関数を書く方法を示します。" #. type: Plain text #: text/chapter7.md:335 @@ -23498,9 +24610,12 @@ msgid "" "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 @@ -23528,8 +24643,10 @@ msgid "" "`subMaybe`, `mulMaybe`, and `divMaybe`. _Hint_: Use `lift2`." msgstr "" "(普通)数値演算子`+`、`-`、`*`、`/`の別のバージョンを書いてください。\n" -"ただし省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた値を返します。\n" -"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けてください。\n" +"ただし省略可能な引数(つまり`Maybe`に包まれた引数)を扱って`Maybe`に包まれた" +"値を返します。\n" +"これらの関数には`addMaybe`、`subMaybe`、`mulMaybe`、`divMaybe`と名前を付けて" +"ください。\n" "*手掛かり*:`lift2`を使ってください。" #. type: Bullet: ' 1. ' @@ -23552,8 +24669,10 @@ msgid "" "optional computation with side-effects and returns a side-effecting " "computation with an optional result." msgstr "" -"(難しい)型`forall a f. Applicative f => Maybe (f a) -> f (Maybe a)`を持つ関数`combineMaybe`を書いてください。\n" -"この関数は副作用を持つ省略可能な計算を取り、省略可能な結果を持つ副作用のある計算を返します。" +"(難しい)型`forall a f. Applicative f => Maybe (f a) -> f (Maybe a)`を持つ関" +"数`combineMaybe`を書いてください。\n" +"この関数は副作用を持つ省略可能な計算を取り、省略可能な結果を持つ副作用のある" +"計算を返します。" #. type: Plain text #: text/chapter7.md:390 @@ -23563,8 +24682,10 @@ msgid "" "key functions exported by the `Data.AddressBook` module have the following " "types:" msgstr "" -"この章のソースコードでは住所録アプリケーションで使うであろう幾つかのデータ型が定義されています。\n" -"詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされる鍵となる関数は次のような型を持ちます。" +"この章のソースコードでは住所録アプリケーションで使うであろう幾つかのデータ型" +"が定義されています。\n" +"詳細はここでは割愛しますが、`Data.AddressBook`モジュールからエクスポートされ" +"る鍵となる関数は次のような型を持ちます。" #. type: Fenced code block (haskell) #: text/chapter7.md:391 @@ -23749,7 +24870,8 @@ msgid "" msgstr "" "`validation`ライブラリでは別のアプリカティブ関手も提供されています。\n" "これは`V`という名前で、何らかの*半群*でエラーを返せます。\n" -"例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、`String`の配列をエラーとして返せます。" +"例えば`V (Array String)`を使うと、新しいエラーを配列の最後に連結していき、" +"`String`の配列をエラーとして返せます。" #. type: Plain text #: text/chapter7.md:465 @@ -24025,7 +25147,9 @@ msgstr "{{#include ../exercises/chapter7/src/Data/AddressBook/Validation.purs:va msgid "" "`validatePhoneNumbers` uses a new function we haven't seen before – " "`traverse`." -msgstr "`validatePhoneNumbers`はこれまでに見たことのない新しい関数である`traverse`を使っています。" +msgstr "" +"`validatePhoneNumbers`はこれまでに見たことのない新しい関数である`traverse`を" +"使っています。" #. type: Plain text #: text/chapter7.md:565 @@ -24067,9 +25191,11 @@ msgid "" "reducing a structure to a single value). In addition, a traversable functor " "can combine a collection of side-effects that depend on its structure." msgstr "" -"全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能関手*は畳み込み操作に対応する型構築子であったことを思い出してください。\n" +"全ての巡回可能関手は`Functor`と`Foldable`のどちらでもあります(*畳み込み可能" +"関手*は畳み込み操作に対応する型構築子であったことを思い出してください。\n" "畳み込みとは構造を1つの値へと簡約するものでした)。\n" -"それに加えて、巡回可能関手はその構造に依存した副作用の集まりを組み合わせられます。" +"それに加えて、巡回可能関手はその構造に依存した副作用の集まりを組み合わせられ" +"ます。" #. type: Plain text #: text/chapter7.md:577 @@ -24128,16 +25254,21 @@ msgid "" "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 msgid "" "In general, `traverse` walks over the elements of a data structure, " "performing computations with side-effects and accumulating a result." -msgstr "一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算し、結果を累算します。" +msgstr "" +"一般に、`traverse`はデータ構造の要素を1つずつ辿っていき、副作用を伴いつつ計算" +"し、結果を累算します。" #. type: Plain text #: text/chapter7.md:595 @@ -24177,7 +25308,8 @@ msgid "" msgstr "" "巡回可能関手はデータ構造走査の考え方を見据えたものです。\n" "これにより作用のある計算の集合を集めてその作用を結合します。\n" -"実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくらい重要です。\n" +"実際、`sequence`と`traversable`は`Traversable`を定義する上でどちらも同じくら" +"い重要です。\n" "これらはお互いがお互いを利用して実装できます。\n" "これについては興味ある読者への演習として残しておきます。" @@ -24223,9 +25355,11 @@ msgid "" "applicative functor `m` to combine the two results." msgstr "" "入力が空のリストのときには、`pure`を使って空のリストを返せます。\n" -"リストが空でないときは、関数`f`を使うと先頭の要素から型`f b`の計算を作成できます。\n" +"リストが空でないときは、関数`f`を使うと先頭の要素から型`f b`の計算を作成でき" +"ます。\n" "また、尾鰭に対して`traverse`を再帰的に呼び出せます。\n" -"最後に、アプリカティブ関手`m`まで`Cons`構築子を持ち上げて、2つの結果を組み合わせられます。" +"最後に、アプリカティブ関手`m`まで`Cons`構築子を持ち上げて、2つの結果を組み合" +"わせられます。" #. type: Plain text #: text/chapter7.md:622 @@ -24277,8 +25411,10 @@ msgid "" "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`の省略可能な値についての検証関数を返すのです。" +"これらの例では、`Nothing`の値の走査は検証なしで`Nothing`の値を返し、`Just x`" +"を走査すると`x`を検証するのに検証関数が使われるということを示しています。\n" +"要は、`traverse`は型`a`についての検証関数を取り、`Maybe a`についての検証関" +"数、つまり型`a`の省略可能な値についての検証関数を返すのです。" # FIXME: Arrayに型変数を入れた方が種として分かりやすそうです。 #. type: Plain text @@ -24289,9 +25425,12 @@ msgid "" "`Traversable` instances. As an example, the exercises will include writing a " "`Traversable` instance for a type of binary trees." msgstr "" -"他の巡回可能関手には、任意の型`a`についての`Array a`、`Tuple a`、`Either a`が含まれます。\n" -"一般に、「容器」のようなほとんどのデータ型構築子は`Traversable`インスタンスを持っています。\n" -"一例として、演習には二分木の型の`Traversable`インスタンスを書くことが含まれます。" +"他の巡回可能関手には、任意の型`a`についての`Array a`、`Tuple a`、`Either a`が" +"含まれます。\n" +"一般に、「容器」のようなほとんどのデータ型構築子は`Traversable`インスタンスを" +"持っています。\n" +"一例として、演習には二分木の型の`Traversable`インスタンスを書くことが含まれま" +"す。" #. type: Bullet: ' 1. ' #: text/chapter7.md:645 @@ -24390,8 +25529,10 @@ msgid "" "this new `Person`. _Hint_: Use `traverse` to validate a field of type `Maybe " "a`." msgstr "" -"(普通)`homeAddress`フィールドが省略可能(`Maybe`を使用)な新しい版の`Person`型をつくってください。\n" -"それからこの新しい`Person`を検証する新しい版の`validatePerson`(`validatePersonOptionalAddress`と改名します)を書いてください。\n" +"(普通)`homeAddress`フィールドが省略可能(`Maybe`を使用)な新しい版の" +"`Person`型をつくってください。\n" +"それからこの新しい`Person`を検証する新しい版の`validatePerson`" +"(`validatePersonOptionalAddress`と改名します)を書いてください。\n" "*手掛かり*:`traverse`を使って型`Maybe a`のフィールドを検証してください。" #. type: Bullet: ' 1. ' @@ -24446,7 +25587,8 @@ msgid "" "perform its side-effects in parallel." msgstr "" "しかし一般には、アプリカティブ関手はこれよりももっと一般的です。\n" -"アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しません。\n" +"アプリカティブ関手の規則は、その計算の副作用にどんな順序付けも強制しませ" +"ん。\n" "実際、並列に副作用を実行するアプリカティブ関手は妥当でしょう。" #. type: Plain text @@ -24457,7 +25599,9 @@ msgid "" "it would not matter what order we ran the various validators. We could even " "run them in parallel over the data structure!" msgstr "" -"例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだとしてもやはり正常に動き、このときどんな順序で各検証器を実行しても問題はありません。\n" +"例えば`V`検証関手はエラーの*配列*を返しますが、その代わりに`Set`半群を選んだ" +"としてもやはり正常に動き、このときどんな順序で各検証器を実行しても問題はあり" +"ません。\n" "データ構造に対して並列にこれの実行さえできるのです。" #. type: Plain text @@ -24468,8 +25612,10 @@ msgid "" "`parallel` that uses some `Applicative` functor to compute the result of its " "input computation _in parallel_:" msgstr "" -"2つ目の例として、`parallel`パッケージは*並列計算*に対応する`Parallel`型クラスを提供します。\n" -"`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入力の計算の結果を*並列に*計算します。" +"2つ目の例として、`parallel`パッケージは*並列計算*に対応する`Parallel`型クラス" +"を提供します。\n" +"`Parallel`は関数`parallel`を提供しており、何らかの`Applicative`関手を使って入" +"力の計算の結果を*並列に*計算します。" #. type: Fenced code block (haskell) #: text/chapter7.md:680 @@ -24521,7 +25667,8 @@ msgid "" "of side-effect." msgstr "" "*アプリカティブ関手*の概念を導入しました。\n" -"これは、関数適用の概念から副作用の観念を捉えた型構築子へと一般化するものです。" +"これは、関数適用の概念から副作用の観念を捉えた型構築子へと一般化するもので" +"す。" #. type: Bullet: '- ' #: text/chapter7.md:698 @@ -24531,8 +25678,10 @@ msgid "" "from reporting a single error to reporting all errors across a data " "structure." msgstr "" -"データ構造の検証という課題をアプリカティブ関手やその切り替えで解く方法を見てきました。\n" -"単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変更できました。" +"データ構造の検証という課題をアプリカティブ関手やその切り替えで解く方法を見て" +"きました。\n" +"単一のエラーの報告からデータ構造を横断する全てのエラーの報告へ変更できまし" +"た。" #. type: Bullet: '- ' #: text/chapter7.md:698 @@ -24556,10 +25705,14 @@ msgid "" "perform that validation. In general, we will see that applicative functors " "are a useful tool for the design of _domain specific languages." msgstr "" -"アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化です。\n" +"アプリカティブ関手は多くの問題に対して優れた解決策を与える興味深い抽象化で" +"す。\n" "本書を通じて何度も見ることになるでしょう。\n" -"今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、これにより検証器が*どうやって*検証を実施するかではなく、*何を*検証すべきなのかを定義できました。\n" -"一般にアプリカティブ関手が*領域特化言語*を設計する上で便利な道具になることを見ていきます。" +"今回の場合、アプリカティブ関手は宣言的な流儀で書く手段を提供していましたが、" +"これにより検証器が*どうやって*検証を実施するかではなく、*何を*検証すべきなの" +"かを定義できました。\n" +"一般にアプリカティブ関手が*領域特化言語*を設計する上で便利な道具になることを" +"見ていきます。" #. type: Plain text #: text/chapter7.md:701 @@ -24584,16 +25737,20 @@ msgid "" "validation. This chapter will introduce another abstraction for dealing with " "side-effects more expressively: _monads_." msgstr "" -"前章では、*副作用*を扱うのに使う抽象化であるアプリカティブ関手を導入しました。\n" +"前章では、*副作用*を扱うのに使う抽象化であるアプリカティブ関手を導入しまし" +"た。\n" "副作用とは省略可能な値、エラー文言、検証などです。\n" -"この章では、副作用を扱うためのより表現力の高い別の抽象化である*モナド*を導入します。" +"この章では、副作用を扱うためのより表現力の高い別の抽象化である*モナド*を導入" +"します。" #. type: Plain text #: text/chapter8.md:8 msgid "" "The goal of this chapter is to explain why monads are a useful abstraction " "and their connection with _do notation_." -msgstr "この章の目的は、なぜモナドが便利な抽象化なのかということと、*do記法*との関係を説明することです。" +msgstr "" +"この章の目的は、なぜモナドが便利な抽象化なのかということと、*do記法*との関係" +"を説明することです。" #. type: Plain text #: text/chapter8.md:12 @@ -24609,7 +25766,9 @@ msgid "" "explicitly." msgstr "" "`effect`: 章の後半の主題である`Effect`モナドを定義しています。\n" -"この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全ての章でも依存関係にありました)、明示的にインストールしなければいけないことは稀です。" +"この依存関係は全てのプロジェクトで始めから入っているものなので(これまでの全" +"ての章でも依存関係にありました)、明示的にインストールしなければいけないこと" +"は稀です。" #. type: Bullet: '- ' #: text/chapter8.md:15 @@ -24719,8 +25878,12 @@ msgid "" "the _array monad_, embedding PureScript functions into a larger programming " "language supporting _non-deterministic choice_." msgstr "" -"前の章では、*省略可能な値*に対応したより大きなプログラミング言語へとPureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養いました。\n" -"同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができます。" +"前の章では、*省略可能な値*に対応したより大きなプログラミング言語へと" +"PureScriptの関数を埋め込む、`Maybe`アプリカティブ関手についての直感的理解を養" +"いました。\n" +"同様に*配列モナド*についても、*非決定選択*に対応したより大きなプログラミング" +"言語へPureScriptの関数を埋め込む、というような直感的理解を得ることができま" +"す。" #. type: Plain text #: text/chapter8.md:52 @@ -24734,10 +25897,14 @@ msgid "" "`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 @@ -24803,7 +25970,8 @@ msgid "" "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" +"`userCity`関数は子の`profile`要素、`profile`要素の中にある`address`要素、最後" +"に`address`要素の中にある`city`要素を探します。\n" "これらの要素の何れかが欠落している場合、返り値は`Nothing`になります。\n" "そうでなければ、返り値は`city`ノードから`Just`を使って構築されます。" @@ -24856,7 +26024,9 @@ msgstr "ここで鍵となる関数は `Bind`型クラスで定義されてい msgid "" "The `Monad` type class extends `Bind` with the operations of the " "`Applicative` type class we've already seen." -msgstr "`Monad`型クラスは、既に見てきた`Applicative`型クラスの操作で`Bind`を拡張します。" +msgstr "" +"`Monad`型クラスは、既に見てきた`Applicative`型クラスの操作で`Bind`を拡張しま" +"す。" #. type: Plain text #: text/chapter8.md:92 @@ -24920,7 +26090,8 @@ msgid "" "some computation:" msgstr "" "`Bind`型クラスとdo記法がどのように関係しているかを見て行きましょう。\n" -"最初に、何らかの計算結果からの値の束縛から始まる、単純なdo記法ブロックについて考えてみましょう。" +"最初に、何らかの計算結果からの値の束縛から始まる、単純なdo記法ブロックについ" +"て考えてみましょう。" #. type: Fenced code block (hs) #: text/chapter8.md:112 @@ -25135,14 +26306,16 @@ msgid "" "`x`, and the result of `m2` is bound to the name `y`." msgstr "" "これらの各計算には3つのモナドの式`m1`、`m2`、`m3`が含まれています。\n" -"どちらの場合でも`m1`の結果は結局は名前`x`に束縛され、`m2`の結果は名前`y`に束縛されます。" +"どちらの場合でも`m1`の結果は結局は名前`x`に束縛され、`m2`の結果は名前`y`に束" +"縛されます。" #. type: Plain text #: text/chapter8.md:194 msgid "" "In `c1`, the two expressions `m1` and `m2` are grouped into their own do " "notation block." -msgstr "`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグループ化されています。" +msgstr "" +"`c1`では2つの式`m1`と`m2`が各do記法ブロック内にグループ化されています。" #. type: Plain text #: text/chapter8.md:196 @@ -25201,8 +26374,11 @@ msgid "" "programming \"in a larger language\" with side-effects, and also illustrate " "the generality which programming with monads brings." msgstr "" -"抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で機能する関数を紹介していきます。\n" -"これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと対応しているという直感的理解を補強しますし、モナドによるプログラミングが齎す一般性も示しています。" +"抽象的にモナドを扱う例として、この節では `Monad`型クラス中の任意の型構築子で" +"機能する関数を紹介していきます。\n" +"これはモナドによるコードが副作用を伴う「より大きな言語」でのプログラミングと" +"対応しているという直感的理解を補強しますし、モナドによるプログラミングが齎す" +"一般性も示しています。" #. type: Plain text #: text/chapter8.md:214 @@ -25238,7 +26414,9 @@ msgstr "" msgid "" "Intuitively, `foldM` performs a fold over a list in some context supporting " "some set of side-effects." -msgstr "直感的には、`foldM`は様々な副作用の組み合わせに対応した文脈で配列を畳み込むものと捉えられます。" +msgstr "" +"直感的には、`foldM`は様々な副作用の組み合わせに対応した文脈で配列を畳み込むも" +"のと捉えられます。" #. type: Plain text #: text/chapter8.md:225 @@ -25247,8 +26425,10 @@ msgid "" "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 @@ -25259,8 +26439,10 @@ msgid "" "of results would consist of all folds over all possible paths. This " "corresponds to a traversal of a graph!" msgstr "" -"もし`m`として型構築子`Array`を選ぶとすると、畳み込みの各段階で0以上の結果を返せるため、畳み込みは各結果に対して独立に次の手順を継続します。\n" -"最後に、結果の集まりは可能な経路の全ての畳み込みから構成されることになります。\n" +"もし`m`として型構築子`Array`を選ぶとすると、畳み込みの各段階で0以上の結果を返" +"せるため、畳み込みは各結果に対して独立に次の手順を継続します。\n" +"最後に、結果の集まりは可能な経路の全ての畳み込みから構成されることになりま" +"す。\n" "これはグラフの走査と対応していますね。" #. type: Plain text @@ -25286,7 +26468,8 @@ msgstr "foldM _ a Nil = pure a\n" #. type: Plain text #: text/chapter8.md:237 msgid "Note that we have to use `pure` to lift `a` into the monad `m`." -msgstr "なお、`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。" +msgstr "" +"なお、`a`をモナド `m`まで持ち上げるために `pure`を使わなくてはいけません。" #. type: Plain text #: text/chapter8.md:239 @@ -25378,7 +26561,8 @@ msgid "" "attempted at any point. Otherwise, it returns the result of repeatedly " "dividing the accumulator, wrapped in the `Just` constructor." msgstr "" -"もし何れかの時点で0による除算が試みられたら、`foldM safeDivide`関数は`Nothing`を返します。\n" +"もし何れかの時点で0による除算が試みられたら、`foldM safeDivide`関数は" +"`Nothing`を返します。\n" "そうでなければ、累算値を繰り返し除算した結果を`Just`構築子に包んで返します。" #. type: Title ## @@ -25436,7 +26620,8 @@ msgid "" "The interested reader can check that `ap` agrees with `apply` for the monads " "we have already encountered: `Array`, `Maybe`, and `Either e`." msgstr "" -"興味のある読者はこれまで登場したモナドについてこの`ap`が`apply`として充足することを確かめてみてください。\n" +"興味のある読者はこれまで登場したモナドについてこの`ap`が`apply`として充足する" +"ことを確かめてみてください。\n" "モナドは`Array`、`Maybe`、`Either e`といったものです。" #. type: Plain text @@ -25464,7 +26649,8 @@ msgid "" "notation. Consider the `userCity` example again, in which we looked for a " "user's city in an XML document that encoded their user profile:" msgstr "" -"しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法の構文で強調されています。\n" +"しかし、モナドはアプリカティブ関手でできること以上ができ、重要な違いはdo記法" +"の構文で強調されています。\n" "`userCity`の例についてもう一度考えてみましょう。\n" "利用者情報をエンコードしたXML文書から利用者の市町村を検索するものでした。" @@ -25505,8 +26691,10 @@ msgid "" "does not apply – a monad has to combine its side-effects in sequence." msgstr "" "前の章では`Applicative`型クラスは並列処理を表現できることを見ました。\n" -"持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りです。\n" -"`Monad`型クラスは計算が前の計算の結果に依存できるようになっており、同じようにはなりません。\n" +"持ち上げられた関数の引数は互いに独立していますから、これはまさにその通りで" +"す。\n" +"`Monad`型クラスは計算が前の計算の結果に依存できるようになっており、同じように" +"はなりません。\n" "つまりモナドは副作用を順番に組み合わせなければならないのです。" #. type: Bullet: ' 1. ' @@ -25518,9 +26706,11 @@ msgid "" "from the `Data.Array` module in the `arrays` package. Use do notation with " "the `Maybe` monad to combine these functions." msgstr "" -"(簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてください。\n" +"(簡単)3つ以上の要素がある配列の3つ目の要素を返す関数`third`を書いてくださ" +"い。\n" "関数は適切な`Maybe`型で返します。\n" -"*手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数の型を見つけ出してください。\n" +"*手掛かり*:`arrays`パッケージの`Data.Array`モジュールから`head`と`tail`関数" +"の型を見つけ出してください。\n" "これらの関数を組み合わせるには`Maybe`モナドと共にdo記法を使ってください。" #. type: Bullet: ' 1. ' @@ -25671,7 +26861,9 @@ msgstr "ネイティブな作用" msgid "" "We will now look at one particular monad of central importance in PureScript " "– the `Effect` monad." -msgstr "ここではPureScriptで中心的な重要性のあるモナドの1つ、`Effect`モナドについて見ていきます。" +msgstr "" +"ここではPureScriptで中心的な重要性のあるモナドの1つ、`Effect`モナドについて見" +"ていきます。" #. type: Plain text #: text/chapter8.md:358 @@ -25769,10 +26961,14 @@ msgid "" "is implemented at runtime." msgstr "" "これらの区別はわかりにくいので注意してください。\n" -"例えば、エラー文言は例外の形でJavaScriptの式の副作用となることがあると言えます。\n" -"その意味では例外はネイティブな副作用を表していて、`Effect`を使用して表現できます。\n" -"しかし、`Either`を使用して実装されたエラー文言はJavaScript実行時の副作用ではなく、`Effect`を使うスタイルでエラー文言を実装するのは不適切です。\n" -"そのため、ネイティブなのは作用自体というより、実行時にどのように実装されているかです。" +"例えば、エラー文言は例外の形でJavaScriptの式の副作用となることがあると言えま" +"す。\n" +"その意味では例外はネイティブな副作用を表していて、`Effect`を使用して表現でき" +"ます。\n" +"しかし、`Either`を使用して実装されたエラー文言はJavaScript実行時の副作用では" +"なく、`Effect`を使うスタイルでエラー文言を実装するのは不適切です。\n" +"そのため、ネイティブなのは作用自体というより、実行時にどのように実装されてい" +"るかです。" #. type: Title ## #: text/chapter8.md:381 @@ -25787,7 +26983,8 @@ msgid "" "side-effects, how can one write useful real-world code?" msgstr "" "PureScriptのような純粋な言語では、ある疑問が浮かんできます。\n" -"副作用がないなら、どうやって役に立つ実際のコードを書くことができるのでしょうか。" +"副作用がないなら、どうやって役に立つ実際のコードを書くことができるのでしょう" +"か。" #. type: Plain text #: text/chapter8.md:386 @@ -25798,7 +26995,8 @@ msgid "" "language is still pure." msgstr "" "その答えはPureScriptの目的は副作用を排除することではないということです。\n" -"純粋な計算と副作用のある計算とを、型システムにおいて区別できるような方法で表現します。\n" +"純粋な計算と副作用のある計算とを、型システムにおいて区別できるような方法で表" +"現します。\n" "この意味で、言語はあくまで純粋なのです。" #. type: Plain text @@ -25809,14 +27007,17 @@ msgid "" "and have side-effects performed unexpectedly." msgstr "" "副作用のある値は、純粋な値とは異なる型を持っています。\n" -"そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作用を持つようなことが起こらなくなります。" +"そういうわけで、例えば副作用のある引数を関数に渡すことはできず、予期せず副作" +"用を持つようなことが起こらなくなります。" #. type: Plain text #: text/chapter8.md:390 msgid "" "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から実行することです。" +msgstr "" +"`Effect`モナドで管理された副作用を現す手段は、型`Effect a`の計算をJavaScript" +"から実行することです。" #. type: Plain text #: text/chapter8.md:392 @@ -25825,7 +27026,8 @@ msgid "" "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" +"Spagoビルドツール(や他のツール)は早道を用意しており、アプリケーションの起動" +"時に`main`計算を呼び出すための追加のJavaScriptコードを生成します。\n" "`main`は`Effect`モナドでの計算であることが要求されます。" #. type: Plain text @@ -25845,7 +27047,8 @@ msgid "" "case." msgstr "" "馴染みのある`log`関数から返る型を見てみましょう。\n" -"`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコンソールIOです。" +"`Effect`はこの関数がネイティブな作用を生み出すことを示しており、この場合はコ" +"ンソールIOです。" #. type: Plain text #: text/chapter8.md:400 @@ -25986,11 +27189,16 @@ msgid "" "doesn't do much except encapsulate side effects." msgstr "" "以前言及したように`Effect`モナドはPureScriptで核心的な重要さがあります。\n" -"なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りする上での常套手段だからです。\n" -"`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕組みを提供します。\n" -"`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように動作しどう使うのか理解することもまた極めて大事なことですので、実際にPureScriptで何か動かす前にその章を読まれることをお勧めします。\n" +"なぜ核心かというと、それはPureScriptの`外部関数インターフェース`とやり取りす" +"る上での常套手段だからです。\n" +"`外部関数インターフェース`はプログラムを実行したり副作用を発生させたりする仕" +"組みを提供します。\n" +"`外部関数インターフェース`を使うことは避けるのが望ましいのですが、どのように" +"動作しどう使うのか理解することもまた極めて大事なことですので、実際に" +"PureScriptで何か動かす前にその章を読まれることをお勧めします。\n" "要は`Effect`モナドは結構単純なのです。\n" -"幾つかの補助関数がありますが、副作用を内包すること以外には大したことはしません。" +"幾つかの補助関数がありますが、副作用を内包すること以外には大したことはしませ" +"ん。" #. type: Plain text #: text/chapter8.md:447 @@ -26204,8 +27412,10 @@ msgid "" "type system." msgstr "" "`new`は型`STRef r a`の可変参照領域を新規作成するのに使われます。\n" -"この領域は`read`動作を使って読み取ったり、`write`動作や`modify`動作で状態を変更するのに使えます。\n" -"型`a`は領域に格納された値の型を、型`r`は*メモリ領域*(または*ヒープ*)を、それぞれ型システムで表しています。" +"この領域は`read`動作を使って読み取ったり、`write`動作や`modify`動作で状態を変" +"更するのに使えます。\n" +"型`a`は領域に格納された値の型を、型`r`は*メモリ領域*(または*ヒープ*)を、そ" +"れぞれ型システムで表しています。" #. type: Plain text #: text/chapter8.md:526 @@ -26286,7 +27496,8 @@ msgid "" "other program parts. We will see that this is exactly what the `ST` effect " "disallows." msgstr "" -"なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの他の部分での使用が許されない限り、これは純粋な関数のままです。\n" +"なお、この関数が変更可能な状態を使っていても、その参照領域`ref`がプログラムの" +"他の部分での使用が許されない限り、これは純粋な関数のままです。\n" "このことが正に`ST`作用が禁止するものであることを見ていきます。" #. type: Plain text @@ -26308,8 +27519,10 @@ msgid "" "the parentheses_ on the left of the function arrow. That means that whatever " "action we pass to `run` has to work with _any region_ `r` whatsoever." msgstr "" -"ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化されているということです。\n" -"`run`に渡したどんな動作でも、*任意の領域*`r`が何であれ動作するということを意味しています。" +"ここで注目して欲しいのは、領域型 `r`が関数矢印の左辺にある*括弧の内側で*量化" +"されているということです。\n" +"`run`に渡したどんな動作でも、*任意の領域*`r`が何であれ動作するということを意" +"味しています。" #. type: Plain text #: text/chapter8.md:563 @@ -26319,8 +27532,11 @@ msgid "" "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`によって限定されたコードの外側で参照領域を使おうとしても型エラーになるでしょう。\n" -"`run`が安全に`ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由なのです。" +"しかし、ひとたび参照領域が`new`によって作成されると、その領域の型は既に固定さ" +"れており、`run`によって限定されたコードの外側で参照領域を使おうとしても型エ" +"ラーになるでしょう。\n" +"`run`が安全に`ST`作用を除去でき、`simulate`を純粋関数にできるのはこれが理由な" +"のです。" #. type: Fenced code block (hs) #: text/chapter8.md:564 @@ -26425,8 +27641,10 @@ msgid "" "scope and can safely turn `ref` into a `var`. Here is the generated " "JavaScript for `simulate` inlined with `run`:" msgstr "" -"そうして、参照領域はそのスコープから逃れられないことと、安全に`ref`を`var`に変換できることにコンパイラが気付きます。\n" -"`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになります。" +"そうして、参照領域はそのスコープから逃れられないことと、安全に`ref`を`var`に" +"変換できることにコンパイラが気付きます。\n" +"`run`が埋め込まれた`simulate`に対して生成されたJavaScriptは次のようになりま" +"す。" #. type: Fenced code block (javascript) #: text/chapter8.md:611 @@ -26550,8 +27768,10 @@ msgid "" "locally-scoped mutable state, especially when used together with actions " "like `for`, `foreach`, and `while`, which generate efficient loops." msgstr "" -"局所的な変更可能状態を扱うとき、`ST`作用は短いJavaScriptを生成する良い方法となります。\n" -"作用を持つ繰り返しを生成する`for`、`foreach`、`while`のような動作を一緒に使うときは特にそうです。" +"局所的な変更可能状態を扱うとき、`ST`作用は短いJavaScriptを生成する良い方法と" +"なります。\n" +"作用を持つ繰り返しを生成する`for`、`foreach`、`while`のような動作を一緒に使う" +"ときは特にそうです。" #. type: Bullet: '1. ' #: text/chapter8.md:672 @@ -26623,7 +27843,9 @@ msgid "" "[`web-dom`](https://github.com/purescript-web/purescript-web-dom) provides " "type definitions and low-level interface implementations for the W3C DOM " "spec." -msgstr "[`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3CのDOM規格に向けた型定義と低水準インターフェース実装を提供します。" +msgstr "" +"[`web-dom`](https://github.com/purescript-web/purescript-web-dom)はW3CのDOM規" +"格に向けた型定義と低水準インターフェース実装を提供します。" #. type: Bullet: '- ' #: text/chapter8.md:682 @@ -26740,7 +27962,8 @@ msgid "" "validation errors will be updated." msgstr "" "利用者が住所録に新しい項目を追加できるフォームを構築することにしましょう。\n" -"フォームには、様々なフィールド(姓、名、市町村、州など)のテキストボックス、及び検証エラーが表示される領域が含まれます。\n" +"フォームには、様々なフィールド(姓、名、市町村、州など)のテキストボックス、" +"及び検証エラーが表示される領域が含まれます。\n" "テキストボックスに利用者がテキストを入力する度に、検証エラーが更新されます。" #. type: Plain text @@ -26758,7 +27981,9 @@ msgstr "" msgid "" "You can launch the web app from the `exercises/chapter8` directory with the " "following commands:" -msgstr "`exercises/chapter8`ディレクトリから以下のコマンドでwebアプリを立ち上げることができます。" +msgstr "" +"`exercises/chapter8`ディレクトリから以下のコマンドでwebアプリを立ち上げること" +"ができます。" #. type: Fenced code block (shell) #: text/chapter8.md:703 @@ -26812,7 +28037,9 @@ msgstr "" msgid "" "In this Address Book app, you can enter some values into the form fields and " "see the validation errors printed onto the page." -msgstr "このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上で出力された検証エラーが見られます。" +msgstr "" +"このアドレス帳アプリでフォームフィールドにいろいろな値を入力すると、ページ上" +"で出力された検証エラーが見られます。" #. type: Plain text #: text/chapter8.md:716 @@ -27026,7 +28253,9 @@ msgstr "" msgid "" "Next, we'll examine some of the additional complexities of the full Address " "Book component." -msgstr "次に、完全なアドレス帳コンポーネントにある幾つかの複雑な事柄を調べていきます。" +msgstr "" +"次に、完全なアドレス帳コンポーネントにある幾つかの複雑な事柄を調べていきま" +"す。" #. type: Plain text #: text/chapter8.md:800 @@ -27066,9 +28295,12 @@ msgid "" "app to use a separate piece of state for each record field of `Person`, but " "that results in a slightly less convenient architecture in this case." msgstr "" -"なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部品に分解することが自在にできます。\n" -"例えば`Person`の各レコードフィールドについて分離した状態の部品を使って、このアプリを書き直すことができるでしょう。\n" -"しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいます。" +"なお、複数回`useState`を呼び出すことで、コンポーネントの状態を複数の状態の部" +"品に分解することが自在にできます。\n" +"例えば`Person`の各レコードフィールドについて分離した状態の部品を使って、この" +"アプリを書き直すことができるでしょう。\n" +"しかしこの場合にそうすると僅かに利便性を損なうアーキテクチャになってしまいま" +"す。" #. type: Plain text #: text/chapter8.md:817 @@ -27302,7 +28534,8 @@ msgid "" "functions:" msgstr "" "ここでDOMの意図した状態を表現する`JSX`を生成しています。\n" -"このJSXは単一のHTML要素を作るHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、`label`、`input`)に対応する関数を適用することで作られるのが普通です。\n" +"このJSXは単一のHTML要素を作るHTMLタグ(例:`div`、`form`、`h3`、`li`、`ul`、" +"`label`、`input`)に対応する関数を適用することで作られるのが普通です。\n" "これらのHTML要素はそれ自体がReactコンポーネントであり、JSXに変換されます。\n" "通常これらの関数にはそれぞれ3つの種類があります。" @@ -27449,7 +28682,8 @@ msgid "" "for safety." msgstr "" "JavaScriptでは`input`要素の`onChange`イベントには`String`値が伴います。\n" -"しかし、JavaScriptの文字列はnullになり得るので、安全のために`Maybe`が使われています。" +"しかし、JavaScriptの文字列はnullになり得るので、安全のために`Maybe`が使われて" +"います。" #. type: Plain text #: text/chapter8.md:943 @@ -27499,7 +28733,9 @@ msgstr "" 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`フックに適切なレコード更新呼び出しを実施します。" +msgstr "" +"`setValue`は`formField`の各呼び出しに与えた関数で、文字列を取り`setPerson`" +"フックに適切なレコード更新呼び出しを実施します。" #. type: Plain text #: text/chapter8.md:963 @@ -27530,7 +28766,8 @@ msgid "" "way the component works." msgstr "" "これでコンポーネント実装の基本を押さえました。\n" -"しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随するソースをお読みください。" +"しかし、コンポーネントの仕組みを完全に理解するためには、この章に付随するソー" +"スをお読みください。" #. type: Plain text #: text/chapter8.md:973 @@ -27565,8 +28802,10 @@ msgid "" "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」背景に集め" +"て表示させています。\n" +"空行で分離することにより、各検証エラーにpink-alert背景を持たせるように変更し" +"てください。" #. type: Plain text #: text/chapter8.md:983 @@ -27648,7 +28887,8 @@ msgstr "`Monad`型クラスとdo記法との関係性を見ました。" msgid "" "We introduced the monad laws and saw how they allow us to transform code " "written using do notation." -msgstr "モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。" +msgstr "" +"モナド則を導入し、do記法を使って書かれたコードを変換する方法を見ました。" # monads can be usedが訳せているかどうか…… #. type: Bullet: '- ' @@ -27656,14 +28896,17 @@ msgstr "モナド則を導入し、do記法を使って書かれたコードを msgid "" "We saw how monads can be used abstractly to write code that works with " "different side-effects." -msgstr "異なる副作用を扱うコードを書く上で、モナドを抽象的に使う方法を見ました。" +msgstr "" +"異なる副作用を扱うコードを書く上で、モナドを抽象的に使う方法を見ました。" #. type: Bullet: '- ' #: 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." -msgstr "モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算を可能にするのかということ、そして2つの手法の違いを説明しました。" +msgstr "" +"モナドがアプリカティブ関手の一例であること、両者がどのように副作用のある計算" +"を可能にするのかということ、そして2つの手法の違いを説明しました。" #. type: Bullet: '- ' #: text/chapter8.md:1011 @@ -27680,7 +28923,9 @@ 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`モナドを使いました。" +msgstr "" +"乱数生成、例外、コンソール入出力、変更可能な状態、及びReactを使ったDOM操作と" +"いった、様々な作用を扱うために `Effect`モナドを使いました。" #. type: Plain text #: text/chapter8.md:1012 @@ -27709,7 +28954,8 @@ msgid "" msgstr "" "この章では`Aff`モナドに集中します。\n" "これは`Effect`モナドに似ていますが、*非同期*な副作用を表現するものです。\n" -"非同期にファイルシステムとやり取りしたりHTTPリクエストしたりする例を実演していきます。\n" +"非同期にファイルシステムとやり取りしたりHTTPリクエストしたりする例を実演して" +"いきます。\n" "また非同期作用の直列ないし並列な実行の管理方法も押さえます。" #. type: Plain text @@ -27744,7 +28990,8 @@ msgid "" "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`ライブラリには`xhr2`NPMモジュールが必要です。\n" +"(Node.js環境のような)ブラウザ外で実行する場合、`affjax`ライブラリには" +"`xhr2`NPMモジュールが必要です。\n" "このモジュールはこの章の`package.json`中の依存関係に挙げられています。\n" "以下を走らせてインストールします。" @@ -27875,8 +29122,10 @@ msgid "" "respectively), but those share the same downsides as discussed earlier with " "JavaScript, so that coding style is not recommended." msgstr "" -"上のコード片をコールバックや同期関数を使って書き換えることも可能です(例えば`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)。\n" -"しかし、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それらのコーディング形式は推奨されません。" +"上のコード片をコールバックや同期関数を使って書き換えることも可能です(例えば" +"`Node.FS.Async`や`Node.FS.Sync`をそれぞれ使います)。\n" +"しかし、JavaScriptで前にお話ししたのと同じ短所がここでも通用するため、それら" +"のコーディング形式は推奨されません。" #. type: Plain text #: text/chapter9.md:60 @@ -27966,7 +29215,8 @@ msgid "" "(Medium) Write a function `concatenateMany` to concatenate multiple text " "files, given an array of input and output file names. _Hint_: use `traverse`." msgstr "" -"(普通)複数のテキストファイルを連結する関数`concatenateMany`を書いてください。\n" +"(普通)複数のテキストファイルを連結する関数`concatenateMany`を書いてくださ" +"い。\n" "入力ファイル名の配列と出力ファイル名が与えられます。\n" "*手掛かり*:`traverse`を使ってください。" @@ -27994,8 +29244,10 @@ msgid "" "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で何らかの関数を見付けだす助けになるかもしれません。" +"もしまだ[公式のAffの手引き](https://pursuit.purescript.org/packages/" +"purescript-aff/)を見ていなければ、今ざっと目を通してください。\n" +"この章の残りの演習を完了する上で事前に直接必要なことではありませんが、Pursuit" +"で何らかの関数を見付けだす助けになるかもしれません。" #. type: Plain text #: text/chapter9.md:100 @@ -28037,8 +29289,12 @@ msgid "" "contrib/purescript-affjax-web) or the [purescript-affjax-node](https://" "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)のどちらかのライブラリを使う必要があります。" +"`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)のどちらか" +"のライブラリを使う必要があります。" #. type: Plain text #: text/chapter9.md:110 @@ -28049,9 +29305,12 @@ msgid "" "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要求をして、応答本文ないしエラー文言を返す例です。" +"この章の以降ではnodeを対象としていくので、`purescript-affjax-node`を使いま" +"す。\n" +"より詳しい使用上の情報は[affjaxのドキュメント](https://pursuit.purescript." +"org/packages/purescript-affjax)にあたってください。\n" +"以下は与えられたURLに向けてHTTPのGET要求をして、応答本文ないしエラー文言を返" +"す例です。" #. type: Fenced code block (hs) #: text/chapter9.md:111 @@ -28140,9 +29399,12 @@ msgid "" "a correspondence between a monad `m` (such as `Aff`) and an applicative " "functor `f` that can be used to combine computations in parallel:" msgstr "" -"`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義しており、並列実行に対応しています。\n" -"以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリカティブ関手がどれほど便利なのかを見ました。\n" -"実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を組み合わせるために使えるアプリカティブ関手`f`との対応関係を定義しているのです。" +"`parallel`パッケージは`Aff`のようなモナドのための型クラス`Parallel`を定義して" +"おり、並列実行に対応しています。\n" +"以前に本書でアプリカティブ関手に出会ったとき、並列計算を合成するときにアプリ" +"カティブ関手がどれほど便利なのかを見ました。\n" +"実は`Parallel`のインスタンスは、(`Aff`のような)モナド`m`と、並列に計算を組" +"み合わせるために使えるアプリカティブ関手`f`との対応関係を定義しているのです。" #. type: Fenced code block (hs) #: text/chapter9.md:144 @@ -28185,7 +29447,8 @@ msgid "" "continuation." msgstr "" "`aff`ライブラリは`Aff`モナドの`Parallel`インスタンスを提供します。\n" -"これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参照を使用して並列に`Aff`動作を組み合わせます。\n" +"これは、2つの継続のどちらが呼び出されたかを把握することによって、変更可能な参" +"照を使用して並列に`Aff`動作を組み合わせます。\n" "両方の結果が返されたら、最終結果を計算してメインの継続に渡せます。" #. type: Plain text @@ -28211,7 +29474,8 @@ msgid "" msgstr "" "直列的なコードの一部と並列計算を組み合わせることもできます。\n" "それにはdo記法ブロック中でアプリカティブコンビネータを使います。\n" -"その逆も然りで、必要に応じて`parralel`と`sequential`を使って型構築子を変更すれば良いのです。" +"その逆も然りで、必要に応じて`parralel`と`sequential`を使って型構築子を変更す" +"れば良いのです。" #. type: Plain text #: text/chapter9.md:164 @@ -28359,10 +29623,13 @@ msgid "" "directory of the file they appear in. _Hint:_ The `node-path` module has " "some helpful functions for negotiating directories." msgstr "" -"(難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてください。\n" +"(難しい)「根」のファイルを取り、そのファイルの中の全てのパスの一覧(そして" +"一覧にあるファイルの中の一覧も)の配列を返す`recurseFiles`関数を書いてくださ" +"い。\n" "一覧にあるファイルを並列に読んでください。\n" "パスはそのファイルが現れたディレクトリから相対的なものです。\n" -"*手掛かり*:`node-path`モジュールにはディレクトリを扱う上で便利な関数があります。" +"*手掛かり*:`node-path`モジュールにはディレクトリを扱う上で便利な関数がありま" +"す。" #. type: Plain text #: text/chapter9.md:212 @@ -28437,3 +29704,95 @@ msgstr "`affjax`ライブラリを使って非同期にHTTPリクエストする #: text/chapter9.md:244 msgid "Run asynchronous code in parallel with the `parallel` library." msgstr "`parallel`ライブラリを使って並列に非同期コードを走らせる。" + +#~ 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`だ" +#~ "けは、この規則の唯一の例外になっています。" From e78926ba035833202f873bdef1f37dc23b37508e Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:26:13 +0900 Subject: [PATCH 23/29] [ update ] translation for fuzzy/untranslated entries --- translation/ja.po | 387 +++++++++++++++--------------------------- translation/terms.txt | 2 + 2 files changed, 139 insertions(+), 250 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index d7485117..4b671de1 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-08-25 20:42+0900\n" -"PO-Revision-Date: 2023-08-25 08:51+0900\n" +"PO-Revision-Date: 2023-08-25 21:26+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -475,7 +475,7 @@ msgstr "" #: 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 "" +msgstr "> なお、PureScriptはJavaScriptのみならず他のバックエンドを対象にできますが、本書ではwebブラウザとnode環境に焦点を絞ります。\n" #. type: Title ## #: text/chapter1.md:43 @@ -1028,19 +1028,12 @@ msgstr "" #. type: Plain text #: text/chapter1.md:150 -#, fuzzy -#| 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." msgid "" "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コードの例が沢山あります。" +msgstr "もし例を読んで学ぶ方が好きでしたら、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:151 @@ -4484,11 +4477,8 @@ msgid "" "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" -"から使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" +"コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptのキーワードを避けることをお勧めします。\n" +"ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" #. type: Title ### #: text/chapter10.md:1155 @@ -14462,6 +14452,8 @@ msgid "" "functions. It re-exports many foundational modules from the `purescript-" "prelude` library." msgstr "" +"`Prelude`モジュールには標準的な定義と関数の小さな集合が含まれます。\n" +"`purescript-prelude`ライブラリから多くの基礎的なモジュールを再エクスポートしているのです。" #. type: Bullet: '- ' #: text/chapter3.md:25 @@ -14490,20 +14482,14 @@ msgstr "" #. type: Plain text #: text/chapter3.md:27 -#, fuzzy -#| 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." msgid "" "Notice that the imports for these modules are listed explicitly in " "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:29 @@ -14723,29 +14709,25 @@ msgstr "" #. type: Plain text #: text/chapter3.md:107 -#, fuzzy -#| msgid "" -#| "Functions can be defined at the top-level of a file by specifying " -#| "arguments before the equals sign:" msgid "" "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 "" -"ファイルの最上位では、等号の直前に引数を指定することで関数を定義できます。" +"PureScriptの関数はJavaScriptの関数に対応します。\n" +"関数はファイルの最上位で定義でき、等号の前に引数を指定します。" #. type: Fenced code block (haskell) #: text/chapter3.md:108 -#, fuzzy, no-wrap -#| msgid "" -#| "add :: Int -> Int -> Int\n" -#| "add x y = x + y\n" +#, 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" @@ -14765,12 +14747,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter3.md:117 -#, fuzzy, no-wrap -#| msgid "" -#| "> :paste\n" -#| "… add :: Int -> Int -> Int\n" -#| "… add = \\x y -> x + y\n" -#| "… ^D\n" +#, no-wrap msgid "" "> import Prelude\n" "> :paste\n" @@ -14778,6 +14755,7 @@ msgid "" "… 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" @@ -14823,16 +14801,10 @@ msgstr "" #. type: Plain text #: text/chapter3.md:137 -#, fuzzy -#| msgid "" -#| "If a declaration spans multiple lines, then any lines except the first " -#| "must be indented past the indentation level of the first line." msgid "" "If a declaration spans multiple lines, any lines except the first must be " "indented past the indentation level of the first line." -msgstr "" -"宣言が複数行にわたる場合は、最初の行以外は最初の行の字下げより深くしなければ" -"なりません。" +msgstr "宣言が複数行にわたる場合、最初の行以外は最初の行の字下げより深くしなければなりません。" #. type: Plain text #: text/chapter3.md:139 @@ -14920,26 +14892,16 @@ msgstr "" #. type: Plain text #: text/chapter3.md:173 -#, fuzzy -#| msgid "" -#| "Certain PureScript keywords (such as `where`, `of` and `let`) introduce a " -#| "new block of code, in which declarations must be further-indented:" msgid "" "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:174 -#, fuzzy, no-wrap -#| msgid "" -#| "example x y z = foo + bar\n" -#| " where\n" -#| " foo = x * y\n" -#| " bar = y * z\n" +#, no-wrap msgid "" "example x y z =\n" " let\n" @@ -14948,24 +14910,21 @@ msgid "" " 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:184 msgid "This doesn't compile:" -msgstr "" +msgstr "これはコンパイルされません。" #. type: Fenced code block (haskell) #: text/chapter3.md:185 -#, fuzzy, no-wrap -#| msgid "" -#| "example x y z = foo + bar\n" -#| " where\n" -#| " foo = x * y\n" -#| " bar = y * z\n" +#, no-wrap msgid "" "example x y z =\n" " let\n" @@ -14974,10 +14933,12 @@ msgid "" " 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" +" bar = y * z\n" +" in\n" +" foo + bar\n" #. type: Plain text #: text/chapter3.md:195 @@ -14985,7 +14946,7 @@ msgid "" "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 "" +msgstr "より多くを学びたければ(あるいは何か問題に遭遇したら)[構文](https://github.com/purescript/documentation/blob/master/language/Syntax.md#syntax)のドキュメントを参照してください。" #. type: Title ## #: text/chapter3.md:196 @@ -15194,7 +15155,7 @@ msgstr "量化された型" msgid "" "For illustration purposes, let's define a primitive function that takes any " "two arguments and returns the first one:" -msgstr "" +msgstr "説明しやすくするため、任意の2つの引数を取り最初のものを返す原始的な関数を定義しましょう。" #. type: Fenced code block (text) #: text/chapter3.md:260 @@ -15205,6 +15166,10 @@ msgid "" "… 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 @@ -15219,52 +15184,44 @@ msgid "" ">\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 -#, fuzzy -#| msgid "" -#| "The keyword `forall` here indicates that `flip` has a _universally " -#| "quantified type_. It means we can substitute any types for `a`, `b`, and " -#| "`c`, and `flip` will work with those types." 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`キーワードは、`flip`が*全称量化された型*を持つことを示していま" -"す。\n" -"つまり`a`や`b`や`c`をどの型に置き換えても良く、`flip`はその型で動作するので" -"す。" +"この`forall`キーワードは、`constantlyFirst`が*全称量化された型*を持つことを示しています。\n" +"つまり`a`や`b`をどの型に置き換えても良く、`constantlyFirst`はその型で動作するのです。" +# FIXME: `b` - `String`は`b` to be `String`のような気がします。 #. type: Plain text #: text/chapter3.md:279 -#, fuzzy -#| 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" 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`、`c`を`String`と選んだとします。\n" -"その場合、`flip`の型を次のように*特殊化*できます。" +"例えば、`a`を`Int`、`b`を`String`と選んだとします。\n" +"その場合、`constantlyFirst`の型を次のように*特殊化*できます。" #. type: Fenced code block (text) #: text/chapter3.md:280 -#, fuzzy, no-wrap -#| msgid "log :: String -> Effect Unit\n" +#, no-wrap msgid "Int -> String -> Int\n" -msgstr "log :: String -> Effect Unit\n" +msgstr "Int -> String -> Int\n" #. type: Plain text #: text/chapter3.md:285 -#, fuzzy -#| 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 `flip` as if it " -#| "had this type already:" 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` " @@ -15272,7 +15229,7 @@ msgid "" msgstr "" "量化された型を特殊化したいということをコードで示す必要はありません。\n" "特殊化は自動的に行われます。\n" -"例えば、あたかも既にその型の`flip`を持っていたかのように、`flip`を使えます。" +"例えば、あたかも既にその型に備わっていたかの如く`constantlyFirst`を使えます。" #. type: Fenced code block (text) #: text/chapter3.md:286 @@ -15282,6 +15239,9 @@ msgid "" "\n" "3\n" msgstr "" +"> constantlyFirst 3 \"ignored\"\n" +"\n" +"3\n" #. type: Plain text #: text/chapter3.md:293 @@ -15289,7 +15249,7 @@ 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 "" +msgstr "`a`と`b`にはどんな型でも選べますが、`constantlyFirst`が返す型は最初の引数の型と同じでなければなりません(両方とも同じ`a`に「紐付く」からです)。" #. type: Fenced code block (text) #: text/chapter3.md:294 @@ -15301,6 +15261,11 @@ msgid "" ":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 @@ -15542,14 +15507,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter3.md:385 -#, fuzzy, no-wrap -#| msgid "" -#| "$ spago repl\n" -#| "\n" -#| "> import Data.List\n" -#| "> :type Cons\n" -#| "\n" -#| "forall a. a -> List a -> List a\n" +#, no-wrap msgid "" "$ spago repl\n" "\n" @@ -15563,7 +15521,7 @@ msgstr "" "> 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:395 @@ -15636,19 +15594,14 @@ msgstr "カリー化された関数" #. type: Plain text #: text/chapter3.md:419 -#, fuzzy -#| msgid "" -#| "Functions in PureScript take exactly one argument. While it looks like " -#| "the `insertEntry` function takes two arguments, it is an example of a " -#| "_curried function_." msgid "" "Functions in PureScript take exactly one argument. While it looks like the " "`insertEntry` function takes two arguments, it is an example of a _curried " "function_. In PureScript, all functions are considered curried." msgstr "" -"PureScriptでは、関数は常に1つの引数だけを取ります。\n" -"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一" -"例なのです。" +"PureScriptの関数はきっかり1つの引数を取ります。\n" +"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。\n" +"PureScriptでは全ての関数はカリー化されたものと見做されます。" #. type: Plain text #: text/chapter3.md:421 @@ -15658,6 +15611,8 @@ msgid "" "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 @@ -15665,13 +15620,12 @@ 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 -#, fuzzy, no-wrap -#| msgid "" -#| "add :: Int -> Int -> Int\n" -#| "add x y = x + y\n" +#, no-wrap msgid "" "add :: Int -> Int -> Int\n" "add x y = x + y\n" @@ -15681,6 +15635,9 @@ msgid "" 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 @@ -15689,6 +15646,9 @@ msgid "" "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 @@ -15704,15 +15664,19 @@ msgid "" ">… ^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 -#, fuzzy, no-wrap -#| msgid "" -#| "> :paste\n" -#| "… add :: Int -> Int -> Int\n" -#| "… add = \\x y -> x + y\n" -#| "… ^D\n" +#, no-wrap msgid "" "> :paste\n" "… addFive :: Int -> Int\n" @@ -15726,9 +15690,15 @@ msgid "" "6\n" msgstr "" "> :paste\n" -"… add :: Int -> Int -> Int\n" -"… add = \\x y -> x + y\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 @@ -15737,13 +15707,16 @@ msgid "" "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:464 -#, fuzzy, no-wrap -#| msgid "The `->` operator in the type of `insertEntry` associates to the right, which means that the compiler parses the type as\n" +#, no-wrap msgid "The `->` operator (in the type signature) associates to the right, which means that the compiler parses the type as\n" -msgstr "`insertEntry`の型に含まれる `->`は右結合の演算子であり、つまりこの型はコンパイラによって次のように解釈されます。\n" +msgstr "" +"(型シグネチャ中の)`->`演算子は右結合です。\n" +"つまりコンパイラは型を次のように解釈します。\n" #. type: Fenced code block (haskell) #: text/chapter3.md:465 @@ -15753,20 +15726,13 @@ msgstr "Entry -> (AddressBook -> AddressBook)\n" #. type: Plain text #: text/chapter3.md:470 -#, fuzzy -#| msgid "" -#| "That is, `insertEntry` is a function that 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`." msgid "" "`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`を取り、新しい関数を返します。\n" -"今度はこの関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返しま" -"す。" +"`insertEntry`は単一の引数`Entry`を取り、新しい関数を返します。\n" +"そして今度はその関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。" #. type: Plain text #: text/chapter3.md:472 @@ -16058,18 +16024,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter3.md:563 -#, fuzzy, no-wrap -#| msgid "" -#| "$ spago repl\n" -#| "\n" -#| "> import Data.List\n" -#| "> :type filter\n" -#| "\n" -#| "forall a. (a -> Boolean) -> List a -> List a\n" -#| "\n" -#| "> :type head\n" -#| "\n" -#| "forall a. List a -> Maybe a\n" +#, no-wrap msgid "" "$ spago repl\n" "\n" @@ -16087,11 +16042,11 @@ msgstr "" "> 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:577 @@ -17255,16 +17210,13 @@ msgstr "それでは`map`の型を見てみましょう。" #. type: Fenced code block (text) #: text/chapter4.md:113 -#, fuzzy, no-wrap -#| msgid "" -#| "> :type map\n" -#| "forall a b f. Functor f => (a -> b) -> f a -> f b\n" +#, no-wrap msgid "" "> :type map\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 @@ -17279,10 +17231,9 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:120 -#, fuzzy, no-wrap -#| msgid "forall a b. (a -> b) -> Array a -> Array b\n" +#, no-wrap msgid "forall (a :: Type) (b :: Type). (a -> b) -> Array a -> Array b\n" -msgstr "forall a b. (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 @@ -17387,7 +17338,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) @@ -17409,10 +17360,8 @@ 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 @@ -17526,15 +17475,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:194 -#, fuzzy, no-wrap -#| msgid "" -#| "> import Data.Array\n" -#| "\n" -#| "> :type concat\n" -#| "forall a. Array (Array a) -> Array a\n" -#| "\n" -#| "> concat [[1, 2, 3], [4, 5], [6]]\n" -#| "[1, 2, 3, 4, 5, 6]\n" +#, no-wrap msgid "" "> import Data.Array\n" "\n" @@ -17547,7 +17488,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" @@ -17572,15 +17513,7 @@ msgstr "実際に動かして見てみましょう。" #. type: Fenced code block (text) #: text/chapter4.md:208 -#, fuzzy, no-wrap -#| msgid "" -#| "> import Data.Array\n" -#| "\n" -#| "> :type concatMap\n" -#| "forall a b. (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" +#, no-wrap msgid "" "> import Data.Array\n" "\n" @@ -17593,7 +17526,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" @@ -17972,12 +17905,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:334 -#, fuzzy, no-wrap -#| msgid "" -#| "> import Control.Alternative\n" -#| "\n" -#| "> :type guard\n" -#| "forall m. Alternative m => Boolean -> m Unit\n" +#, no-wrap msgid "" "> import Control.Alternative\n" "\n" @@ -17987,7 +17915,7 @@ 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 @@ -18140,15 +18068,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter4.md:376 -#, fuzzy, no-wrap -#| msgid "" -#| "> import Data.Foldable\n" -#| "\n" -#| "> :type foldl\n" -#| "forall a b f. 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" +#, no-wrap msgid "" "> import Data.Foldable\n" "\n" @@ -18161,36 +18081,24 @@ 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 -#, fuzzy -#| msgid "" -#| "These types are more general than we are interested in right now. For " -#| "this chapter, we can assume that PSCi has given the following (more " -#| "specific) answer:" msgid "" "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 -#, fuzzy, no-wrap -#| msgid "" -#| "> :type foldl\n" -#| "forall a b. (b -> a -> b) -> b -> Array a -> b\n" -#| "\n" -#| "> :type foldr\n" -#| "forall a b. (a -> b -> b) -> b -> Array a -> b\n" +#, no-wrap msgid "" "-- foldl\n" "forall a b. (b -> a -> b) -> b -> Array a -> b\n" @@ -18198,10 +18106,10 @@ msgid "" "-- 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 @@ -19536,12 +19444,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter5.md:153 -#, fuzzy, no-wrap -#| msgid "" -#| "> showPerson { first: x, last: y } = y <> \", \" <> x\n" -#| "\n" -#| "> :type showPerson\n" -#| "forall r. { first :: String, last :: String | r } -> String\n" +#, no-wrap msgid "" "> showPerson { first: x, last: y } = y <> \", \" <> x\n" "\n" @@ -19551,7 +19454,7 @@ 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 @@ -22121,12 +22024,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter6.md:380 -#, fuzzy, no-wrap -#| msgid "" -#| "> import Prelude\n" -#| "\n" -#| "> :type \\x -> x + x\n" -#| "forall a. Semiring a => a -> a\n" +#, no-wrap msgid "" "> import Prelude\n" "\n" @@ -22136,7 +22034,7 @@ 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 @@ -22627,13 +22525,7 @@ msgstr "" #. type: Fenced code block (text) #: text/chapter6.md:541 -#, fuzzy, no-wrap -#| msgid "" -#| "> :type genericTail\n" -#| "forall stream element. Stream stream element => stream -> Maybe stream\n" -#| "\n" -#| "> genericTail \"testing\"\n" -#| "(Just \"esting\")\n" +#, no-wrap msgid "" "> :type genericTail\n" "forall (stream :: Type) (element :: Type). Stream stream element => stream -> Maybe stream\n" @@ -22642,7 +22534,7 @@ msgid "" "(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" @@ -23746,16 +23638,13 @@ msgstr "`lift3`の型を見てみるとわかりやすいでしょう。" #. type: Fenced code block (text) #: text/chapter7.md:87 -#, fuzzy, 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" +#, no-wrap msgid "" "> :type lift3\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 @@ -29793,6 +29682,4 @@ msgstr "`parallel`ライブラリを使って並列に非同期コードを走 #~ 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`だ" -#~ "けは、この規則の唯一の例外になっています。" +#~ msgstr "ただし、ソースファイルの先頭、最初の`module`宣言におけるキーワード`where`だけは、この規則の唯一の例外になっています。" diff --git a/translation/terms.txt b/translation/terms.txt index 1ad5b633..3f7e7445 100644 --- a/translation/terms.txt +++ b/translation/terms.txt @@ -16,3 +16,5 @@ type synonym: 型同義語 configure: 構成。設定はsettingで一応区別したいです。 handle: 制御対象 help message: ヘルプ文言。「使用方法の文言」と噛み砕くのもありそうですが、ややまどろっこしい感じがします。 +open import: 一括インポート +keyword: キーワード。予約語はまた意味が違ってくるようです。 From bf55ff426c2c6a413c99d20f1cde3d5651d2aff7 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:26:41 +0900 Subject: [PATCH 24/29] [ generate ] translations --- text-ja/chapter1.md | 8 +--- text-ja/chapter10.md | 2 +- text-ja/chapter3.md | 95 +++++++++++++++++++------------------------- text-ja/chapter4.md | 10 ++--- 4 files changed, 49 insertions(+), 66 deletions(-) diff --git a/text-ja/chapter1.md b/text-ja/chapter1.md index cfb9e67e..632284a6 100644 --- a/text-ja/chapter1.md +++ b/text-ja/chapter1.md @@ -46,7 +46,7 @@ PureScriptは軽量な構文を備えていますが、この構文によりと また、JavaScriptやJavaScriptへとコンパイルされる他の言語と相互運用するときに重要な、高速で理解しやすいコードを生成します。 概してPureScriptとは、純粋関数型プログラミングの理論的な強力さと、JavaScriptのお手軽で緩いプログラミングスタイルとの、とても現実的なバランスを狙った言語だということを理解して頂けたらと思います。 -> Note that PureScript can target other backends, not only JavaScript, but this book focuses on targeting web browser and node environments. +> なお、PureScriptはJavaScriptのみならず他のバックエンドを対象にできますが、本書ではwebブラウザとnode環境に焦点を絞ります。 ## 型と型推論 @@ -200,11 +200,7 @@ PSCi対話式モードプロンプトに入力するコマンドは、行の先 PureScript!](https://try.purescript.org)は利用者がwebブラウザでPureScriptのコードをコンパイルできるwebサイトです。 幾つかの簡単なコードの例もあります。 -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. +もし例を読んで学ぶ方が好きでしたら、GitHubの[purescript](https://github.com/purescript)、[purescript-node](https://github.com/purescript-node)、[purescript-contrib](https://github.com/purescript-contrib)組織にはPureScriptコードの例が沢山あります。 ## 著者について diff --git a/text-ja/chapter10.md b/text-ja/chapter10.md index 917260e7..c4dc8cb1 100644 --- a/text-ja/chapter10.md +++ b/text-ja/chapter10.md @@ -1298,7 +1298,7 @@ example' = 100 var example$prime = 100; ``` -コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptの予約語を避けることをお勧めします。 +コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図している場合、識別子は英数字のみを使用し、JavaScriptのキーワードを避けることをお勧めします。 ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScriptから使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。 ### 実行時のデータ表現 diff --git a/text-ja/chapter3.md b/text-ja/chapter3.md index f1014ba2..b4b8516f 100644 --- a/text-ja/chapter3.md +++ b/text-ja/chapter3.md @@ -21,9 +21,8 @@ ここでは、幾つかのモジュールをインポートします。 -- The `Prelude` module, which contains a small set of standard definitions - and functions. It re-exports many foundational modules from - the `purescript-prelude` library. +- `Prelude`モジュールには標準的な定義と関数の小さな集合が含まれます。 + `purescript-prelude`ライブラリから多くの基礎的なモジュールを再エクスポートしているのです。 - `Control.Plus`モジュールには`empty`値が定義されています。 - `Data.List`モジュールは`lists`パッケージで提供されています。 またこのパッケージはSpagoを使ってインストールできます。 @@ -33,10 +32,8 @@ 訳者注:ダブルドット (`..`) を使用すると、 指定された型コンストラクタのすべてのデータコンストラクタをインポートできます。 -Notice that the imports for these modules are listed explicitly in -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. +これらのモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください(`Prelude`は除きます。これは一括インポートされるのが普通です)。 +明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。 ソースコードリポジトリをクローンしたと仮定すると、この章のプロジェクトは次のコマンドでSpagoを使用して構築できます。 @@ -121,12 +118,11 @@ String`型のフィールド`interests`で、後者は`String`の配列という ["Functional Programming","JavaScript"] ``` -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: +PureScriptの関数はJavaScriptの関数に対応します。 +関数はファイルの最上位で定義でき、等号の前に引数を指定します。 ```haskell -import Prelude -- bring the (+) operator into scope +import Prelude -- (+) 演算子をスコープに持ち込みます add :: Int -> Int -> Int add x y = x + y @@ -155,8 +151,7 @@ PSCiでこの関数が定義されていると、次のように関数の隣に2 PureScriptのコードは字下げの大きさに意味があります。ちょうどHaskellと同じで、JavaScriptとは異なります。コード内の空白の多寡は無意味ではなく、Cのような言語で中括弧によってコードのまとまりを示しているように、PureScriptでは空白がコードのまとまりを示すために使われているということです。 -If a declaration spans multiple lines, any lines except the first must be -indented past the indentation level of the first line. +宣言が複数行にわたる場合、最初の行以外は最初の行の字下げより深くしなければなりません。 したがって、次は正しいPureScriptコードです。 @@ -194,8 +189,8 @@ y + z … ^D ``` -Certain PureScript keywords introduce a new block of code, in which -declarations must be further-indented: +PureScriptの幾つかのキーワードは新たなコードのまとまりを導入します。 +その中での宣言はそれより深く字下げされなければなりません。 ```haskell example x y z = @@ -206,7 +201,7 @@ example x y z = foo + bar ``` -This doesn't compile: +これはコンパイルされません。 ```haskell example x y z = @@ -217,9 +212,7 @@ example x y z = foo + bar ``` -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. +より多くを学びたければ(あるいは何か問題に遭遇したら)[構文](https://github.com/purescript/documentation/blob/master/language/Syntax.md#syntax)のドキュメントを参照してください。 ## 独自の型の定義 @@ -293,8 +286,7 @@ PureScriptの _種システム_ は他にも面白い種に対応しています ## 量化された型 -For illustration purposes, let's define a primitive function that takes any -two arguments and returns the first one: +説明しやすくするため、任意の2つの引数を取り最初のものを返す原始的な関数を定義しましょう。 ```text > :paste @@ -303,29 +295,29 @@ two arguments and returns the first one: … ^D ``` -> Note that if you use `:type` to ask about the type of `constantlyFirst`, it will be more verbose: +> なお、`:type`を使って`constantlyfirst`の型について尋ねた場合、もっと冗長になります。 > > ```text > : type constantlyFirst > forall (a :: Type) (b :: Type). a -> b -> a > ``` > -> The type signature contains additional kind information, which explicitly notes that `a` and `b` should be concrete types. +> 型シグネチャには追加で種の情報が含まれます。 +> `a`と`b`が具体的な型であることが明記されています。 -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. +この`forall`キーワードは、`constantlyFirst`が*全称量化された型*を持つことを示しています。 +つまり`a`や`b`をどの型に置き換えても良く、`constantlyFirst`はその型で動作するのです。 -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 +例えば、`a`を`Int`、`b`を`String`と選んだとします。 +その場合、`constantlyFirst`の型を次のように*特殊化*できます。 ```text Int -> String -> Int ``` -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: +量化された型を特殊化したいということをコードで示す必要はありません。 +特殊化は自動的に行われます。 +例えば、あたかも既にその型に備わっていたかの如く`constantlyFirst`を使えます。 ```text > constantlyFirst 3 "ignored" @@ -333,9 +325,7 @@ as if it had this type already: 3 ``` -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`): +`a`と`b`にはどんな型でも選べますが、`constantlyFirst`が返す型は最初の引数の型と同じでなければなりません(両方とも同じ`a`に「紐付く」からです)。 ```text :type constantlyFirst true "ignored" @@ -480,17 +470,15 @@ insertEntry entry book = Cons entry book ## カリー化された関数 -Functions in PureScript take exactly one argument. While it looks like the -`insertEntry` function takes two arguments, it is an example of a _curried -function_. In PureScript, all functions are considered curried. +PureScriptの関数はきっかり1つの引数を取ります。 +`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。 +PureScriptでは全ての関数はカリー化されたものと見做されます。 -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. +カリー化が意味するのは複数の引数を取る関数を1度に1つ取る関数に変換することです。 +関数を呼ぶときに1つの引数を渡し、これまた1つの引数を取る別の関数を返し、といったことを全ての引数が渡されるまで続けます。 -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: +例えば`add`に`5`に渡すと別の関数が得られます。 +その関数は整数を取り、5を足し、合計を結果として返します。 ```haskell add :: Int -> Int -> Int @@ -500,11 +488,11 @@ addFive :: Int -> Int addFive = add 5 ``` -`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: +`addFive`は*部分適用*の結果です。 +つまり複数の引数を取る関数に、引数の全個数より少ない数だけ渡すのです。 +試してみましょう。 -> Note that you must define the `add` function if you haven't already: +> なお、お済みでなければ`add`関数を定義しなくてはなりません。 > > ```text > > import Prelude @@ -527,23 +515,22 @@ arguments. Let's give it a try: 6 ``` -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`. +カリー化と部分適用をもっと理解するには、例にあった`add`とは別の関数を2、3作ってみてください。 +そしてそれができたら`insertEntry`に戻りましょう。 ```haskell {{#include ../exercises/chapter3/src/Data/AddressBook.purs:insertEntry_signature}} ``` -The `->` operator (in the type signature) associates to the right, which means that the compiler parses the type as +(型シグネチャ中の)`->`演算子は右結合です。 +つまりコンパイラは型を次のように解釈します。 ```haskell Entry -> (AddressBook -> 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`. +`insertEntry`は単一の引数`Entry`を取り、新しい関数を返します。 +そして今度はその関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。 これはつまり、最初の引数だけを与えて`insertEntry`を*部分適用*できたりするということです。 PSCiで結果の型が見られます。 diff --git a/text-ja/chapter4.md b/text-ja/chapter4.md index bb8cea21..37b5187a 100644 --- a/text-ja/chapter4.md +++ b/text-ja/chapter4.md @@ -190,7 +190,7 @@ infix 8 range as .. 上記の例では、`1 .. 5`という式は括弧で囲まれていましたが、実際にはこれは必要ありません。 なぜなら、`Data.Array`モジュールは、`<$>`に割り当てられた優先順位より高い優先順位を`..`演算子に割り当てているからです。 -上の例では、`..`の優先順位は、予約語`infix`のあとに書かれた数の`8` と定義されていました。 +上の例では、`..`の優先順位は、キーワード`infix`のあとに書かれた数の`8` と定義されていました。 ここでは`<$>`の優先順位よりも高い優先順位を`..`に割り当てており、このため括弧を付け加える必要がないということです。 ```text @@ -198,7 +198,8 @@ infix 8 range as .. ["1","2","3","4","5"] ``` -中置演算子に(左または右の)*結合性*を与えたい場合は、代わりに予約語`infixl`と`infixr`を使います。`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。 +中置演算子に(左または右の)*結合性*を与えたい場合は、代わりにキーワード`infixl`と`infixr`を使います。 +`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。 ## 配列の絞り込み @@ -461,9 +462,8 @@ forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (b -> a -> b) forall (f :: Type -> Type) (a :: Type) (b :: Type). Foldable f => (a -> b -> b) -> b -> f a -> b ``` -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: +これらの型は、現在興味があるものよりも一般化されています。 +この章では単純化して以下の(より具体的な)型シグネチャと見て構いません。 ```text -- foldl From 948acf8e6aff13475d2dd531a072a19753fcf5bb Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:29:18 +0900 Subject: [PATCH 25/29] [ update ] translation readme --- translation/README.md | 3 +++ 1 file changed, 3 insertions(+) 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`で検証します。 From fed0c5cf3bf6639796f712c0d16959b84f7b0a28 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:30:21 +0900 Subject: [PATCH 26/29] [ remove ] license translations --- translation/ja.po | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/translation/ja.po b/translation/ja.po index 4b671de1..fca460d7 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-08-25 20:42+0900\n" -"PO-Revision-Date: 2023-08-25 21:26+0900\n" +"PO-Revision-Date: 2023-08-25 21:30+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -284,15 +284,7 @@ msgid "" "The text of this book is licensed under the Creative Commons Attribution-" "NonCommercial-ShareAlike 3.0 Unported License: ." -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)のもとに使用が許" -"諾される。
" +msgstr "The text of this book is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License: ." #. type: Plain text #: README.md:39 @@ -301,25 +293,12 @@ msgid "" "com/purescript/documentation), which uses the same license, and is copyright " "[various contributors](https://github.com/purescript/documentation/blob/" "master/CONTRIBUTORS.md)." -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)の著作権が含まれる。" +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)." #. 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 From 9019e7619d04868be9624b7f062f40bf6e5b10cd Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:31:33 +0900 Subject: [PATCH 27/29] [ update ] translation --- text-ja/index.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/text-ja/index.md b/text-ja/index.md index cba01101..f3ef8779 100644 --- a/text-ja/index.md +++ b/text-ja/index.md @@ -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ライセンスの下に使用が許諾される。 - - - - From 48b8224f4596b783c4ffc54e714674d2bbb5d8f3 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:34:01 +0900 Subject: [PATCH 28/29] [ add ] translation target: contribution --- po4a.cfg | 3 ++ translation/all.pot | 49 ++++++++++++++++- translation/ja.po | 127 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 155 insertions(+), 24 deletions(-) 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/translation/all.pot b/translation/all.pot index 2a929da3..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-08-25 20:42+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" @@ -24515,3 +24515,50 @@ msgstr "" #, 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 fca460d7..e2d5f5a9 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" -"POT-Creation-Date: 2023-08-25 20:42+0900\n" +"POT-Creation-Date: 2023-08-25 21:33+0900\n" "PO-Revision-Date: 2023-08-25 21:30+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" @@ -284,7 +284,10 @@ msgid "" "The text of this book is licensed under the Creative Commons Attribution-" "NonCommercial-ShareAlike 3.0 Unported License: ." -msgstr "The text of this book is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License: ." +msgstr "" +"The text of this book is licensed under the Creative Commons Attribution-" +"NonCommercial-ShareAlike 3.0 Unported License: ." #. type: Plain text #: README.md:39 @@ -293,7 +296,11 @@ msgid "" "com/purescript/documentation), which uses the same license, and is copyright " "[various contributors](https://github.com/purescript/documentation/blob/" "master/CONTRIBUTORS.md)." -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)." +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)." #. type: Plain text #: README.md:40 @@ -1012,7 +1019,11 @@ msgid "" "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](https://github.com/purescript)、[purescript-node](https://github.com/purescript-node)、[purescript-contrib](https://github.com/purescript-contrib)組織にはPureScriptコードの例が沢山あります。" +msgstr "" +"もし例を読んで学ぶ方が好きでしたら、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:151 @@ -4456,8 +4467,11 @@ msgid "" "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から使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" +"コンパイルされたPureScriptコードがJavaScriptから呼び出されることを意図してい" +"る場合、識別子は英数字のみを使用し、JavaScriptのキーワードを避けることをお勧" +"めします。\n" +"ユーザ定義演算子がPureScriptコードでの使用のために提供される場合、JavaScript" +"から使うための英数字の名前を持つ代替関数を提供しておくことをお勧めします。" #. type: Title ### #: text/chapter10.md:1155 @@ -14432,7 +14446,8 @@ msgid "" "prelude` library." msgstr "" "`Prelude`モジュールには標準的な定義と関数の小さな集合が含まれます。\n" -"`purescript-prelude`ライブラリから多くの基礎的なモジュールを再エクスポートしているのです。" +"`purescript-prelude`ライブラリから多くの基礎的なモジュールを再エクスポートし" +"ているのです。" #. type: Bullet: '- ' #: text/chapter3.md:25 @@ -14467,8 +14482,11 @@ msgid "" "import). This is generally a good practice, as it helps to avoid conflicting " "imports." msgstr "" -"これらのモジュールのインポート内容が括弧内で明示的に列挙されていることに注目してください(`Prelude`は除きます。これは一括インポートされるのが普通です)。\n" -"明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣です。" +"これらのモジュールのインポート内容が括弧内で明示的に列挙されていることに注目" +"してください(`Prelude`は除きます。これは一括インポートされるのが普通で" +"す)。\n" +"明示的な列挙はインポート内容の衝突を避けるのに役に立つので、一般に良い習慣で" +"す。" #. type: Plain text #: text/chapter3.md:29 @@ -14783,7 +14801,9 @@ msgstr "" msgid "" "If a declaration spans multiple lines, any lines except the first must be " "indented past the indentation level of the first line." -msgstr "宣言が複数行にわたる場合、最初の行以外は最初の行の字下げより深くしなければなりません。" +msgstr "" +"宣言が複数行にわたる場合、最初の行以外は最初の行の字下げより深くしなければな" +"りません。" #. type: Plain text #: text/chapter3.md:139 @@ -14925,7 +14945,10 @@ msgid "" "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 "より多くを学びたければ(あるいは何か問題に遭遇したら)[構文](https://github.com/purescript/documentation/blob/master/language/Syntax.md#syntax)のドキュメントを参照してください。" +msgstr "" +"より多くを学びたければ(あるいは何か問題に遭遇したら)[構文](https://github." +"com/purescript/documentation/blob/master/language/Syntax.md#syntax)のドキュメ" +"ントを参照してください。" #. type: Title ## #: text/chapter3.md:196 @@ -15134,7 +15157,9 @@ msgstr "量化された型" msgid "" "For illustration purposes, let's define a primitive function that takes any " "two arguments and returns the first one:" -msgstr "説明しやすくするため、任意の2つの引数を取り最初のものを返す原始的な関数を定義しましょう。" +msgstr "" +"説明しやすくするため、任意の2つの引数を取り最初のものを返す原始的な関数を定義" +"しましょう。" #. type: Fenced code block (text) #: text/chapter3.md:260 @@ -15180,8 +15205,10 @@ msgid "" "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`はその型で動作するのです。" +"この`forall`キーワードは、`constantlyFirst`が*全称量化された型*を持つことを示" +"しています。\n" +"つまり`a`や`b`をどの型に置き換えても良く、`constantlyFirst`はその型で動作する" +"のです。" # FIXME: `b` - `String`は`b` to be `String`のような気がします。 #. type: Plain text @@ -15228,7 +15255,9 @@ 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`に「紐付く」からです)。" +msgstr "" +"`a`と`b`にはどんな型でも選べますが、`constantlyFirst`が返す型は最初の引数の型" +"と同じでなければなりません(両方とも同じ`a`に「紐付く」からです)。" #. type: Fenced code block (text) #: text/chapter3.md:294 @@ -15579,7 +15608,8 @@ msgid "" "function_. In PureScript, all functions are considered curried." msgstr "" "PureScriptの関数はきっかり1つの引数を取ります。\n" -"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一例なのです。\n" +"`insertEntry`関数は2つの引数を取るように見えますが、*カリー化された関数*の一" +"例なのです。\n" "PureScriptでは全ての関数はカリー化されたものと見做されます。" #. type: Plain text @@ -15590,8 +15620,10 @@ msgid "" "one argument, and it returns another function that also takes one argument " "until all arguments are passed." msgstr "" -"カリー化が意味するのは複数の引数を取る関数を1度に1つ取る関数に変換することです。\n" -"関数を呼ぶときに1つの引数を渡し、これまた1つの引数を取る別の関数を返し、といったことを全ての引数が渡されるまで続けます。" +"カリー化が意味するのは複数の引数を取る関数を1度に1つ取る関数に変換することで" +"す。\n" +"関数を呼ぶときに1つの引数を渡し、これまた1つの引数を取る別の関数を返し、と" +"いったことを全ての引数が渡されるまで続けます。" #. type: Plain text #: text/chapter3.md:423 @@ -15686,7 +15718,8 @@ msgid "" "other functions, for example, out of `add`. And when you're done, let's " "return to the `insertEntry`." msgstr "" -"カリー化と部分適用をもっと理解するには、例にあった`add`とは別の関数を2、3作ってみてください。\n" +"カリー化と部分適用をもっと理解するには、例にあった`add`とは別の関数を2、3作っ" +"てみてください。\n" "そしてそれができたら`insertEntry`に戻りましょう。" #. type: Plain text @@ -15711,7 +15744,8 @@ msgid "" "new `AddressBook`." msgstr "" "`insertEntry`は単一の引数`Entry`を取り、新しい関数を返します。\n" -"そして今度はその関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返します。" +"そして今度はその関数が単一の引数`AddressBook`を取り、新しい`AddressBook`を返" +"します。" #. type: Plain text #: text/chapter3.md:472 @@ -17339,8 +17373,11 @@ msgid "" "any expression using the same operator multiple times or using multiple " "operators of the same precedence." msgstr "" -"中置演算子に(左または右の)*結合性*を与えたい場合は、代わりにキーワード`infixl`と`infixr`を使います。\n" -"`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなります。" +"中置演算子に(左または右の)*結合性*を与えたい場合は、代わりにキーワード" +"`infixl`と`infixr`を使います。\n" +"`infix`を使うと何ら結合性は割り当てられず、同じ演算子を複数回使ったり複数の同" +"じ優先度の演算子を使ったりするときに、式を括弧で囲まなければいけなくなりま" +"す。" #. type: Title ## #: text/chapter4.md:168 @@ -29573,6 +29610,48 @@ msgstr "`affjax`ライブラリを使って非同期にHTTPリクエストする 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 "" + +#. 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 "" + +#. type: Fenced code block (sh) +#: CONTRIBUTING.md:11 +#, no-wrap +msgid "mdbook serve -o\n" +msgstr "" + +#. type: Plain text +#: CONTRIBUTING.md:15 +msgid "" +"The rendered webpage will automatically refresh with any changes to readme " +"files." +msgstr "" + #~ msgid "" #~ "PureScript's functions correspond to JavaScript's functions. The " #~ "PureScript standard libraries provide plenty of examples of functions, " @@ -29661,4 +29740,6 @@ msgstr "`parallel`ライブラリを使って並列に非同期コードを走 #~ 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`だけは、この規則の唯一の例外になっています。" +#~ msgstr "" +#~ "ただし、ソースファイルの先頭、最初の`module`宣言におけるキーワード`where`" +#~ "だけは、この規則の唯一の例外になっています。" From 4790efce1711422cfb672e8533e6b41251554b13 Mon Sep 17 00:00:00 2001 From: gemmaro Date: Fri, 25 Aug 2023 21:37:20 +0900 Subject: [PATCH 29/29] [ translate ] constibuting --- CONTRIBUTING.ja.md | 15 +++++++++++++++ translation/ja.po | 16 ++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 CONTRIBUTING.ja.md 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/translation/ja.po b/translation/ja.po index e2d5f5a9..6ca0f625 100644 --- a/translation/ja.po +++ b/translation/ja.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: com.github.gemmaro.purescript-book.v0.1.0\n" "POT-Creation-Date: 2023-08-25 21:33+0900\n" -"PO-Revision-Date: 2023-08-25 21:30+0900\n" +"PO-Revision-Date: 2023-08-25 21:37+0900\n" "Last-Translator: gemmaro \n" "Language-Team: none\n" "Language: ja\n" @@ -29614,43 +29614,43 @@ msgstr "`parallel`ライブラリを使って並列に非同期コードを走 #: CONTRIBUTING.md:1 #, no-wrap msgid "Contributing" -msgstr "" +msgstr "貢献" #. type: Plain text #: CONTRIBUTING.md:4 msgid "Please open PRs or Issues if you find anything to improve in the book." -msgstr "" +msgstr "本書で何かしら改善になるものを見付けたらPRやイシューを開いてください。" #. type: Plain text #: CONTRIBUTING.md:6 msgid "We appreciate your feedback." -msgstr "" +msgstr "フィードバックに感謝します。" #. type: Title ## #: CONTRIBUTING.md:7 #, no-wrap msgid "Editing chapter text" -msgstr "" +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 "" +msgstr "テキストの変更をローカルで見てみるには、[mdbook](https://github.com/rust-lang/mdBook)をインストールし、以下のコマンドをリポジトリのルートで走らせます。" #. type: Fenced code block (sh) #: CONTRIBUTING.md:11 #, no-wrap msgid "mdbook serve -o\n" -msgstr "" +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 "" +msgstr "readmeファイルへの変更毎に描画されたwebページが自動的に再読み込みされます。" #~ msgid "" #~ "PureScript's functions correspond to JavaScript's functions. The "