53693


Haskellを勉強して1週間ほどなので、馬鹿らしい質問かもしれませんがあらかじめ御了承ください。

Haskellの勉強中にふとラムダ式でパターンは使えるのかと思い、下のような関数を作りました

[code]

    pow :: Num a => a -> Integer -> a
    pow x = 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)
    
[/code]

しかし、これを実行するとコンパイルは通るのですが、無限ループになってしまっているようなのです。  
なぜ、無限ループの陥ってしまうのかを教えていただきたいです。

開発環境はOS:Windows 10、コンパイラ：ghc 8.6.3です。


CC BY-SA 4.0
2019-03-24T10:44:01.077
53692
2019-03-24T22:33:43.710
2019-03-24T16:20:35.033
754
32650
question
haskell
Haskellのラムダ式のパターンマッチに関する質問です。


> Haskellの勉強中にふとラムダ式でパターンは使えるのかと思い、

残念ながら少なくとも標準のHaskellでは使えません。  
`LambdaCase`というGHCによる言語拡張を有効にする必要があります。

言語拡張を有効にする場合、下記のような特殊なコメントを、ファイルの先頭に書いてください。

[code]

    {-# LANGUAGE LambdaCase #-}
    
[/code]

GHCi上で試したい場合、下記のように入力してください。

[code]

    :set -XLambdaCase
    
[/code]

しかしいずれにしても、ラムダ式の中でパターンマッチをする構文は、tokumeimanxxさんに挙げていただいたようなものではありません。

にもかかわらずなぜコンパイルが通ったのかというと、それは`do`を使ったからです。  
`do`は通常、Monad型クラスのインスタンスである型の値（「アクション」とも言います）を行ごとに列挙するのに使用するのですが、tokumeimanxxさんが書いたように、それ以外の式を行ごとに列挙するのにも使えます。  
なので、tokumeimanxxさんの例で言う`\0 -> 1`、`\1 -> x`といった行は、 **それぞれ別々のラムダ式として解釈**
されてしまっています。  
`do`記法にアクションでない、普通の式を列挙した場合、結果を`let`で代入しなければ、それらの **式は無視** されてしまいます。  
結果、最後の行に当たる

[code]

        \n  -> 
            if even n   then pow (pow x 2) (n `div` 2)
            else             x * pow (pow x 2) ((n - 1) `div` 2)
    
[/code]

のみが有効な式として解釈されたため、`if`式の`then`節も`else`節もどちらでも再帰している上記の式によって、無限ループとなってしまった、ということです。

この、「`do`に列挙した式の結果をどこにも代入してない」という間違いは、GHCの警告を有効にすることで、検出できます。

例えば、tokumeimanxxさんのコードを`pow.hs`という名前で保存した上で、`GHCi`上で下記のように入力すれば、その警告を見ることができるでしょう。

`warning: [-Wunused-do-bind]`と書かれている警告が、当該の警告です。

[code]

    > :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.
    
[/code]


CC BY-SA 4.0
2019-03-24T11:09:46.380
53693
2019-03-24T22:33:43.710
2019-03-24T22:33:43.710
8007
8007
53692
answer