3

Haskell では合成はごく普通のことですが、合成関数の特別な動作を定義できることだけは知っています。

Prelude> (floor . sqrt) (10^55)
3162277660168379365112938496
Prelude> let (floor . sqrt) n | n < 2 = n | otherwise = head $ dropWhile (\x -> x^2 > n) $ iterate (\x -> (x + n `div` x) `div` 2) (n `div` 2)
Prelude> (floor . sqrt) (10^55)
3162277660168379331998893544

特殊定義関数の結果は正しいです (最初の浮動小数点エラーのため)。

.hs今、私は同じようにファイル内でやりたいと思っています

(floor . sqrt) n
    | n < 2 = n
    | otherwise = head $ dropWhile (\x -> x^2 > n)
                       $ iterate (\x -> (x + n `div` x) `div` 2) (n `div` 2)

main = do
    print $ (floor . sqrt) (10^55)

今度ghcは私に怒鳴る

Ambiguous occurrence `.'
It could refer to either `Main..', defined at me.hs:1:8
                      or `Prelude..',
                         imported from `Prelude' at me.hs:1:1
                         (and originally defined in `GHC.Base')

ファイルでこのような関数を定義することは可能.hsですか? (ただし、内部mainで定義してもlet問題ありません)。

4

2 に答える 2

13

まず第一に、GHCi でのあなたの例は、 と の特別な構成を定義していませfloorsqrt。代わりに、 、、(.)という名前の 3 つの引数を取り、 という名前の既存の標準関数を隠す演算子を定義しています。floorsqrtn(.)

次に、新しい関数を標準ライブラリ関数floorおよびsqrtに適用します。これらは、新しい関数で同じ名前のパラメーターになります(.)

表示されるエラーは、最上位の定義が既存の定義を自動的に非表示にしないためです。いずれにせよ、それは明らかに実際にやりたいことではありません。

これで、完全に新しい関数を定義して (groovy の回答のように独自の名前を付けることができれば) 特殊なfloor . sqrt関数を実行できますが、既存の関数の特殊化されたバージョンとして定義する方法は Haskell 自体にはありません。

あなたが考えている可能性があるのは、GHC でコンパイラ プラグマ書き換え規則を使用して、特定の式を同等の改良されたバージョンに自動的に置き換えることです。ただし、書き直したフォームが、置き換えたものと同じ答えになるように注意する必要があります。そうしないと、本当に不可解なデバッグ セッションが発生する危険があります。

于 2013-04-18T18:10:41.693 に答える
1

これはどう?

floorSqrt n
    | n < 2     = n
    | otherwise = head $ dropWhile (\x -> x^2 > n)
                       $ iterate (\x -> (x + n `div` x) `div` 2) (n `div` 2)

main = do
    print $ floorSqrt (10^55)
于 2013-04-18T18:07:57.793 に答える