3

我仍然是 Haskell 的新手,我想我现在已经不知所措了。我的代码如下所示。

data World = World {
  intStack :: [Int],
  boolStack :: [Bool]
} deriving Show

instance IntStack World where
   getIntStack = intStack
   putIntStack ints (World _ bools) = World ints bools

instance BoolStack World where
    getBoolStack = boolStack
    putBoolStack bools (World ints _) = World ints bools

class IntStack a where
    getIntStack :: a -> [Int]
    putIntStack :: [Int] -> a -> a

class BoolStack a where
    getBoolStack :: a -> [Bool]
    putBoolStack :: [Bool] -> a -> a

(<=>) :: (IntStack c, BoolStack c) => c -> c
(<=>) w = putIntStack xs . putBoolStack ((x == x'):bs) $ w
    where (x:x':xs) = getIntStack w
          bs = getBoolStack w

(<+>) :: (IntStack c) => c -> c
(<+>) w = putIntStack ((x+x'):xs) w
    where (x:x':xs) = getIntStack w

我的重点(现在忽略函数中的错误情况)是能够将 (<=>) 和 (<+>) 等函数链接在一起,假设底层数据类型实现了函数所需的接口。

我觉得我可以用 state monad 清理很多,但我不确定如何构造它以允许更改实现 IntStack、BoolStack 等的任何数据类型。

我知道这是一个非常模糊的描述,但我觉得我上面的代码可能是绝对错误的方法。

感谢您的任何反馈!

4

2 回答 2

5
class IntStack a where
    getIntStack :: a -> [Int]
    putIntStack :: [Int] -> a -> a

class BoolStack a where
    getBoolStack :: a -> [Bool]
    putBoolStack :: [Bool] -> a -> a

恭喜,你刚刚发明了镜头!抽象[Int]and[Bool]类型,并使用data而不是class,你会得到类似的东西

data Lens a b = Lens
    { get :: a -> b
    , put :: b -> a -> a
    }

...这在 Hackage 上的六个包中实现。大多数至少提供:

  • 能够直接从数据声明中导出像您的getIntStack/putIntStackgetBoolStack/这样的投影镜头putBoolStack
  • 水平构图(首先运行一个镜头,然后是第二个镜头——例如,首先World从一些较大的结构中挑选一个,然后从其中挑选intStack一个World)和垂直构图(平行运行两个镜头,每个镜头在一对的一侧)
  • 一些与Stateand的接口StateT(例如,某种类型的东西Lens a b -> State b r -> State a r),它可以让你在 a 上编写计算[Bool][Int]运行它们,就好像它们是在 a 上的计算一样World

所以,检查一下黑客攻击!有data-lens族,包括核心派生能力有状态接口镜头包;和无意义的镜头包。我可能也忘记了一些。

于 2011-10-10T13:48:37.167 回答
1

您可以在 state monad 中实现 push 和 pop 操作,并使用它们来实现您的功能:

popInt :: IntStack c => State c Int
popInt = do
  (x:xs) <- getIntStack <$> get
  modify $ putIntStack xs
  return x

pushInt :: IntStack c => Int -> State c ()
pushInt x = do
  xs <- getIntStack <$> get
  modify $ putIntStack (x:xs)

(<+>) :: IntStack c => State c ()
(<+>) = do 
  x <- popInt
  x' <- popInt
  pushInt (x + x')
于 2011-10-10T11:52:55.727 回答