【翻訳】PureScriptとHaskellの違い　＋α

![hasu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64695/6971fa4c-ebe1-7f59-cd86-2ac6fa2680d4.jpeg)


PureScriptの公式ドキュメントより、[『Haskellとの違い』](https://github.com/purescript/documentation/blob/master/language/Differences-from-Haskell.md)のざっくり翻訳＋αです。原文のライセンスは[Creative Commons Legal Code Attribution-NonCommercial-ShareAlike 3.0 Unported](https://github.com/purescript/documentation/blob/master/LICENSE) です。

（翻訳ここから）
<br>

----

<!--
## Evaluation strategy
-->

## 評価戦略

<!--
Unlike Haskell, PureScript is strictly evaluated.
-->

Haskellとは異なり、PureScriptは正格評価です。

<!--
As the evaluation strategy matches JavaScript, interoperability with existing code is trivial - a function exported from a PureScript module behaves exactly like any "normal" JavaScript function, and correspondingly, calling JavaScript via the FFI is simple too.
-->

JavaScriptの評価戦略と一致するので、既存のコードとの相互運用はとても簡単です。PureScriptモジュールからエクスポートされた関数は、「通常の」JavaScript関数とまったく同じように振る舞いますし、それに対応して、FFIを通じてのJavaScriptの呼び出しもシンプルになっています。

<!--
Keeping strict evaluation also means there is no need for a runtime system or overly complicated JavaScript output. It should also be possible to write higher performance code when needed, as introducing laziness on top of JavaScript comes with an unavoidable overhead.
-->

正格評価を維持するということは、実行時システムや非常に複雑なJavaScript出力も必要ないということを意味します。やむをえないオーバーヘッドもついてきますが、JavaScriptの上に遅延性を導入することで、必要ならより効率のいいコードを書くことも可能です。

## Prelude/base

<!--
There is no implicit `Prelude` import in PureScript, the `Prelude` module is just like any other. Also, no libraries are distributed with the compiler at all.
-->

PureScriptに暗黙の`Prelude`インポートはありません。`Prelude`モジュールは他のモジュールとまったく同じものです。また、コンパイラと一緒に配布されるライブラリもありません。

<!--
The generally accepted "standard" `Prelude` is the [`purescript-prelude`](https://github.com/purescript/purescript-prelude) library.
-->

一般に広く使われている『標準の』`Prelude`は[`purescript-prelude`](https://github.com/purescript/purescript-prelude) です。

<!--
## Module Imports / Exports
-->
## モジュールのインポートとエクスポート

<!--
Type classes in modules must be specifically imported using the `class` keyword.
-->

モジュールに定義された型クラスは、`class`キーワードを使って特別にインポートします。


```purescript
module B where

import A (class Fab)
```

<!--
There is no `qualified` keyword in PureScript. Writing `import Data.List as List` has the same effect as writing `import qualified Data.List as List` in Haskell.
-->

PureScriptに`qualified`キーワードはありません。`import Data.List as List` というように書くと、Haskellで`import qualified Data.List as List`と書いたのと同じ効果になります。

<!--
Module imports and exports are fully documented on the [Modules](Modules.md) page.
-->

モジュールのインポートとエクスポートについては、[Modules](https://github.com/purescript/documentation/blob/master/language/Modules.md)のページで詳しく説明されています。


<!--
## Types
-->

## 型


<!--
### Explicit forall
-->
### 明示的な forall

<!--
Polymorphic functions in PureScript require an explicit `forall` to declare type variables before using them. For example, Haskell's list `length` function is declared like this:
-->


PureScriptにおける多相的な関数は、明示的な`forall`を使って事前に型変数を定義する必要があります。たとえば、Haskellではリストの`length`関数は次のように定義することができます。

``` haskell
length :: [a] -> Int
```

<!--
In PureScript this will fail with the error `Type variable a is undefined`. The PureScript equivalent is:
-->

PureScriptでは、この定義は`Type variable a is undefined`というエラーになります。PureScriptでこれと同じような定義をするには、次のように書きます。


``` purescript
length :: forall a. Array a -> Int
```

<!--
A `forall` can declare multiple type variables at once, and should appear before typeclass constraints:
-->

`forall`では一度に複数個の型変数を定義することもできます。また、型クラス制約の手前に書かなくてはなりません。

``` purescript
ap :: forall m a b. (Monad m) => m (a -> b) -> m a -> m b
```

<!--
### Numbers
-->

### 数

<!--
There is a native `Number` type which represents JavaScript's standard IEEE 754 float and an `Int` which is restricted to the range of 32-bit integers. In JavaScript, the `Int` values and operations are generated with a `|0` postfix to achieve this, e.g. if you have variables `x`, `y`, and `z` of type `Int`, then the PureScript expression `(x + y) * z` would compile to `((x + y)|0 * z)|0`.
-->

JavaScriptの標準のIEEE754浮動小数点数を表す、組み込みの`Number`型が存在し、`Int`型ではそれが32ビット整数の値域に制限されます。`Int`の値と操作には`|0`が後ろに付加されてJavaScriptが生成されることでこれが実現されています。たとえば、もし`Int`型の変数`x`と`y`と`z`があるとしたら、PureScriptの`(x + y) * z`は`((x + y)|0 * z)|0`へとコンパイルされます。

### Unit

<!--
PureScript has a type `Unit` used in place of Haskell's `()`. The `Prelude` module provides a value `unit` that inhabits this type.
-->

PureScriptは`Unit`型を持っており、これはHaskellの`()`に相当します。`Prelude`モジュールでは、この`Unit`型の値として`unit`という値を提供しています。

### `[a]`

<!--
PureScript does not provide syntactic sugar for list types. Construct list types using `List` from `Data.List`.
-->

PureScriptではリスト型に対して構文糖は提供していません。`Data.List`の`List`を使ってリストを構築してください。

<!--
There is also an `Array` type for native JavaScript arrays, but this does not have the same performance characteristics as `List`. `Array` _values_ can be constructed with `[x, y, z]` literals, but the type still needs to be annotated as `Array a`.
-->

組み込みのJavaScript配列に対応するものとしては`Array`型がありますが、これは`List`と同じようなパフォーマンス特性があるわけではありません。`Array`の**値**は`[x, y, z]`というようなリテラルで構築することができますが、型については`Array a`というように型注釈をすることが必要です。

<!--
## Records
-->

## レコード

<!--
PureScript can encode JavaScript-style objects directly by using row types, so Haskell-style record definitions actually have quite a different meaning in PureScript:
-->

PureScriptではJavaScript形式のオブジェクトを行型(Row types)を使って直接エンコードすることができます。Haskell形式のレコード定義は、PureScriptのものとはまったく異なる意味を持っています。

``` purescript
data Point = Point { x :: Number, y :: Number }
```

<!--
In Haskell a definition like this would introduce several things to the current environment:
-->

Haskellでは、上の定義は現在の環境へ次のようないくつかのものを導入します。

``` haskell
Point :: Number -> Number -> Point
x :: Point -> Number
y :: Point -> Number
```

<!--
However in PureScript this only introduces a `Point` constructor that accepts an object type. In fact, often we might not need a data constructor at all when using object types:
-->

それに対して、PureScriptではオブジェクト型ひとつを保持する`Point`構築子だけを導入します。実のところ、オブジェクト型を使うときは、データコンストラクタをまったく必要としないことが大半です。

``` purescript
type PointRec = { x :: Number, y :: Number }
```

<!--
Objects are constructed with syntax similar to that of JavaScript (and the type definition):
-->

オブジェクトはJavaScriptと同じような構文で構築されます(型の定義も同様です)。

``` purescript
origin :: PointRec 
origin = { x: 0, y: 0 }
```

<!--
And instead of introducing `x` and `y` accessor functions, `x` and `y` can be read like JavaScript properties:
-->

そしてPureScriptでは、Haskellのように`x`や`y`アクセサ関数が導入されるのではなく、JavaScriptのプロパティと同じように`x`や`y`を読むことができます。

``` purescript
originX :: Number
originX  = origin.x
```

<!--
PureScript also provides a record update syntax similar to Haskell's:
-->

PureScriptではHaskellと同じようなレコード更新構文も提供します。

``` purescript
setX :: Number -> PointRec -> PointRec 
setX val point = point { x = val }
```

<!--
A common mistake to look out for is when writing a function that accepts a data type like the original `Point` above—the object is still wrapped inside `Point`, so something like this will fail:
-->

気をつけたほうがいいよくある間違いとして、先程の本来の`Point`と同じようにデータ型を受け入れる関数を書いているときに、このオブジェクトは`Point`の中に包まれたままだというものがあります。そのため、次のようなコードはうまくいきません。


``` purescript
showPoint :: Point -> String
showPoint p = show p.x <> ", " <> show p.y
```

<!--
Instead, we need to destructure `Point` to get at the object:
-->

そうではなく、`Point`を分解してオブジェクトからオブジェクトを取り出す必要があります。

``` purescript
showPoint :: Point -> String
showPoint (Point obj) = show obj.x <> ", " <> show obj.y
```

<!--
## Type classes
-->

## 型クラス

<!--
### Arrow direction
-->

### 矢印の方向

<!--
When declaring a type class with a superclass, the arrow is the other way around. For example:
-->

スーパークラスをもつ型クラスを定義するとき、PureScriptとHaskellでは矢印は逆向きになります。たとえば、PureScriptでは次のように書きます。

```purescript
class (Eq a) <= Ord a where
  ...
```

<!--
This is so that `=>` can always be read as logical implication; in the above case, an `Ord a` instance _implies_ an `Eq a` instance.
-->

この`=>`は論理包含と同じように読むことができます。この場合、`Ord a`インスタンスが存在する『ならば』`Eq a`インスタンスが存在します。


<!--
### Named instances
-->

### 名前付きのインスタンス

<!--
In PureScript, instances must be given names:
-->

PureScriptでは、インスタンスには次のように名前が付きます。

```purescript
instance arbitraryUnit :: Arbitrary Unit where
  ...
```

<!--
Overlapping instances are still disallowed, like in Haskell. The instance names are used to help the readability of compiled JavaScript.
-->

Haskellと同じように重複インスタンスは禁止されます。インスタンスの名前はコンパイル後のJavaScriptの可読性のために使われます。


<!--
### Deriving
-->

### インスタンスの導出

<!--
Unlike Haskell, PureScript doesn't have deriving functionality when declaring
data types.  For example, the following code does not work in PureScript:
-->

Haskellとは異なり、PureScriptにはデータ型の定義の構文自体にはインスタンスの自動導出の機能がありません。例えば、次のようなコードはPureScriptでは動きません。

```haskell
data Foo = Foo Int String deriving (Eq, Ord)
```

<!--
However, PureScript does have `StandaloneDeriving`-type functionality:
-->

しかしそのかわり、PureScriptには型の`StandaloneDeriving`という機能があります。

```purescript
data Foo = Foo Int String

derive instance eqFoo :: Eq Foo
derive instance ordFoo :: Ord Foo
```

<!--
Examples of type classes that can be derived this way include `Eq`, `Functor`,
and `Ord`.  See
[here](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#type-class-deriving)
for a list of other type classes.
-->

この方法での導出が可能な型クラスの例としては、`Eq`や`Functor`、`Ord`があります。その他の型クラスの一覧については、[こちら](https://github.com/purescript/documentation/blob/master/language/Type-Classes.md#type-class-deriving)を参照してください。

<!--
Using generics, it is also possible to use generic implementations for type
classes like `Bounded`, `Monoid`, and `Show`.  See
[the generics-rep library](https://pursuit.purescript.org/packages/purescript-generics-rep)
for a list of other type classes that have generic implementations, as well as
an explanation of how to write generic implementations for your own type
classes.
-->

ジェネリクスを使うと、`Bounded`や`Monoid`、`Show`などの型クラスについてのジェネリックな実装を使うことが可能になります。ジェネリックな実装を持つ他の型クラスについてや、独自の型クラスに対してジェネリックな実装を書く方法についての説明は、[the generics-rep library](https://pursuit.purescript.org/packages/purescript-generics-rep)を参照してください。

<!--
### Orphan Instances
-->

### はぐれたインスタンス

<!--
Unlike Haskell, orphan instances are completely disallowed in PureScript.  It is a compiler error to try to declare orphan instances.
-->

Haskellとは異なり、PureScriptでははぐれたインスタンス(Orphan instances)は完全に禁止されます。これは、はぐれたインスタンスの定義はコンパイルエラーを引き起こすことがあるからです。

<!--
When instances cannot be declared in the same module, one way to work around it is to use [newtype wrappers](http://stackoverflow.com/questions/22080564/whats-the-practical-value-of-all-those-newtype-wrappers-in-data-monoid).
-->

同じモジュール内にインスタンスが定義できないときは、[newtypeで包む](http://stackoverflow.com/questions/22080564/whats-the-practical-value-of-all-those-newtype-wrappers-in-data-monoid)ことで回避する方法があります。


<!--
### Default members
-->

### デフォルトのメンバ

<!--
At the moment, it is not possible to declare default member implementations for type classes. This may change in the future.
-->

今のところ、型クラスにデフォルトのメンバを定義することはできません。これは将来的には変更される可能性があります。

<!--
### Type class hierarchies
-->

### 型クラス階層

<!--
Many type class hierarchies are more granular than in Haskell. For example:
-->

多くの型クラス階層はHaskellよりも段階的になっています。たとえば次のようになっています。

<!--
* `Category` has a superclass `Semigroupoid` which provides `(<<<)`, and does not require an identity.
* `Monoid` has a superclass `Semigroup`, which provides `(<>)`, and does not require an identity.
* `Applicative` has a superclass `Apply`, which provides `(<*>)` and does not require an implementation for `pure`.
-->

* `Category`はスーパークラスとして`(<<<)`を提供する型クラスである`Semigroupoid`を持ちます。`Semigroupoid`は単位元を要求しません。**(※訳注：Haskellでは`Category`型クラスが射の合成`(.)`と単位元`id`の両方を持ちますが、PureScriptではこれらのメンバは射の合成`(<<<)`を提供する型クラス`Semigroupoid`と単位元`identity`を提供する型クラス`Category`に分かれており、`Semigroupoid`が`Category`のスーパークラスになっています。Haskellではひとつの型クラスであったものが、PureScriptでは親子関係のあるふたつの型クラスに分割されているということです。)**
* `Monoid`はスーパークラスとして`(<>)`を提供する`Semigroup`を持ちます。`Semigroup`は単位元を要求しません。
* `Applicative`はスーパークラスとして`(<*>)`を提供する`Apply`を持ちます。`Apply`は`pure`の実装は要求しません。

<!--
## Tuples
-->

## タプル

<!--
PureScript has no special syntax for tuples as records can fulfill the same role that *n*-tuples do with the advantage of having more meaningful types and accessors.
-->

レコードを使えば同じような役割を果たす任意個のタプルをもっと意味のある型とアクセサを持って実現できるので、PureScriptではタプルに特別な構文は持っていません。

<!--
A `Tuple` type for 2-tuples is available via the [purescript-tuples](https://github.com/purescript/purescript-tuples) library. `Tuple` is treated the same as any other type or data constructor.
-->

2要素のタプルについては、[purescript-tuples](https://github.com/purescript/purescript-tuples) ライブラリを通じて使うことができます。`Tuple`は他の型やデータコンストラクタとまったく同じように扱われます。

<!--
## Composition operator
-->

## 合成演算子

<!--
PureScript uses `<<<` rather than `.` for right-to-left composition of functions. This is to avoid a syntactic ambiguity with `.` being used for property access and name qualification. There is also a corresponding `>>>` operator for left-to-right composition.
-->

PureScriptでは右から左に合成する関数として、`.`ではなく`<<<`を使います。これは`.`のプロパティアクセスや名前の修飾の構文とのあいまいさを避けるためです。また、左から右への合成については、対応する`>>>`演算子があります。

<!--
The `<<<` operator is actually a more general morphism composition operator that applies to semigroupoids and categories, and the `Prelude` module provides a `Semigroupoid` instance for the `->` type, which gives us function composition.
-->

実際にはこの`<<<`演算子は、semigroupoids とCategoryに適用されるより抽象的な「射の合成演算子」です。`Prelude`モジュールは`->`型についての`Semigroupoid`インスタンスを提供しており、これが関数合成になっています。


## `return`

<!--
In the past, PureScript used `return`. However, it is now removed and replaced with [`pure`](https://pursuit.purescript.org/packages/purescript-prelude/1.1.0/docs/Control.Applicative#v:pure). It was always an alias for `pure`, which means this change was implemented by simply removing the alias.
-->

過去にはPureScriptでも`return`を使っていたときがありました。しかし、現在はこれは削除され、[`pure`](https://pursuit.purescript.org/packages/purescript-prelude/1.1.0/docs/Control.Applicative#v:pure)に置き換えられています。`return`は`pure`の単なる別名でしたので、この変更というのは単に別名が削除されたというだけです。

<!--
## Array Comprehensions
-->

## 配列内包表記

<!--
PureScript does not provide special syntax for array comprehensions. Instead, use `do`-notation. The `guard` function from the `Control.MonadPlus` module in `purescript-control` can be used to filter results:
-->

PureScriptでは配列内包表記に特別な構文は提供していません。そのかわり、`do`記法を使ってください。`purescript-control`パッケージの`Control.MonadPlus`モジュールが提供している`guard`関数は、結果をフィルターするのに使うことができます。

```purescript
import Prelude (($), (*), (==), bind, pure)
import Data.Array ((..))
import Data.Tuple (Tuple(..))
import Control.MonadZero (guard)

factors :: Int -> Array (Tuple Int Int)
factors n = do
  a <- 1 .. n
  b <- 1 .. a
  guard $ a * b == n
  pure $ Tuple a b
```

<!--
## No special treatment of `$`
-->

## `$`を特別扱いしない

<!--
GHC provides a special typing rule for the `$` operator, so that the following natural application to the rank-2 `runST` function is well-typed:
-->

GHCは`$`演算子に特別な型付けルールを適用しますが、そのためランク２の`runST`関数への`$`の適用が正しく型付けされます。

```haskell
runST $ do
  ...
```

<!--
PureScript does not provide this rule, so it is necessary to either 
-->

PureScriptではこのようなルールは提供していませんので、次のどちらかに従います。

<!--
- omit the operator: `runST do ...`
- or use parentheses instead: `runST (do ...)`
-->

* `runST do ...`のようにして演算子をとる
* または、`runST (do ...)`のようにして括弧で囲む

<!--
## Defining Operators
-->

## 演算子の定義

<!--
In Haskell, it is possible to define an operator with the following natural syntax:
-->

Haskellでは、次のような自然な構文で演算子を定義することができます。

```haskell
f $ x = f x
```

<!--
In PureScript, you provide an operator alias for a named function. Defining functions using operators is removed since version 0.9.
-->

PureScriptでは、演算子は名前付き関数の別名として提供することになります。演算子を使った関数の定義は、バージョン0.9で廃止されました。

```purescript
apply f x = f x
infixr 0 apply as $
```

<!--
## Operator Sections
-->

## 演算子のセクション

<!--
In Haskell, there is syntactic sugar to partially apply infix operators.
-->

Haskellでは、中置記法の演算子の部分適用には構文糖があります。

```haskell
(2 ^) -- desugars to `(^) 2`, or `\x -> 2 ^ x`
(^ 2) -- desugars to `flip (^) 2`, or `\x -> x ^ 2`
```

<!--
In PureScript, operator sections look a little bit different.
-->

PureScriptでは、演算子セクションはちょっと異なる見た目になります。

```purescript
(2 ^ _)
(_ ^ 2)
```

<!--
## Extensions
-->

## 拡張

<!--
The PureScript compiler does not support GHC-like language extensions. However, there are some "built-in" language features that are equivalent (or at least similar) to a number of GHC extensions. These currently are:
-->

PureScriptコンパイラはGHCのような言語拡張を提供しません。しかし、GHC拡張のいくつかと同等の機能（もしくは少なくとも似たような機能）が、『組み込みの』言語機能として存在しています。

* DataKinds (see note below)
* EmptyDataDecls
* ExplicitForAll
* FlexibleContexts
* FlexibleInstances
* FunctionalDependencies
* KindSignatures
* MultiParamTypeClasses
* PartialTypeSignatures
* RankNTypes
* RebindableSyntax
* ScopedTypeVariables

<!--
Note on `DataKinds`: Unlike in Haskell, user-defined kinds are open, and they are not promoted, which means that their constructors can only be used in types, and not in values. For more information about the kind system, see https://github.com/purescript/documentation/blob/master/language/Types.md#kind-system
-->

`DataKinds`については注意してください。Haskellとは異なり、ユーザは種を自分で定義することができますが、それらは昇格されません。つまり、これらのコンストラクタは型でのみ使うことができ、値では使うことができません。種のシステムについての詳しい情報は、以下を参照してください。

https://github.com/purescript/documentation/blob/master/language/Types.md#kind-system

<!--
## `error` and `undefined`
-->

## `error`と`undefined`

<!--
For `error`, you can use `Effect.Exception.Unsafe.unsafeThrow`, in the `purescript-exceptions` package.
-->

`error`については、`purescript-exceptions`パッケージの`Effect.Exception.Unsafe.unsafeThrow`を使うことができます。

<!--
`undefined` can be emulated with `Unsafe.Coerce.unsafeCoerce unit :: forall a. a`, which is in the `purescript-unsafe-coerce` package. See also https://github.com/purescript/purescript-prelude/issues/44.
-->

`undefined` は`purescript-unsafe-coerce`パッケージにある `Unsafe.Coerce.unsafeCoerce unit :: forall a. a`で模倣することができます。 https://github.com/purescript/purescript-prelude/issues/44 を参照してみてください。

<!--
Although note that these might have different behaviour to the Haskell versions due to PureScript's strictness.
-->

ただし、PureScriptの正格性が原因で、これらはHaskell版とは異なる振る舞いを持つことがあるのに注意してください。

<!--
## Documentation comments
-->

## ドキュメントコメント

<!--
When writing documentation, the pipe character `|` must appear at the start of every comment line, not just the first. See [the documentation for doc-comments](Syntax.md#comments) for more details.
-->

ドキュメントを書くときは、ドキュメントコメントの最初の一行だけではなく、ドキュメントコメントのすべての行の先頭にパイプ文字`|`を書かなければなりません。詳しくは[the documentation for doc-comments](https://github.com/purescript/documentation/blob/master/language/Syntax.md#comments)を参照してください。

<!--
## Where is ... from Haskell?
-->

## Haskellの◯◯はどこにあるの？

<!--
As PureScript has not inherited Haskell's legacy code, some operators and functions that are common in Haskell have different names in PureScript:
-->

PureScriptはHaskellのコードをそのまま引き継いでいるわけではないので、Haskellの演算子や関数のなかには、PureScriptでは異なる名前を持っているものがあります。

<!--
- `(>>)` is `(*>)`, as `Apply` is a superclass of `Monad` so there is no need to have an `Monad`-specialised version.
- Since 0.9.1, the `Prelude` library does not contain `(++)` as a second alias for `append` / `(<>)` (`mappend` in Haskell) anymore.
- `mapM` is `traverse`, as this is a more general form that applies to any traversable structure, not just lists. Also it only requires `Applicative` rather than `Monad`. Similarly, `liftM` is `map`.
- Many functions that are part of `Data.List` in Haskell are provided in a more generic form in `Data.Foldable` or `Data.Traversable`.
- `some` and `many` are defined with the type of list they operate on (`Data.Array` or `Data.List`).
- Instead of `_foo` for typed holes, use `?foo`. You have to name the hole; `?` is not allowed.
- Ranges are written as `1..2` rather than `[1..2]`

-->

- `(>>)`は`(*>)`に変わりました。`Apply`は`Monad`のスーパークラスなので、`Monad`専用のバージョンは必要ないからです。
- 0.9.1以降、`Prelude`ライブラリは`append`つまり`(<>)` (Haskellでは`mappend`)のふたつめの別名である`(++)`をもはや含んでいません。
- `mapM`は`traverse`です。`traverse`は、リストに限らず、どんなtraversableな構造に対しても適用するより一般的な形式であるからです。また、`Monad`ではなく`Applicative` であることだけを要求します。同じように、`liftM`も`map`になっています。
- Haskellの`Data.List`の一部の関数は、 `Data.Foldable`や `Data.Traversable`でもっと一般的な形式で提供されています。
- `some`や`many`が　リストのような型(`Data.Array` や `Data.List`)にそれぞれ　定義されています。
- typed holesには`_foo`ではなく`?foo`を使ってください。holeには名前をつけなくてはならず、単なる`?`は禁止です。
- 範囲は`[1..2]`ではなく`1..2`のように書きます。

----

(翻訳ここまで)


# ＋α

そのほかの違いで、私が思いついたものや、指摘を受けて気付いたものをいくつか付け加えておきます。


## 文字列の型

Haskellでは文字列の型`String`は文字 `Char` のリスト`[Char]` の別名となっています。これは確かに直感的で、リストの関数がすべて `String` に対しても使えるというわかりやすさはあったものの、パフォーマンスが劣悪で結局は Haskell 最大の失敗のひとつとなりました。
OverloadedStrings拡張などで凌いではいるものの、文字列という基本的な型が`String`、`Text`、`ByteString`のように複数入り混じっているのは、わかりやすいとはとても言えません。PureScriptではJavaScriptの`String`と対応する`String`がひとつあるだけで、それとは別に`Char`があります。

* 参考：[文字列 - haskell-shoen](https://scrapbox.io/haskell-shoen/%E6%96%87%E5%AD%97%E5%88%97)


## Lazyな入出力

評価戦略とも関係するのですが、Haskellのでは古くから遅延評価の仕組みに基づく入出力の関数がいくつか提供されています。しかしこれは実用上はまったく使い物になりませんでした。PureScriptは正格評価なので、このような落とし穴はまったくありません。

* 参考：[ストリーミング - haskell-shoen](https://scrapbox.io/haskell-shoen/%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0)



## 型クラス制約

Haskellでは`(TypeClassA a, TypeClassB b) => Type a b`のようにして、いちどの`=>`で複数の型クラス制約を書くことができましたが、PureScriptでは`TypeClassA a => TypeClassB b => Type a b`のようにして、`=>`につきひとつづつの型クラス制約を書きます。これはPureScriptにおける型クラス制約は、**暗黙の引数**に他ならないためです。たとえば、`for`は`traverse`の引数の順序を交換したものに過ぎませんが、次のように定義されています。

```haskell
for
  :: forall a b m t
   . Applicative m
  => Traversable t
  => t a
  -> (a -> m b)
  -> m (t b)
for x f = traverse f x
```

これをコンパイルすると、次のようなJavaScriptへと変換されます。

```js
var $$for = function (dictApplicative) {
    return function (dictTraversable) {
        return function (x) {
            return function (f) {
                return Data_Traversable.traverse(dictTraversable)(dictApplicative)(f)(x);
            };
        };
    };
};
```

型クラス制約が特殊な引数でしかないということを考えると、カリー化された関数のように`=>`を繰り返し使う構文に一貫性があることがわかると思います。

## Eq型クラスのメンバ

Haskellでは`Eq`型クラスには`(==)`と`(/=)`のふたつが定義されますが、PureScriptの`Eq`型クラスでは`(==)`の本来の名前である`eq`だけが定義されており、`notEq`およびその別名である`(/=)`はただの独立した関数になっています。

Haskellで`(==)`と`(/=)`の両方が実装可能になっているのは最適化の都合だというような話だったかと思うのですが、`(/=)`が実装可能であることで実用上大きく性能が改善するというようなケースがあるのかは疑わしいです。PureScriptのシンプルな定義のほうが良さそうです。



## `for_`

Haskellでは同じ機能である`for :: (Traversable t, Applicative f) => t a -> (a -> f b) -> f (t b)`と`forM :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)`のふたつが効率上の理由で別々に提供されていますが、PureScriptでは`for`だけが提供されています。


## 関数をつくるアンダーバー`_`

演算子のセクションの話題と重複しますが、PureScriptでは式の一部がアンダーバー`_`になっていると、「その部分を引数として受け取るような関数」を表す式になることがあります。演算子では`(_ + 42)`は`\x -> x + 42`と同じ意味になりました。それと同様に、次のようなアンダーバーを条件部分においたcase式

```
case _ of 
    Nothing -> "Nothing"
    Just x -> "Just" <> show x
```

は、次のような関数と同じ意味になります。

```
\v -> case v of 
    Nothing -> "Nothing"
    Just x -> "Just" <> show x
```

これと同じようなアンダーバーを、`if _ then x else y`のようにif式でも使えますし、`_.foo`のようにプロパティの読み取りに使ったり、`_ { x = 42 }`や`_ { x = _ }`のようにしてプロパティの更新をする関数を書くこともできます。「アンダーバーに置き換えた部分を引数にとるような関数にする」という振る舞いにおいて構文上の一貫性が取れています。


## `map`の名前


Haskellには`map :: (a -> b) -> [a] -> [b]` がありますが、これは`Functor`の`fmap :: Functor f => (a -> b) -> f a -> f b`によって一般化され、`map`は不要になりました。これを踏まえてPureScriptには最初からリスト専用の関数である`map`はありませんので、`Functor`のほうの一般化された関数のほうに`map`の名前を使うことができました。



## `IO`と`Effect`

Haskellでは組み込みの作用の型は`IO`ですが、PureScriptでは`Effect`です。使い勝手のうえではほとんど差はないのですが、これらが入出力以外も含む作用一般のための型であることを踏まえると、強いて言えば`Effect`のほうが適切な名前なのではないかと思います。もちろん、`IO`のほうが短くて書くのが楽だというのはあります。


## 部分関数の排除

Haskellの`head :: [a] -> a`は空リストに適用すると実行時エラーになります。このようないわゆる部分関数がHaskellには少なからず存在しており、Haskellはその厳格なイメージに反して実行時エラーに対して脆弱な部分を数多く残しています。PureScriptではそれに相当する関数は`head :: forall a. Array a -> Maybe a`となっており、結果を`Maybe`で返すようになっているので実行時エラーになることがありません。このように、PureScriptのあらゆるAPIや構文は基本的に実行時エラーを起こさないような設計になっており、実行時エラーが起きることは基本的にありません。このような言語デザインは、同じくHaskell派生の言語であるElmでも同様になっています。

一方で、効率のためや記述性のために、部分関数である`head :: forall a. Partial => Array a -> a`も`Data.Array.Partial`という別のモジュールで提供されており、必要であれば安全性と引き換えにしてこちらを使うこともできます。



# ライブラリの高い一貫性

Preludeのところでも簡単に触れましたが、Haskellでは多くのライブラリが言語やコンパイラ組み込みになっている一方、PureScriptでは言語に組み込まれたライブラリは[`Prim`モジュール](https://pursuit.purescript.org/builtins/docs/Prim)に含まれた幾つかの基礎的な型のみです。特殊な要素を極限まで廃することで、言語自体をシンプルに保つと同時に、例外的に扱われる型が極めて少ない、一貫性のあるライブラリを提供できています。


# さいごに

Haskellはある種の伝説というか、関数型プログラミング言語のなかでも特にラディカルな位置にあって、Haskellを『美しい言語』だと評する人もいるようです。しかし、Haskellもまた長い歴史を持ち、歴史的な理由で多くの瑕疵を抱えてきた言語です。この記事にあるように、多くの関数が重複していたりしますし、部分関数も多く提供されており実行時エラーを引き起こしやすく、素のHaskellは機能不足で使いづらく多くのGHC拡張を導入してようやく快適に書ける言語だと言えます。そんなわけで私は決して『美しい』とまでは思いませんが、Haskellはそれを正しく理解し、なるべく互換性も保ちつつも改良を加え続け、泥臭くも着実に正しい方向に進んでいると私は思います。

そうはいっても、これだけ長い歴史のある言語を互換性を維持しながら改良を続けるのは容易ではなく、その点PureScriptはHaskellの精神を受け継ぎつつも反省を踏まえて新たに作られている言語で、Haskellに残された不満が大きく解消しています。Haskellに手を出すような人はかなり身軽に言語を乗り換えるタイプの人だと思いますし、PureScriptにも気軽に興味を示すHaskellユーザがもっと増えてくれればいいと私は思います。