适用于增加haskell环境的应用

时间:2022-09-13 17:05:03

I'm wondering if there is an Applicative that can track how many applicative operations have occurred. I tried to implement it as follows:

我想知道是否有一个可以跟踪已经发生了多少应用操作的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)))

But, this of course does not work. If we call runhaskell on the file, we get this:

但是,这当然不起作用。如果我们在文件上调用runhaskell,我们得到:

(1,2,2,2)

And what I want is this:

我想要的是这个:

(1,2,3,4)

I've seen people accomplish this effect by pushing the requirement to increment into the actual data (this is how yesod-forms does its formlet-style implementation). This more-or-less uses a variation on State, and it allows people to break assumed invariants if they don't use particular helper functions (I think the yesod one is called mhelper). I want to know if the incrementing can be pulled into the applicative instance as I have tried to do. This would make violating this particular invariant impossible.

我已经看到人们通过将需求增加到实际数据中来实现这种效果(这就是yesod-forms执行其formlet样式的方式)。这或多或少使用State的变体,并且如果他们不使用特定的辅助函数,它允许人们打破假定的不变量(我认为yesod被称为mhelper)。我想知道增量是否可以像我试图的那样被拉入应用实例中。这将使违反这一特定的不变量变得不可能。

1 个解决方案

#1


(,) a is an Applicative when a is a Monoid. We can compose (,) (Sum Int) with other applicative using Data.Functor.Compose, and get an applicative that lets us estimate the "cost" assigned to a computation before running it.

(,)a是a是Monoid时的应用。我们可以使用Data.Functor.Compose与其他应用程序组合(,)(Sum Int),并获得一个应用程序,它允许我们在运行之前估计分配给计算的“成本”。

To count the steps, we need a lift function from the base applicative that always assigns a cost of 1:

要计算步数,我们需要从基础应用程序提升功能,总是分配成本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 

For greater safety, we could hide the composed aplicative behind a newtype, and not export the constructor, only the step function.

为了更安全,我们可以隐藏newtype后面的组合aplicative,而不是导出构造函数,只导出step函数。

(Actions created with pure have cost 0 and do not count as a step.)

(使用pure创建的操作的成本为0,不计入步骤。)

#1


(,) a is an Applicative when a is a Monoid. We can compose (,) (Sum Int) with other applicative using Data.Functor.Compose, and get an applicative that lets us estimate the "cost" assigned to a computation before running it.

(,)a是a是Monoid时的应用。我们可以使用Data.Functor.Compose与其他应用程序组合(,)(Sum Int),并获得一个应用程序,它允许我们在运行之前估计分配给计算的“成本”。

To count the steps, we need a lift function from the base applicative that always assigns a cost of 1:

要计算步数,我们需要从基础应用程序提升功能,总是分配成本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 

For greater safety, we could hide the composed aplicative behind a newtype, and not export the constructor, only the step function.

为了更安全,我们可以隐藏newtype后面的组合aplicative,而不是导出构造函数,只导出step函数。

(Actions created with pure have cost 0 and do not count as a step.)

(使用pure创建的操作的成本为0,不计入步骤。)