質問: do \0 -> 1 \1 -> x \2 -> x * x \n -> if even n then pow (pow x 2) (n `div` 2) else x * pow (pow x 2) ((n - 1) `div` 2) ``` しかし、これを実行するとコンパイルは通るのですが、無限ループになってしまっているようなのです。 なぜ、無限ループの陥ってしまうのかを教えていただきたいです。 開発環境はOS:Windows 10、コンパイラ:ghc 8.6.3です。
回答: > > Haskellの勉強中にふとラムダ式でパターンは使えるのかと思い、 > > > 残念ながら少なくとも標準のHaskellでは使えません。 `LambdaCase`というGHCによる言語拡張を有効にする必要があります。 言語拡張を有効にする場合、下記のような特殊なコメントを、ファイルの先頭に書いてください。 ``` {-# LANGUAGE LambdaCase #-} ``` GHCi上で試したい場合、下記のように入力してください。 ``` :set -XLambdaCase ``` しかしいずれにしても、ラムダ式の中でパターンマッチをする構文は、tokumeimanxxさんに挙げていただいたようなものではありません。 にもかかわらずなぜコンパイルが通ったのかというと、それは`do`を使ったからです。 `do`は通常、Monad型クラスのインスタンスである型の値(「アクション」とも言います)を行ごとに列挙するのに使用するのですが、tokumeimanxxさんが書いたように、それ以外の式を行ごとに列挙するのにも使えます。 なので、tokumeimanxxさんの例で言う`\0 -> 1`、`\1 -> x`といった行は、**それぞれ別々のラムダ式として解釈**されてしまっています。 `do`記法にアクションでない、普通の式を列挙した場合、結果を`let`で代入しなければ、それらの**式は無視**されてしまいます。 結果、最後の行に当たる ``` \n -> if even n then pow (pow x 2) (n `div` 2) else x * pow (pow x 2) ((n - 1) `div` 2) ``` のみが有効な式として解釈されたため、`if`式の`then`節も`else`節もどちらでも再帰している上記の式によって、無限ループとなってしまった、ということです。 この、「`do`に列挙した式の結果をどこにも代入してない」という間違いは、GHCの警告を有効にすることで、検出できます。 例えば、tokumeimanxxさんのコードを`pow.hs`という名前で保存した上で、`GHCi`上で下記のように入力すれば、その警告を見ることができるでしょう。 `warning: [-Wunused-do-bind]`と書かれている警告が、当該の警告です。 ``` > :set -Wall > :l pow.hs [1 of 1] Compiling Main ( pow.hs, interpreted ) pow.hs:3:5: warning: [-Wunused-do-bind] A do-notation statement discarded a result of type ‘Integer’ Suppress this warning by saying ‘_ <- \ 0 -> 1’ | 3 | \0 -> 1 | ^^^^^^^^ ... 省略 ... Ok, one module loaded. ```