2017-06-20 17 views
3

与えられたデータ型に応じて異なることを行う関数をHaskellで作成したいと思います。私はクラスが私が望むことをするべきだと思ったが、今は問題に遭遇した。私ができることをしたいのは、次のようなものです:インスタンスを宣言せずにクラス内の関数を呼び出す

let x1 = myFunction :: MyInstance1 
let x2 = myFunction :: MyInstance2 

そして、与えられたインスタンスに応じて異なることがあります。

私の現在のアプローチは、コンパイラは「型の変数A0が 『MyFunctionの』の曖昧性チェックでは曖昧である」と私はこれを読んでいたものからに関連している私に語った、しかし

class MyClass a where 
    create :: Int -> a 
    doSomething :: a -> [Int] 

    myFunction :: [Int] 
    myFunction = doSomething $ create 4 

instance MyClass MyInstance1 where 
    -- implementation of create and doSomething 

instance MyClass MyInstance2 where 
    -- implementation of create and doSomething 

ですコンパイラは 'doSomething'のどのインスタンスを呼び出すべきかを知らない。

「一般的な」方法で「doSomething」を呼び出し、データ型を後で適用する方法はありますか?あるいは、私の問題に対して全く異なるアプローチが必要なのでしょうか?

--- EDIT ---

だから私は私の問題へカイの答えを適用するが、それは完全にそれをまだ解決していません。ここに私のコードは

{-# LANGUAGE AllowAmbiguousTypes #-} 

class C a where 
    myFunction :: Int 
    create :: Int -> a 
    doSomething :: a -> Int 
    -- anotherFunction :: Int -> Int 
    -- anotherFunction x = doSomething $ create 4 

instance C Int where 
    myFunction = 1 
    create x = 2 * x 
    doSomething x = x + 4 

instance C Bool where 
    myFunction = 2 
    create x = True 
    doSomething x = if x then 42 else 24 

だこれはプロンプト

create @ Bool 4 
create @ Int 4 

にコンパイルされ、I期待される結果を返します。しかし、anotherFunction

Test.hs:8:23: error: 
    • Could not deduce (C a0) arising from a use of ‘doSomething’ 
     from the context: C a 
     bound by the class declaration for ‘C’ at Test.hs:(3,1)-(8,44) 
     The type variable ‘a0’ is ambiguous 
     These potential instances exist: 
     instance C Bool -- Defined at Test.hs:15:10 
     instance C Int -- Defined at Test.hs:10:10 
    • In the expression: doSomething $ create 4 
     In an equation for ‘anotherFunction’: 
      anotherFunction x = doSomething $ create 4 
Failed, modules loaded: none. 

が、この文脈でdoSomethingのを使用するだけではできませんエラーメッセージを与えて正常にコンパイルされませんか?私の考えは、すべてのインスタンスに対して同じように機能を実装して、あなたはそれを行うために拡張子のカップルを必要とするが、それはなんとかです

anotherFunction @ Bool 4 
anotherFunction @ Int 6 

答えて

4

を書くことです。ここではそれを示すのGHCiセッションです:

> :set -XAllowAmbiguousTypes 
> class C a where myFunction :: Int 
> instance C Int where myFunction = 1 
> instance C Bool where myFunction = 2 
> :set -XTypeApplications 
> myFunction @ Int 
1 
> myFunction @ Bool 
2 

「古い」ソリューションは、

class C a where myFunction :: proxy a -> Int 

をプロキシ引数を追加するためにうまくいけば、これは数年後には、スタイルの外にフェードインしますだろう - 私が渡し見つけますプロキシを渡すよりも明示的に明確な型。別の例で


完全なコード、:

{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-} 

class C a where 
    myFunction :: Int 
    create :: Int -> a 
    doSomething :: a -> Int 
    anotherFunction :: Int -> Int 
    anotherFunction x = doSomething $ create @ a 4 

instance C Int where 
    myFunction = 1 
    create x = 2 * x 
    doSomething x = x + 4 

instance C Bool where 
    myFunction = 2 
    create x = True 
    doSomething x = if x then 42 else 24 

テスト:

> :set -XTypeApplications 
> anotherFunction @ Bool 4 
42 
> anotherFunction @ Int 6 
12 
+0

編集あなたが示唆したものを対処するための質問。回答ありがとうございます! – ryan91

+1

@ ryan91これに 'a'型を渡す必要があります。私の編集を参照してください。 – chi

+0

もちろん!私はちょうどあなたのソリューションに徐々に近づいていたが、まだそれを作っていなかった、ありがとう! – ryan91

関連する問題