問題は何をするかではなくIO
、それがどのように定義されているか、その署名です。具体的には、これはデータかクラスか、a
その型パラメーターは " " か? どこにも見つかりませんでした。また、私はこれの構文上の意味を理解していません:
f :: IO a
問題は何をするかではなくIO
、それがどのように定義されているか、その署名です。具体的には、これはデータかクラスか、a
その型パラメーターは " " か? どこにも見つかりませんでした。また、私はこれの構文上の意味を理解していません:
f :: IO a
がデータ型であるかどうかを尋ねIO a
ました。そうです。そして、がその型パラメーターであるかどうかを尋ねa
ました。そうです。あなたはその定義が見つからないと言いました。それを見つける方法をお見せしましょう:
localhost:~ gareth.rowlands$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Prelude> :i IO
newtype IO a
= GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
-- Defined in `GHC.Types'
instance Monad IO -- Defined in `GHC.Base'
instance Functor IO -- Defined in `GHC.Base'
Prelude>
ghci では、:i
または:info
型について説明します。型宣言とそれが定義されている場所を示しています。IO
それが aMonad
であり、 a であることがわかりFunctor
ます。
この手法は、通常の Haskell 型でより便利です。他の人が指摘しているように、IO
Haskell では魔法です。典型的な Haskell 型では、型シグネチャは非常に明確ですが、知っておくべき重要なことIO
はその型宣言ではなく、IO
アクションが実際に実行されることIO
です。これは、通常は基盤となる C または OS ルーチンを呼び出すことによって、かなり従来の方法で行われます。たとえば、Haskell のputChar
アクションは C のputchar
関数を呼び出す場合があります。
あなたが私に尋ねるなら、これはとても良い質問です。私もこれについて非常に混乱したことを覚えています、多分これは助けになるでしょう...
'IO' は型コンストラクター、'IO a' は型、'a' ('IO a' 内) は型変数です。文字「a」には意味がありません。文字「b」または「t1」も同様に使用できます。
IO 型コンストラクターの定義を見ると、次のように定義された新しい型であることがわかります: GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC .Prim.RealWorld、a #))
'f :: IO a' は 'f' と呼ばれる関数の型であり、明らかに引数がなく、IO モナドの制約のない型の結果を返します。'in the IO monad' は、結果の計算中に f が何らかの IO を実行できることを意味します (つまり、'RealWorld' を変更します。'change' は、提供された RealWorld を新しいものに置き換えることを意味します)。f の結果は多態的です (これは、'Int' のような型定数ではなく、型変数 'a' です)。ポリモーフィックな結果とは、プログラム内で結果の型を決定するのは呼び出し元であることを意味します。したがって、ある場所では f を使用すると Int が返され、別の場所では String が返される可能性があります。「制約なし」とは、返すことができる型を制限する型クラスがないため、任意の型を返すことができることを意味します。
パラメータがなく、Haskell は純粋なので、なぜ 'f' は関数で定数ではないのですか? IO の定義は、'f :: IO a' は 'f :: GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, a #)' など、実際にはパラメータがあります。「現実世界の状態」です。
データ内のIO a
a
は、主に と同じ意味を持ちMaybe a
ます。しかし、次のようにコンストラクターを取り除くことはできません。
fromIO :: IO a -> a
fromIO (IO a) = a
幸いなことに、次のように、このデータをモナドで使用できます。
{-# LANGUAGE ScopedTypeVariables #-}
foo = do
(fromIO :: a) <- (dataIO :: IO a)
...