And*_*tin 4 haskell applicative
我想知道是否有Applicative可以跟踪已经发生了多少应用操作.我尝试按如下方式实现它:
import Control.Applicative
main :: IO ()
main = print $ run 1 $ (,,,) <$> FromInt id <*> FromInt id <*> FromInt id <*> FromInt id
data FromInt a = FromInt (Int -> a)
run :: Int -> FromInt a -> a
run i (FromInt f) = f i
instance Functor FromInt where
fmap g (FromInt f) = FromInt (g . f)
instance Applicative FromInt where
pure a = FromInt (const a)
FromInt f <*> FromInt g = FromInt (\i -> f i (g (i + 1)))
Run Code Online (Sandbox Code Playgroud)
但是,这当然不起作用.如果我们在文件上调用runhaskell,我们得到:
(1,2,2,2)
Run Code Online (Sandbox Code Playgroud)
我想要的是这个:
(1,2,3,4)
Run Code Online (Sandbox Code Playgroud)
我已经看到人们通过将需求增加到实际数据中来实现这种效果(这就是yesod-forms执行其formlet样式的方式).这或多或少使用了一个变体State,如果它们不使用特定的辅助函数,它允许人们打破假定的不变量(我认为yesod被调用mhelper).我想知道增量是否可以像我试图的那样被拉入应用实例中.这将使违反这一特定的不变量变得不可能.
dan*_*iaz 10
(,) a是Applicative当a是一个Monoid.我们可以(,) (Sum Int)使用其他应用程序进行组合Data.Functor.Compose,并获得一个应用程序,让我们在运行之前估算分配给计算的"成本".
要计算步数,我们需要从基础应用程序提升功能,总是分配成本1:
module Main where
import Data.Monoid
import Control.Applicative
import Data.Functor.Compose
type CountedIO a = Compose ((,) (Sum Int)) IO a
-- lift from IO
step :: IO a -> CountedIO a
step cmd = Compose (Sum 1, cmd)
countSteps :: CountedIO a -> Int
countSteps = getSum . fst . getCompose
exec :: CountedIO a -> IO a
exec = snd . getCompose
program :: CountedIO ()
program = step (putStrLn "aaa") *> step (putStrLn "bbb") *> step (putStrLn "ccc")
main :: IO ()
main = do
putStrLn $ "Number of steps: " ++ show (countSteps program)
exec program
Run Code Online (Sandbox Code Playgroud)
为了更安全,我们可以隐藏newtype后面的组合aplicative,而不是导出构造函数,只导出step函数.
(使用pure成本0 创建的操作并不算作步骤.)