Haskell编译智能构造函数的时间检查 [英] Haskell compile time checking of smart constructors

查看:86
本文介绍了Haskell编译智能构造函数的时间检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习Haskell,并通过以下讲座进行学习: http://www.cis.upenn.edu/~cis194/spring13/

I'm learning Haskell, running through the lectures: http://www.cis.upenn.edu/~cis194/spring13/

我有:

module HanoiDisk(HanoiDisk, hanoiDisk) where
import Control.Exception
data HanoiDisk = HanoiDisk' Integer deriving (Show)
hanoiDisk :: Integer -> HanoiDisk 
hanoiDisk n = assert (n >= 1) $ HanoiDisk' n

这有效,但是如果我有:

This works, but if i have:

main = do 
  print(show (hanoiDisk (-3))

我只会在运行时出现错误,而不会在编译时出现.

I only get an error during run-time and not at compile-time.

我非常想了解如何完全消除运行时异常.

I'm pretty keen to understand how to eliminate run-time exceptions entirely.

任何人都可以提供替代方法吗?

Can anyone provide an alternative approach?

谢谢

推荐答案

据我了解,当有人将函数hanoiDisk应用于小于1的参数时,您想要一种很好地失败"的方法.

From what I understand, you want a way to "fail nicely" when someone applies the function hanoiDisk to an argument that's less than 1.

正如评论者所述,在编译时执行此操作超出了基本Haskell的范围,因此您在日常代码中不需要它!

As a commenter stated, doing that at compile time is outside the scope of basic Haskell and you shouldn't need it in your day-to-day code!

通过使用Either a b数据类型,您绝对可以很好地失败".

You can definitely "fail nicely" by using the Either a b datatype.

这个想法是,如果您有一个函数hanoiDisk :: Integer -> HanoiDisk,该函数需要一个Integer,并且如果输入为"good",则应该返回一个HanoiDisk值,而当输入为不好",则可以使用备用构造函数对其进行编码.

The idea is that if you have a function hanoiDisk :: Integer -> HanoiDisk that takes an Integer and is supposed to return a HanoiDisk value if the input is "good" and an error value of some sort when the input is "bad", you can encode that using alternate constructors.

Either a b数据类型的构造函数是Left aRight b,其中 错误输出的格式为Left a,良好的输出格式为Right b.让我们用这个来重写您的函数.

The constructors for the Either a b datatype are Left a and Right b where an error output would be of the form Left a and a good output would be of the form Right b. Let's rewrite your function using this.

hanoiDisk :: Integer -> Either String HanoiDisk 
hanoiDisk n = if n >= 1 
              then Right (HanoiDisk' n)
              else Left "a hanoi disk must be least 1"

(可能)更合适的答案

让我们讨论一个简单的问题,即以编译器可接受的方式构造必须为非负数(而不是正数)的数字.

(Probably) More Appropriate Answer

Let's discuss the simpler problem of constructing numbers that must be nonnegative (as opposed to positive) in a way that's acceptable to the compiler.

我认为问题与编译器解析数字的方式有关.每当您在程序中使用符号"0","1","2","3","4",...,"9"来表示数字时,语言解析器都会期望最终结果符合类型,例如Int,Double等,因此当您使用这些符号时,您可能会发现某人可能在数字序列前加一个'-'并将您的非负数变成负数一个.

I think the problem is tied to the way numbers are parsed by the compiler. Any time you use the symbols '0', '1', '2', '3', '4', ..., '9' to represent digits in your program the language parser expects the end result to conform to a type like Int, Double, etc. and so when you use these symbols you open yourself up to the possibility that someone might prepend a '-' to the sequence of digits and turn your nonnegative number into a negative one.

让我们制作一个名为 Natural 的新模块,它将使我们能够创建正数.在其中,我们使用每个符号名称的前两个字母(例如,tw表示"2")为符号"0",...,"1"定义别名".由于人类使用十进制来编写自然数,因此我们创建了一个称为Natural的数据类型,该数据类型带有两个参数-我们要代表的数字的第一个数字,然后是一个后续数字的列表.最后,我们有选择地从模块中导出功能,以禁止用户滥用".

Let's make a new module called Natural which will allow us to create positive numbers. In it, we define "aliases" for the symbols '0',...,'1' using the first two letters of each symbol's name (eg. tw for '2'). Since humans write natural numbers using the decimal system, we create a data type called Natural that takes two arguments - the first digit of the number we're representing and then a list of subsequent digits. Finally, we selectively export functions from the module to prohibit "misuse" by users.

module Natural (ze,on,tw,th,fo,fi,si,se,ei,ni,Natural(..)) where

newtype Digit = Digit Int

ze = Digit 0
on = Digit 1
tw = Digit 2
th = Digit 3
fo = Digit 4
fi = Digit 5
si = Digit 6
se = Digit 7
ei = Digit 8
ni = Digit 9

data Natural = Nat Digit [Digit]

例如,自然数312将表示为Nat th [on,tw].

As an example, the natural number 312 would be represented as Nat th [on,tw].

任何导入 Natural 的模块都只能访问我们导出的函数,因此尝试使用其他任何东西来定义类型为Natural的值都将导致编译错误.此外,由于我们没有导出Digit构造函数,因此导入程序无法为Digit类型定义自己的值.

Any module importing Natural would only have access to the functions that we export, so attempts to use anything else to define a value of type Natural would result in compile errors. Furthermore, since we didn't export the Digit constructor there's no way for importers to define their own values for the Digit type.

我遗漏了NumIntegralEqOrd等实例的定义,因为我认为它们不会增加我的解释.

I'm leaving out definitions of the instances for Num, Integral, Eq, Ord, etc. because I don't think they would add more to my explanation.

这篇关于Haskell编译智能构造函数的时间检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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