3

以下程序类型检查和编译:

import Control.Arrow

data Ns = Na | Nb | Nc | Nd deriving Show

data Net a where
    Uni :: a -> Net a
    Serial :: Net a -> Net a -> Net a
    Branch :: Show a => Net a -> Net (Net a, Net a)

deriving instance Show a => Show (Net a)

eval :: (Arrow a) => Net c -> a b (Net c)
eval (Uni m) = arr (const (Uni m))
eval (Serial m n) = eval m >>> eval n
--eval (Branch m) = eval m &&& eval m

example = Serial (Serial (Uni Na) (Uni Nb)) (Serial (Uni Nc) (Uni Nd))

main = do
    putStrLn $ show (app (eval example, Na))

但是,当我尝试为 添加案例时eval (Branch m),请键入检查炸弹。某种类型的东西

Arrow a => a b (Net d)

是预期的,但当然我的方式是

Arrow a => a b (c',c'')

有人对如何写作有建议eval (Branch m)吗?

编辑我

作为对@sabauma 评论的回应,我认为 for 的类型签名eval将不得不改变,但我不确定它应该是什么。

编辑二

这是应该发生的事情的示例:

branch = Branch example
app (eval branch, Na)

应该给,

Uni (Uni Na,Uni Na)

这就是@sabauma 的提议所做的。

4

3 回答 3

3

一种可能是

eval :: (Arrow a) => Net c -> a b (Net c)
eval (Uni m)      = arr (const (Uni m))
eval (Serial m n) = eval m >>> eval n
eval (Branch m)   = (eval m &&& eval m) >>> arr Uni

我不知道这是否具有所需的行为,但它会进行类型检查并且不是简单的解决方案。这使您无需更改类型签名即可逃脱。

于 2013-03-13T14:39:35.510 回答
3

我的猜测是重新定义Branch以采用两个参数(因为分支对我来说意味着这一点):

data Net a where
  Uni :: a -> Net a
  Serial :: Net a -> Net a -> Net a
  Branch :: Show a => Net a -> Net a -> Net (Net a, Net a)

导致

eval :: (Arrow a) => Net c -> a b (Net c)
eval (Uni m) = arr (const $ Uni m)
eval (Serial m n) = eval m >>> eval n
eval (Branch l r) = (eval l) &&& (eval r) >>> arr (uncurry Branch)

但我不能说这种变化对你是否有意义。您可能应该给出一些解释如何使用您的类型。

于 2013-03-13T14:51:52.880 回答
2

虽然我不完全确定您的代码的目的,这可能不是您所追求的,但以下类型检查:

eval :: Arrow a => Net c -> a b (Net c)
eval (Uni m)      = arr (const (Uni m)) 
eval (Serial m n) = eval m >>> eval n
eval (Branch m)   = arr (const (Branch m)) 

当然,arr . const对于 eval 来说是微不足道的,但现在我几乎可以肯定这不是你想要的。

于 2013-03-13T14:18:43.670 回答