Haskell中的前提条件检查有哪些选项? [英] What are the options for precondition checking in Haskell

查看:157
本文介绍了Haskell中的前提条件检查有哪些选项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个简单的问题,我假设一个复杂的答案。

一个非常常见的编程问题是一个函数,它返回一些东西,或者失败了前提条件检查。在Java中,我会使用一些在方法开始处抛出 IllegalArgumentException 的assert函数,如下所示:

  {
//方法体
Assert.isNotNull(foo);
Assert.hasText(bar)
return magic(foo,bar);
}

我喜欢的是它是每个前提条件的一个oneliner。我不喜欢这件事是因为抛出异常(因为异常〜goto)。

在Scala中,我与Either合作过,后者有点笨重,但比抛出异常要好。



有人向我建议:

  putStone stone originalBoard = case attemptedSuicide 
True - > Nothing
False - >只需boardAfterMove
其中{
attemptedSuicide = undefined
boardAfterMove = undefined
}

我不喜欢的是把重点放在真和假上,这本身毫无意义; attemptedSuicide 前提条件隐藏在语法之间,所以与Nothing无关以及 putStone 的实际实现没有明确关联(boardAfterMove )并不是明确的核心逻辑。引导它不会编译,但我相信这不会破坏我的问题的有效性。



前提条件检查的方式是什么可以在Haskell中干净地完成吗?

解决方案

您有两个选择:


  1. 在您的类型中对您的前提条件进行编码,以便在编译时对其进行检查。

  2. 在运行时检查您的前提条件是否成立让你的程序在做一些令人讨厌和意外的事情之前停下来。 Gabriel Gonzales详细地显示了这一点他的回答

选项1.当然是首选,但并非总是可行。例如,你不能在Haskell的类型系统中说一个参数比另一个参数大,等等。但是你仍然可以表达很多,通常远远超过其他语言。还有一些语言使用所谓的依赖类型,并允许您在其中表达任何条件类型系统。但他们大多是实验或研究工作。如果您有兴趣,我建议您阅读Adam Chlipala的依赖类型的认证编程一书。

执行运行时检查更容易,这是程序员更习惯的。在Scala中,您可以在方法中使用 require ,并从相应的异常中恢复。在Haskell中这很棘手。异常(由失败的模式守卫引起,或通过调用错误未定义发出)的性质是 IO ,因此只有 IO 代码可以捕获它们。



如果你怀疑你的代码可能由于某些原因失败,最好使用 Maybe 或者来向调用者发送失败信号。缺点是这样会使代码更加复杂和不易读。

一种解决方案是将您的计算嵌入错误处理/报告monad中,如 MonadError 。然后,您可以干净地报告错误并将它们捕捉到更高级别的某处。如果你已经在使用monad进行计算,你可以将你的monad包装成 EitherT 转换器。


This is a simple question with a complex answer I presume.

A very common programming problem is a function that returns something, or fails precondition checks. In Java I would use some assert function that throws IllegalArgumentException at the beginning of the method like so:

{
  //method body
  Assert.isNotNull(foo);
  Assert.hasText(bar)
  return magic(foo, bar);
}

What I like about this is that it is a oneliner for each precondition. What I don't like about this is that an exception is thrown (because exception ~ goto).

In Scala I've worked with Either, which was a bit clunky, but better than throwing exceptions.

Someone suggested to me:

putStone stone originalBoard = case attemptedSuicide of 
  True  -> Nothing
  False -> Just boardAfterMove
  where {
    attemptedSuicide = undefined
    boardAfterMove = undefined
  }

What I don't like is that the emphasis is put on the True and the False, which mean nothing by themselves; the attemptedSuicide precondition is hiding in between syntax, so not clearly related to the Nothing AND the actual implementation of putStone (boardAfterMove) is not clearly the core logic. To boot it doesn't compile, but I'm sure that that doesn't undermine the validity of my question.

What is are the ways precondition checking can be done cleanly in Haskell?

解决方案

You have two options:

  1. Encode your preconditions in your types so that they're checked at compile-time.
  2. At run-time check that your preconditions hold so that your programs stops before doing something nasty and unexpected. Gabriel Gonzales shows this in detail his answer

Option 1. is of course preferred, but it's not always possible. For example, you can't say in Haskell's type systems that one argument is greater than other one, etc. But still you can express a lot, usually much more than in other languages. There are also languages that use so called dependent types and which allow you to express any condition in their type system. But they're mostly experimental or research work. If you're interested, I suggest you to read book Certified Programming with Dependent Types by Adam Chlipala.

Doing run-time checks is easier and it's what programmers are more used to. In Scala you can use require in your methods and recover from the corresponding exception. In Haskell this is trickier. Exceptions (caused by failing pattern guards, or issued by calling error or undefined) are by their nature IO based, so only IO code can catch them.

If you suspect that your code can fail for some reasons, it's better to use Maybe or Either to signal failures to the caller. The drawback is that this will make the code more complex and less readable.

One solution is to embed your computations into an error handling/reporting monad, such as MonadError. Then you can report errors cleanly and catch them somewhere at a higher level. And if you're already using a monad for your computations, you can just wrap your monad into EitherT transformer.

这篇关于Haskell中的前提条件检查有哪些选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆