2017-02-18 10 views
0

以下はおそらく愚かな例ですが、これを解決すると、別の問題が解決します。詳細はin this questionです。関数の結果タイプに基づく最適化

私はこのシグネチャを持つ関数を書きたい:

myread :: (Read a) => String -> a 

なときa ~ Int、その場合myread _ = 0を除いて、myread = read、その。

明らかにこの関数は愚かですが、ポイントは戻り値の型に基づいて最適化したいのです。

書き換えルールなどはここでは問題ありません。私の実際の問題については、ソリューションが書き換えルールであれば、起動しないケースがあるかどうかは問題ではありませんが、答えが出てくる場所を例に挙げてみたいと思います。

+0

正しいツールを手元に持っているようです。つまり、 'a'のクラス制約です。もちろん、 'Read Int'インスタンスは制御しませんが、実際のユースケースでは、クラスの定義とインスタンスを制御しているようです。または、おそらく私はあなたが「最適化」することを誤解していますか? (脇に:私は 'x :: H a => T a'はコンテキスト" H a "ではなくタイプ" x "を意味するのではなく、タイプ" H "のx (Read a => F a) - > X 'には適用されません。 – user2407038

+0

私は' Read'を制御しません。クラスであり、既に存在する場合、 'Int'のための自分自身の' Read'インスタンスを作ることはできません。多分私はあなたを誤解しています。 – Clinton

答えて

0

未定義のインスタンスで新しいクラスを定義することはどうですか?あなたはルールの左手側は表現コンテキストであることを思い出した場合

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE UndecidableInstances #-} 

class MyRead a where 
    myread :: String -> a 

instance {-# OVERLAPPABLE #-} Read a => MyRead a where 
    myread = read 

instance MyRead Int where 
    myread = const 0 

main = do 
    print $ (myread "True" :: Bool) -- True 
    print $ (myread "\"string\"" :: String) -- "string" 
    print $ (myread "12" :: Int) -- 0 
+0

この場合、 'MyRead'は署名' myread :: MyRead a => String - > a'を持ちます。質問で述べたように、必要に応じて、署名は 'myread :: Read a => String - > a'になります(それ以外の場合、関連する質問の問題は解決しません)。 – Clinton

1

あなたは、パターンの文脈では、(おそらく)で、書き換えルールと直接ないを明白な方法でこれを行うことができます。特に、左側のタイプのアプリケーションは完全に有効です。でもタイプのアプリケーションなし

{-# LANGUAGE TypeApplications #-} 

module A where 

{-# INLINE [1] myread #-} 
{-# RULES "myread" forall s . myread @Int s = 0 #-} 

myread :: Read a => String -> a 
myread = read 

は、次のようにも完全に有効です(ただし、出力タイプはf aだった、あなたは、あなたが.. = (result :: [ _ ])を持っていることができなかっただけでf「最適化」したかった場合例えば、一般的にはできない場合があります):

{-# RULES "myread" forall s . myread s = (0 :: Int) #-} 

そして、一例として

module B where 

import A 

fun :: String -> String -> (Int, Bool) 
fun x y = (myread x, myread y) 

ルール火災は常に(もちろん、コアを見ていることを証明を使用します省略無関係ビット):

fun4 :: Int 
fun4 = I# 0# 

fun :: String -> String -> (Int, Bool) 
fun = 
    \ _ (w1 :: String) -> 
    (fun4, 
    case readEither6 (run fun3 w1) of _ { 
     [] -> fun2; 
     : x ds -> 
     case ds of _ { 
      [] -> x; 
      : ipv ipv1 -> fun1 
     } 
    }) 

注、これは正確に目標が何であるかを実際にコメントしていない私はよく分からないという理由だけ答えですが、コードはコメントに適合していないでしょう。

関連する問題