3

Haskell で多変量関数を勉強しているときに、次の SO の質問に出くわしました。

多変量ハスケル関数を作成するには?

Haskell、多変量関数と型推論

そして、可変数の文字列を取り、それらを単一の文字列に連結/マージする関数を実装して、試してみることにしました。

{-# LANGUAGE FlexibleInstances #-}

class MergeStrings r where
    merge :: String -> r
instance MergeStrings String where
    merge = id
instance (MergeStrings r) => MergeStrings (String -> r) where
    merge acc = merge . (acc ++)

これは、少なくとも 1 つの文字列引数を指定して merge を呼び出し、最終型を指定すると、これまでのところ機能します。

foo :: String
foo = merge "a" "b" "c"

final 型を省略すると、エラーが発生します。つまり、次をコンパイルします。

bar = merge "a" "b" "c"

結果は

test.hs:12:7: error:
    • Ambiguous type variable ‘t0’ arising from a use of ‘merge’
      prevents the constraint ‘(MergeStrings t0)’ from being solved.
      Relevant bindings include bar :: t0 (bound at test.hs:12:1)
      Probable fix: use a type annotation to specify what ‘t0’ should be.
      These potential instances exist:
        instance MergeStrings r => MergeStrings (String -> r)
          -- Defined at test.hs:6:10
        instance MergeStrings String -- Defined at test.hs:4:10
    • In the expression: merge "a" "b" "c"
      In an equation for ‘bar’: bar = merge "a" "b" "c"
   |
12 | bar = merge "a" "b" "c"
   |

たとえば、エラーメッセージは簡単に思いつくことができるので、完全に理にかなっています。

bar :: String -> String
bar = merge "a" "b" "c"

baz = bar "d"

単一barの文字列ではなく、1 つの文字列を受け取って返す関数に変換します。

結果の型が型でなければならないことを Haskell に伝える方法はありStringますか? たとえば、明示的に定義せずText.Printf.printf "hello world"に型に評価されます。String

4

2 に答える 2

2

Brad (コメント)と Max は、printf "…" …</code> to IO ( ) is the reason for it working in ghci without type annotations. But it is not the end of the story. There are things we can do to make your definition of bar work.

First, I should mention the «monomorphism restriction» — an obscure and unintuitive type inference rule we have in Haskell. For whatever reason, the designers of Haskell decided that a top level definition without a type signature should have no polymorphic variables in its inferred type — that is, be monomorphic. <code>barはポリモーフィックなので、影響を受けることがわかります。

一部の型クラス(特に数値)には、型シグネチャなしで宣言し、それを推論させることを可能にする既定のルールがあります。型のデフォルト設定は、いくつかの祝福されたクラスでしか利用できないため、独自のクラスで使用することはできず、指定されたデフォルトの GHC がなければ、どの特定の単相型を選択するかを決定できません。x = 13x :: Integer

ただし、型チェッカーを満足させるために、デフォルトにする以外に、次のいずれかのことを行うことができます。

現在barはポリモーフィックであり、期待どおりに機能します。見る:

λ putStrLn bar
abc
λ putStrLn (bar "x")
abcx
λ putStrLn (bar "x" "y")
abcxy

デフォルト設定を使用して、show barwork などの式を作成することもできます。は、拡張デフォルト ルールShowが有効な場合にデフォルト設定できるクラスの 1 つであるため、使用したいモジュールで発行すると、期待どおりに機能します。default (String)show bar

于 2020-05-31T13:14:52.260 に答える