1

とが同じ型の場合は がその型、そうでない場合は となるbar :: Foo a -> Foo b -> Foo cような関数を書きたいと思います。機能的な依存関係が役立つと思いますが、どうすればよいかわかりません。私は書きますabc()

class Bar a b c | a b -> c where
  bar :: Foo a -> Foo b -> Foo c 

instance Bar x x x where
  bar (Foo a) (Foo b) = Foo a

instance Bar x y () where
  bar _ _ = Foo ()

しかし明らかに、bar (Foo 'a') (Foo 'b')両方のインスタンスを満たしています。x /= y2 つの異なる型のみのインスタンスを宣言するにはどうすればよいですか?

4

1 に答える 1

3

あなたはほとんどそこにいます。OverlappingInstancesと を使用すると、これを非常に簡単に行うことができますUndecidableInstances。これはおそらく閉じた世界の種類のクラスとして意図されているため、決定不能なインスタンスはおそらく大したことではありません。

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances
 , OverlappingInstances, TypeFamilies, UndecidableInstances #-}

data Foo a = Foo a deriving Show

class Bar a b c | a b -> c where
  bar :: Foo a -> Foo b -> Foo c 

instance Bar x x x where
  bar (Foo a) (Foo b) = Foo a

instance (u ~ ())=> Bar x y u where
  bar _ _ = Foo ()

最後のインスタンスに注意してください。()インスタンス ヘッドを配置すると、他のインスタンスよりも具体的になり、最初に一致するため、代わりにTypeFamilies( ~) からの型等価アサーションを使用します。私はこれをオレグから学びました。

これがどのように動作するかに注意してください。

*Main> bar (Foo 'a') (Foo 'b')
Foo 'a'
*Main> bar (Foo 'a') (Foo True)
Foo ()
*Main> bar (Foo 'a') (Foo 1)

<interactive>:16:1:
    Overlapping instances for Bar Char b0 c0
      arising from a use of `bar'
    Matching instances:
      instance [overlap ok] u ~ () => Bar x y u
        -- Defined at foo.hs:13:10
      instance [overlap ok] Bar x x x -- Defined at foo.hs:9:10
    (The choice depends on the instantiation of `b0, c0'
     To pick the first instance above, use -XIncoherentInstances
     when compiling the other instance declarations)
    In the expression: bar (Foo 'a') (Foo 1)
    In an equation for `it': it = bar (Foo 'a') (Foo 1)

<interactive>:16:20:
    No instance for (Num b0) arising from the literal `1'
    The type variable `b0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus three others
    In the first argument of `Foo', namely `1'
    In the second argument of `bar', namely `(Foo 1)'
    In the expression: bar (Foo 'a') (Foo 1)

また、GHC 7.8 では、閉じた型ファミリにアクセスできるようになると思いますが (これは私の興味に関連しているため)、これをより適切な方法で処理できるようになりますが、詳細は少し混乱します。

于 2013-11-06T18:36:42.267 に答える