6

A -> IO B関数をに変換したいのですがIO (A -> B)、 の可能な値は有限数しかないことを知っていますA。現時点では私はちょうど

 convert :: (A -> IO B) -> IO (A -> B)
 convert f = do
     b1 <- f a1
     b2 <- f a2
     ...
     let f' a1 = b1
         f' a2 = b2
         ...
     return f'

ただし、これに必要なコードの量には満足していません。

4

5 に答える 5

9

Data.Mapルックアップをより高速に実行するために使用する、ヨアヒムの回答のわずかに強化されたバージョン。TupleSections プラグマも使用します。

{-# LANGUAGE TupleSections #-}

import Data.Map
import Control.Monad

きちんとしたものにするために、あなたのPiece型が与えられると仮定してくださいOrdBoundedおよびEnumインスタンス。

data Piece = Knight | Bishop | Rook deriving (Ord,Bounded,Enum,Show)

enumerate便利な関数を定義する

enumerate :: (Bounded a, Enum a) => [a]
enumerate = [minBound..maxBound]

今、あなたはすることができます

convert :: (Monad m, Bounded a, Enum a, Ord a) => (a -> m b) -> m (a -> b)
convert f = do
    memo <- sequence [liftM (a,) (f a)  | a <- enumerate]
    return (fromList memo!)
于 2013-09-19T11:08:28.247 に答える
4

完全を期すために、Hackage の可算パッケージFiniteが型クラスを提供することでこれを可能にしていることを述べておきます。次のようなものを定義します

instance Finite Piece where
  allValues = [Pawn, Knight, Bishop, Rook, Queen, King]

それからあなたは持っています

assemble :: (Finite a, Applicative f) => (a -> f b) -> f (a -> b)

これは、まさにあなたが必要とするものに特化します。

ソースを見ると連想リストを使っているようで、型が大きいと遅くなります。Foldableさらに、関数に対してandTraversableおよびEq(!)のいくつかの孤立したインスタンスを定義します。

于 2013-09-19T18:07:52.390 に答える
0

あなたの関数シグネチャはa->m b、入力時に任意の関数を許可しますが、内部では特定の範囲の値を想定しています。convert署名が宣言しているように見えるほど多形的ではありません。

あなたが行ったことは、a から b へのマップを作成し、そのマップで純粋な値を検索する純粋な関数を作成したことです。理由は次のとおりです。

あなたが求めているのは、モノイド圏 (C, ⊗, I) のテンソル強度 strength :: (Monad m) => (a, m b) -> m (a, b)の実装に似ています - 圏 C の二項関係 ⊗ とモナド m が与えられた場合、a ⊗ mb を m (a ⊗ b) に変換します。これが特定の要件を満たす二項関係で可能な場合、そのモナドは強力です。Haskell では、テンソル積 a ⊗ b がペアとして選択された場合、すべてのモナドは強い(a, b)ですstrength (a, mb) = mb >>= return . (a,)。しかし、ここでは二項関係に対して同じことをしようとしています->。残念ながら、a -> bをテンソル積として選択することはできません。これは双関手ではないためですa。そのため、任意の関数に対して必要なことを達成することはできません。

あなたの場合の違いは、基本的にすべてのペアを構築したことです(a,b)。したがってabたとえばm (Map a b). ここにある他のものは、「関数のような」インターフェースを公開する素敵なシュガーを提供しましたが、それらはマップ内のルックアップにすぎません。

于 2013-09-19T11:29:42.157 に答える
0

関数f :: A -> IO B があり、 があり、関数をasでg :: IO A使用しますconvertApplicative <*> :: f (a -> b) -> f a -> f b

fg :: IO a -> (a ->IO B) -> IO B
fg g f = (convert f) <*>  g

しかし、あなたはモナドを使うことができます(>>=) :: m a -> (a -> m b) -> m b

fg :: IO a -> (a ->IO B) -> IO B
fg g f = g >>= f
于 2013-09-19T09:52:09.410 に答える