Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在haskell中提取此模式?_Haskell_Error Handling_Monads_Abstraction - Fatal编程技术网

如何在haskell中提取此模式?

如何在haskell中提取此模式?,haskell,error-handling,monads,abstraction,Haskell,Error Handling,Monads,Abstraction,场景:我有一个解释器,它从AST自下而上构建值。某些节点具有权限--其他布尔表达式。权限失败应该传播,但是如果AST中上面的节点具有权限,则成功可以恢复计算并停止错误的传播 起初我认为Error MyError MyValuemonad就足够了:MyError的一个成员可能是permerro,如果第二次检查成功,我可以使用catchError从permerro中恢复。但是,当我到达处理程序时,MyValue已经消失。我想最终可能会有一种方法,让PermError携带一个MyValue字段,这样处

场景:我有一个解释器,它从AST自下而上构建值。某些节点具有权限--其他布尔表达式。权限失败应该传播,但是如果AST中上面的节点具有权限,则成功可以恢复计算并停止错误的传播

起初我认为
Error MyError MyValue
monad就足够了:
MyError
的一个成员可能是
permerro
,如果第二次检查成功,我可以使用
catchError
permerro
中恢复。但是,当我到达处理程序时,
MyValue
已经消失。我想最终可能会有一种方法,让PermError携带一个
MyValue
字段,这样处理程序就可以恢复它,但这可能很难看,并且在每个步骤检查异常会破坏异常发生的概念

我在想另一种抽象方法。基本上,我必须返回一个数据类型
,要么是AllerrorExceptPermError(可能是PermError,MyValue)
,要么更简单地说是
(可能是AllErrors,MyValue)
(其他错误是不可恢复的,并且与错误单元组匹配得很好),我正在寻找一些可以避免元组混乱的东西,因为在操作的链接方式上似乎有一个共同的模式。我对哈斯克尔的了解仅此而已。在这种情况下,您如何利用haskell发挥优势

当我写这篇文章的时候,我想到了一个想法(一只奇特的橡皮鸭也是如此):一个在内部处理类型(a,b)的单子(当单子计算终止时,最终返回它,必须有某种
runMyMonad
),但让我尽可能直接处理类型b。差不多

data T = Pass | Fail | Nothing
instance Monad (T , b) where
  return v = (Nothing, v)
  (Pass, v) >>= g = let (r', v') = g v in (if r' == Fail then Fail else Pass, v')
  (Fail, v) >>= g = let (r', v') = g v in (if r' == Pass then Pass else Fail, v')
  (Nothing, _) >>= g = error "This should not have been propagated, all chains should start with Pass or Fail"

错误被简化为T,并且
实例
行可能有语法错误,但您应该了解这一点。这有意义吗?

我认为您可以使用
State
monad进行权限和值计算,并将其包装在
error
monad transformer中以处理错误。下面是这样一个例子,它展示了这个想法,这里的计算是汇总一个列表,权限是列表中偶数的数目,错误条件是当我们在列表中看到0时

import Control.Monad.Error
import Control.Monad.State

data ZeroError = ZeroError String
              deriving (Show)

instance Error ZeroError where


fun :: [Int] -> ErrorT ZeroError (State Int) Int
fun [] = return 0
fun (0:xs) = throwError $ ZeroError "Zero found"
fun (x:xs) = do
  i <- get
  put $ (if even(x) then i+1 else i)
  z <- fun xs
  return $ x+z


main = f $ runState (runErrorT $ fun [1,2,4,5,10]) 0
       where
         f (Left e,evens) = putStr $ show e
         f (Right r,evens) = putStr $ show (r,evens)
import Control.Monad.Error
进口控制单体状态
数据ZeroError=ZeroError字符串
派生(显示)
实例错误ZeroError where
乐趣::[Int]->errortZeroError(stateint)Int
fun[]=返回0
乐趣(0:xs)=投掷者$ZeroError“找到零”
乐趣(x:xs)=do

我为什么不在AST中传播正确的权限信息,例如通过
ReaderT Permissions…
?然后你可以在本地决定权限是否足够。我不明白为什么构建AST需要包含权限。为什么您不能(懒洋洋地)一步构建一个AST,然后对生成的数据结构运行权限计算?@kosmikus:因为权限本身就是表达式,需要自下而上进行计算。missingno:惰性地构建AST是第一步。第二步(这个问题的主题)是把它折叠成一个(isAllowed,Value)元组。你所做的有属性语法的味道。即使需要对权限进行自下而上的计算,如果需要,也可以将整个计算作为对树的一次遍历来编写。您计算的值的类型类似于
(权限,权限->值)
。也就是说,在每个节点中,您假设您获得最终权限作为输入,并决定如何向下分配权限。在顶部,您可以对函数应用自下而上计算的
权限
,以获得感兴趣的
值。你说得对,
State
也是一个选项。问题是,在我有限的经验中,
State
始终是一个选项:D我从Haskell(我想关于所有强类型语言,这里是恢复Python/JS程序员)中学到的一件好事是,如果您对类型进行尽职调查,避免过度泛型类型,您最终得到的类型签名只有一个可能的实现可以进行类型检查:正确的一个:-)我不太愿意接受这个答案,因为它确实不是我应该在这里使用的。在我的例子中,您有一个AST,与您的示例不同,权限可以恢复,但只能从家长处恢复。州政府将允许兄弟姐妹恢复决策。我可以添加检查,但重点是通过类型系统强制执行此保证。也许我根本不应该使用任何抽象,让我的eval函数返回一个(值,权限)元组并手动处理它们。