Haskellの1 == "x" が違法だなんて誰も言ってない！

# 前提
例えばJavaを例に上げると、全てのclassはObjectを継承しており、Objectがequalsメソッドを持つので
異なる型を比較（`equals`）できてしまいます。

```java
class Foo {}
class Bar {}

public class Test {
    public static void main(String[] args) {
        System.out.println(new Foo().equals(new Bar()));
    }
}
// {output}
// false
```

これはインスタンスをアップキャストしたい際などには便利ですが、
私個人としては「ある値x,yが異なる型を持てば同じものではない（`x != y`）」というものを認めた方が
誤りが発生しにくいと考えています :hankey:

それをおおよそ認めたとも捉えれられる言語の１つとしてHaskellがあります :sparkle:

Haskellは異なる型の比較（`==`）をコンパイルエラーで報告します。

```haskell
-- CharとBoolの比較
main :: IO ()
main = print $ 'a' == True
-- /tmp/nvimkIYPkj/4.hs:2:23: error:
--     • Couldn't match expected type ‘Char’ with actual type ‘Bool’
--     • In the second argument of ‘(==)’, namely ‘True’
--       In the second argument of ‘($)’, namely ‘'a' == True’
--       In the expression: print $ 'a' == True
```

繰り返しになりますが、これはある種の安全性を担保します。


# `1 == "x"`が`True`になることを合法にする
　上記のHaskellの例を見た時に、もしかしたら貴方は「柔軟性に乏しい」と考えたかもしれません。

そんなことはないよ。

そんなことないことについて、`1 == "x"`の比較が**型付け**によって`True`に成りうるという事実を以て示したいと思います。
（主にGHC拡張を振りかざすことによって）

## `IsString` + `Num`
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">NumとEqとIsStringのインスタンスだけでできると思います。 <a href="https://t.co/DSMCmvAIVX">pic.twitter.com/DSMCmvAIVX</a></p>&mdash; caffeine propulsion (@iand675) <a href="https://twitter.com/iand675/status/955758784487534593?ref_src=twsrc%5Etfw">2018年1月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```haskell
{-# LANGUAGE OverloadedStrings #-}

import Data.String (IsString(..))

data Foo = Foo

instance IsString Foo where
  fromString _ = Foo

instance Num Foo where
  fromInteger _ = Foo

instance Eq Foo where
  _ == _ = True

default (Foo)

main :: IO ()
main = print $ 1 == "x"
-- {output}
-- True
```

　値`1`と`"x"`を、単一の値を持つ型`Foo`に型付けしてしまうアプローチです。

　GHCには`OverloadedStrings`という独自言語拡張があり、
これは通常`"x"`が`"x" :: String`という暗黙的型付けを行うルールを、
`"x" :: IsString x => x`という暗黙的型付けに変更します。

つまるところ`"x" :: Foo`という型付けが合法になります。

　文字列リテラルに関する`OverloadedStrings`と似たような、数値リテラルに対する暗黙的型付けルールを
Haskellはデフォルトで持ちます。

このルールは値`1`を`1 :: Num a => a`というような型（[^1]）に型付けます。
ですので`1 :: Foo`という暗黙的型付けが合法になります。

　最後に`default (Foo)`は`1`のような明示的型付きを成されていない数値リテラルを
デフォルトで`Foo`に型付けるようにします。

　上記3つのルール

- `OverloadedStrings`が`"x" :: IsString x => x`に型付ける
- Haskellのデフォルト挙動が`1 :: Num a => a`に型付ける
- `default (Foo)`が`1 :: Foo`に型付ける

によって`1 == "x"`が`(1 :: Foo) == ("x" :: IsString x => x)`として型付けられる。
かつ`==`は左辺と右辺に同じ型を持つので
`(1 :: Foo) == ("x" :: Foo)`（`(==) :: Foo -> Foo -> Bool`）
を導くことができました :boom:


## Num
　先程は`Foo`に集約しましたが、しかしながら`String`に集約することも可能です。

```haskell
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}

instance Num String where
  fromInteger _ = "x"

default (String)

main :: IO ()
main = print $ 1 == "x"
-- {output}
-- True
```

　これは章「`IsString` + `Num`」と全く同じことをしていますが、
ただし`1`を`1 :: String`に型付けています。


## RebindableSyntax
　最後に1つ、ぶっ飛んだ例を紹介して終わります。
これについては、あまり型付けに関していません。

```haskell
{-# LANGUAGE RebindableSyntax #-}

import Prelude (Integer, String, IO, print, ($), (==))

fromInteger :: Integer -> String
fromInteger _ = "x"

main :: IO ()
main = print $ 1 == "x"
-- {output}
-- True
```

　GHCの`RebindableSyntax`拡張は、Haskell標準が`1`という式を`Prelude.fromInteger (1 :: Integer)`という式に展開するという仕様について改変します。

- [7.3. Syntactic extensions](https://downloads.haskell.org/~ghc/7.2.1/docs/html/users_guide/syntax-extns.html)
    - 7.3.11. Rebindable syntax and the implicit Prelude import

Haskell標準は`1`を`Prelude.fromInteger (1 :: Integer)`に展開しますが、
`RebindableSyntax`が有効になっている場合は`1`を`fromInteger (1 :: Integer)`に展開します。

つまり、とりあえず現在のスコープにある`fromInteger`と`Integer`を取ってきて使うというめっちゃ乱暴なものです :boom:

ですので`1 == "x"`がローカルの`fromInteger`の定義を用いて`"x" == "x"`という簡素な式を導きます :innocent:

`Integer`をローカルに定義して、そちらを使うようにしても面白いかもしれません。


# 参考ページ

- [7.3. Syntactic extensions](https://downloads.haskell.org/~ghc/7.2.1/docs/html/users_guide/syntax-extns.html)
    - 7.3.11. Rebindable syntax and the implicit Prelude import

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">プログラマの面接を行うことになった面接官がHaskellerに尋ねた。<br>「2+2は何になりますか?」<br>Haskellerはドアに鍵をかけ、型定義とそれに対するNumインスタンスを書きながら小声で尋ねた。<br>「2+2をいくつにしたいんです？」<a href="https://t.co/ePWU41mZDr">https://t.co/ePWU41mZDr</a> <a href="https://t.co/0uQR1HEVpl">pic.twitter.com/0uQR1HEVpl</a></p>&mdash; Make 生活リズム 正常 again (@mod_poppo) <a href="https://twitter.com/mod_poppo/status/955685593471705088?ref_src=twsrc%5Etfw">2018年1月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">みなさん、 2+2 のようなクソ2番煎じネタじゃなくて、代数的実数の方を拡散してください <a href="https://t.co/eSMVWbRyTo">https://t.co/eSMVWbRyTo</a></p>&mdash; Make 生活リズム 正常 again (@mod_poppo) <a href="https://twitter.com/mod_poppo/status/955716537683341312?ref_src=twsrc%5Etfw">2018年1月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">NumとEqとIsStringのインスタンスだけでできると思います。 <a href="https://t.co/DSMCmvAIVX">pic.twitter.com/DSMCmvAIVX</a></p>&mdash; caffeine propulsion (@iand675) <a href="https://twitter.com/iand675/status/955758784487534593?ref_src=twsrc%5Etfw">2018年1月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

- - -

[^1]: 実際は暗黙的型付けというよりは糖衣構文の展開だけど、「`1`が`Num`インスタンスのいずれかに型付けられる」ということを導くのは同じはず