简体   繁体   English

如何使用没有案例的警卫重写这个Haskell?

[英]How can I rewrite this Haskell using guards with no case-of?

I have three versions of a function laid out below. 我有三个版本的功能,如下所示。 #2 and #3 work. #2和#3工作。 #2 would be my first choice right now. #2现在是我的第一选择。 I'd like to find some way of making #1 work, and see how it compares. 我想找到一些让#1工作的方法,看看它是如何比较的。 It's down at the bottom. 它在底部。

First, I have this type: 首先,我有这种类型:

data Value =
    IntVal Int
  | BoolVal Bool
  deriving (Show)

And this (working fragment of a) function: 而这个(工作片段)功能:

-- #2
evaluate (If ec et ef) s0 =
  case vc of
    (IntVal ____) -> error "Conditional expression in If statement must be a boolean" 
    (BoolVal vcb) -> if vcb then (vt, st)
                            else (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

I'm wondering if I can get rid of the case statement and use guards instead. 我想知道我是否可以摆脱案件陈述并使用警卫代替。 I can use guards inside the case statement, I've found this works: 我可以使用case语句后卫,我发现这工作:

-- #3
evaluate (If ec et ef) s0 =
  case vc of
    (IntVal _) -> error "Conditional expression in If statement must be a boolean" 
    (BoolVal vcb) | vcb       -> (vt, st)
                  | otherwise -> (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

That's good to know. 很高兴知道。 I think #2 most clearly communicates my intentions. 我认为#2最清楚地传达了我的意图。 Nonetheless, here's the first thing I tried, and I'd like to figure out how it could actually work: 尽管如此,这是我尝试的第一件事,我想弄清楚它是如何实际工作的:

-- #1
evaluate (If ec et ef) s0 
  | (IntVal vc) = error "Conditional expression in If statement must be a boolean" 
  | vc == True  = (vt, st)
  | otherwise   = (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

Which gives the following errors. 这给出了以下错误。 It seems like I need something that will ask if something of the Value type is also of the IntVal subtype?: 似乎我需要一些东西来询问Value类型的某些东西是否也是IntVal子类型的东西?:

Couldn't match expected type `Int' with actual type `Value'
In the first argument of `IntVal', namely `vc'
In the expression: (IntVal vc)

--------------------------------------------------------------------------------

Couldn't match expected type `Bool' with actual type `Value'
In the expression: (IntVal vc)
In a stmt of a pattern guard for
               an equation for `evaluate':
  (IntVal vc)

How can I fix these errors and have a no-cases, guards-only implementation? 如何解决这些错误并实现无案例,仅限警卫的实施?

This isn't really an answer, but I'd write the whole thing something like this: 这不是一个真正的答案,但我会写下这样的事情:

evaluate (If ec et ef) s0 =
    case evaluate ec s0 of
    (True,  sc) -> evaluate et sc
    (False, sc) -> evaluate ef sc

I find the naming of vt , st , vf , and sf to be harder to read because I have to trace the data flow of those variables myself. 我发现vtstvfsf的命名更难以阅读,因为我必须自己跟踪这些变量的数据流。 Keeping them unnamed simplifies understanding. 保持他们的匿名简化了理解。

The problem with your #1 is that ordinary guards can only be Boolean expressions, which have no power to succinctly match patterns. 你的#1的问题在于,普通的守卫只能是布尔表达式,它们无法简洁地匹配模式。 So IntVal vc just won't work as one. 所以IntVal vc就不会像一个人一样工作。 And even if it did, the vc you get from an IntVal vc pattern cannot be used as a Bool value - you need the BoolVal vc pattern for that. 而且即使这样做了, vc你从得到IntVal vc模式不能被用作一个Bool值-你需要的BoolVal vc该模式。

However, you can use pattern guards : 但是,您可以使用图案保护

evaluate (If ec et ef) s0
  | IntVal _      <- vc = error "Conditional expression in If statement must be a boolean" 
  | BoolVal True  <- vc = (vt, st)
  | BoolVal False <- vc = (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

If you redefine the type Value using record syntax : 如果使用记录语法重新定义类型Value

data Value = IntVal { unInt :: Int } | BoolVal { unBool :: Bool }

Then you can do: 然后你可以这样做:

evaluate (If ec et ef) s0 =
  if unBool vc then (vt, st) else (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM