6

IO 関数内で純粋関数を使用するにはどうすればよいですか? :-/

例: ファイル (IO 関数) を読み取っていて、参照透過性を持つ純粋な関数を使用して、そのコンテキスト (文字列) を解析したいと考えています。

純粋関数とIO関数という世界が分かれているようです。どうすればそれらを橋渡しできますか?

4

4 に答える 4

12

最も簡単な方法はfmap、次の型を持つ を使用することです。

fmap :: (Functor f) => (a -> b) -> f a -> f b

IOFunctorこれは、 for を代入IOfて取得することにより、上記の型を特殊化できることを意味します。

fmap :: (a -> b) -> IO a -> IO b

言い換えれば、as をbs に変換する関数を取り、それを使用してアクションの結果を変更しIOます。例えば:

getLine :: IO String

>>> getLine
Test<Enter>
Test
>>> fmap (map toUpper) getLine
Test<Enter>
TEST

そこで何が起こったのですか?さて、map toUpperタイプがあります:

map toUpper :: String -> String

引数としてa を取り、結果として aStringを返しますString。具体的には、文字列全体を大文字にします。

では、次のタイプを見てみましょうfmap (map toUpper)

fmap (map toUpper) :: IO String -> IO String

関数をアップグレードして、IO値を操作できるようにしました。アクションの結果を変換してIO、大文字の文字列を返します。

do記法を使用してこれを実装することもできます。

getUpperCase :: IO String
getUpperCase = do
    str <- getLine
    return (map toUpper str)

>>> getUpperCase
Test<Enter>
TEST

すべてのモナドには次のプロパティがあることがわかります。

fmap f m = do
    x <- m
    return (f x)

つまり、いずれかの型が を実装している場合、上記の定義を使用してMonad常に も実装できる必要があります。Functor実際、常に をliftMデフォルトの実装として使用できfmapます。

liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f m = do
    x <- m
    return (f x)

liftMfmapファンクターほど一般的ではないモナドに特殊化されていることを除いて、 と同じです。

したがって、IOアクションの結果を変換する場合は、次のいずれかを使用できます。

  • fmap
  • liftM、 また
  • do表記

どちらを好むかは本当にあなた次第です。個人的におすすめfmapです。

于 2013-02-17T04:49:00.163 に答える
2

実際の答えは次のとおりです。

main = do
  val <- return (purefunc ...arguments...)
  ...more..actions...

returndoに割り当てることができるように、適切なモナドでラップしvalます。

于 2015-06-11T20:00:45.443 に答える
2

Control.Monad の liftM 関数も考えられます。
あなたを助けるための小さな例(IOモナドの下にいるので、ghciに実行してください)

$ import Control.Monad -- to emerge liftM
$ import Data.Char     -- to emerge toUpper
$ :t map to Upper -- A pure function
map toUpper :: [Char] -> [Char]
$ :t liftM 
liftM :: Monad m => (a1 -> r) -> m a1 -> m r
$ liftM (map toUpper) getLine 
于 2013-02-17T00:51:39.903 に答える
2

アレックス・ホースマンが私を助けてくれました。彼は言った:

「たぶん私は誤解していますが、それはかなり単純に聞こえますか? do {x <- ioFunc; return (pureFunc x)}」

そして、私は私の問題を解決しました:

import System.IO  
import Data.List

getFirstPart line Nothing = line
getFirstPart line (Just index) = fst $ splitAt index line 

eliminateComment line = 
 getFirstPart line $ elemIndex ';' line

eliminateCarriageReturn line =
 getFirstPart line $ elemIndex '\r' line

eliminateEntersAndComments :: String -> String  
eliminateEntersAndComments text =
 concat $ map mapFunction $ lines text
 where
  mapFunction = (++ " ") . eliminateCarriageReturn . eliminateComment

main = do {
 contents <- readFile "../DWR-operators.txt"; 
 return (eliminateEntersAndComments contents)
}
于 2013-02-17T00:45:36.940 に答える