2013-08-07 8 views
7

私の意図は簡単です。私はタイプa -> bの関数をString -> Stringにラップしたいので(異種の関数の束をリストに入れることができるように)だから私は書く:Haskellの `a - > b`型の関数を` String - > String`型に変換する

wrap :: (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s :: a) 

はしかし、ghc苦情:

Could not deduce (Read a1) arising from a use of `read' 
from the context (Read a, Show b) 
    bound by the type signature for 
      wrap :: (Read a, Show b) => (a -> b) -> String -> String 

私はコードの私の作品が動作しませんとハックの種類は、私の目標を達成するために必要とされる理由を知りたいですか?

ありがとうございました。暗黙的に(関数内でそれ以外:: a注釈は型シグネチャにaから別のタイプを指しているので

{-# LANGUAGE ScopedTypeVariables #-} 
... 
wrap :: forall a b. (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s :: a) 

それを:あなたがScopedTypeVariablesような何かをする必要があります、明示的read sの種類を指定するには

+3

リストに異種関数を入れておけば、良いhaskellではなく、文字列変換でそれらをすべてラップするのは間違いです。あなたはもっと大きな意味で何をしようとしていますか? – NovaDenizen

+0

これは間違いです。これをしないでください。あなたは、Haskellの強力な型システムとそれに付随する偉大なコンパイル時のチェックをすべて破棄しています。あなたの車が罰金であると言って、それから高速道路で壊れてしまう整備士は、何かを修理するためにあなたに何かを(今はガレージにある間に) (後で、それはより多くのダメージを引き起こした後、コールアウト料金があり、それを修正する男は彼と一緒に必要な部分を持っていない)。スタティックタイピングは良いメカニック、ダイナミックタイピングはそれがいいと言っている人です。 – AndrewC

+0

@NovaDenizen私は間違いなく静的なタイピングをしています。最近私はシンプルなサーバーを書いています。 'a - > IO b'は実装されたサービスを表します。 1つのコンポーネントは '[(String、a - > IO b)]'を '' Map String(a - > IO b) 'に変換することです。しかし型システムはそれを許さない。型の安全性を強化するために、より複雑な型の設計をしています(つまり、クライアントがタイプaの入力に 'a - > IO b '型の入力を与えなければならないので、チェック)。しかし、キャッチは、サーバがハスケルで書かれたクライアントをまったく提供していない可能性があるということです。その場合、私の仕組みは機能しません。 – tfboy

答えて

13

に体を簡素化することができます。 wrap :: (Read a, Show b) => (a -> b) -> (String -> String)aは、read s :: aのものとはまったく異なるaです(両方とも普遍的に数値化されています)。これはエラーメッセージのa1のソースです。 GHCしかし、fの引数タイプは、アルファ変換

wrap :: (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s :: a1) 

にプログラムをwrap内に固定するので、単に型注釈を除去して正常に動作されます。あなたの関数は

wrap :: (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s) 
    -- Or wrap f = show . f . read 

となり、あなたはそれを使用することができます。

ghci> map ($ "42") [wrap (+ (7 :: Integer)), wrap (* (2.0 :: Double))] 
["49","84.0"] 

注これはread sは、あなたがダウンして書き込むことはできませんタイプを持っていることを意味していること。 Haskell 2010(または98)では、これを回避する唯一の方法はasTypeOf :: a -> a -> aのような関数を使うことです。 asTypeOfはちょうどconstですが、その型シグニチャーのおかげで、最初に返された引数は、その型と同じ型になるように制約されます。もちろん、aという変数を作成する必要があります。以下は、そのために働くでしょう:

wrap :: (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s `asTypeOf` fInput) 
    where fInput = undefined 
     fOutput = f fInput -- I still can't give this a type signature 

をGHCでは、これを避けるために、あなたはthe ScopedTypeVariables extensionをオンにすることができます。それで、すべての型変数をforallで明示的に修飾すると、それらは値レベルの名前と同じようにスコープされます。次に、あなたのコードは

{-# LANGUAGE ScopedTypeVariables #-} 
wrap :: forall a b. (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s :: a) 

になるしかし、あなたはこの単純な例のために、すべての任意の型の注釈を必要としない、覚えているでしょう。

10

手段::: forall a. a)。しかし、あなたはまた、単に完全に型注釈をドロップすることができますのでご注意:

wrap :: (Read a, Show b) => (a -> b) -> (String -> String) 
wrap f = \s -> show $ f (read s) 

read sの種類を推定することができるので。それはまた、あなたがHaskellはまたは範囲型変数を再利用しないので、あなたのコードは動作しません

wrap f = show . f . read 
関連する問題