Delphi中三重逻辑

时间:2013-10-23 08:16:37

标签: delphi logic delphi-2006

如何在Delphi中最好地实现three valued logic

我在考虑

type
  TExtBoolean = (ebTrue, ebFalse, ebUnknown);

function ExtOr(A: TExtBoolean; B: TExtBoolean): TExtBoolean;
begin
  if (A = ebTrue) or (B = ebTrue) then
    Result := ebTrue
  else if (A = ebFalse) and (B = ebFalse) then
    Result := ebFalse
  else
    Result := ebUnknown;
end;

等等。

但这似乎并不优雅。有更好的方法吗?

编辑:优雅我的意思是易于使用。实现越优雅越好。 CPU效率对我来说并不重要。

2 个答案:

答案 0 :(得分:13)

您可以通过运算符重载实现增强记录。它看起来像这样:

type
  TTriBool = record
  public
    type
      TTriBoolEnum = (tbFalse, tbTrue, tbUnknown);
  public
    Value: TTriBoolEnum;
  public
    class operator Implicit(const Value: Boolean): TTriBool;
    class operator Implicit(const Value: TTriBoolEnum): TTriBool;
    class operator Implicit(const Value: TTriBool): TTriBoolEnum;
    class operator Equal(const lhs, rhs: TTriBool): Boolean;
    class operator LogicalOr(const lhs, rhs: TTriBool): TTriBool;
    function ToString: string;
  end;

class operator TTriBool.Implicit(const Value: Boolean): TTriBool;
begin
  if Value then
    Result.Value := tbTrue
  else
    Result.Value := tbFalse;
end;

class operator TTriBool.Implicit(const Value: TTriBoolEnum): TTriBool;
begin
  Result.Value := Value;
end;

class operator TTriBool.Implicit(const Value: TTriBool): TTriBoolEnum;
begin
  Result := Value.Value;
end;

class operator TTriBool.Equal(const lhs, rhs: TTriBool): Boolean;
begin
  Result := lhs.Value=rhs.Value;
end;

class operator TTriBool.LogicalOr(const lhs, rhs: TTriBool): TTriBool;
begin
  if (lhs.Value=tbTrue) or (rhs.Value=tbTrue) then
    Result := tbTrue
  else if (lhs.Value=tbFalse) and (rhs.Value=tbFalse) then
    Result := tbFalse
  else
    Result := tbUnknown;
end;

function TTriBool.ToString: string;
begin
  case Value of
  tbFalse:
    Result := 'False';
  tbTrue:
    Result := 'True';
  tbUnknown:
    Result := 'Unknown';
  end;
end;

一些示例用法:

var
  x: Double;
  tb1, tb2: TTriBool;

tb1 := True;
tb2 := x>3.0;
Writeln((tb1 or tb2).ToString);

tb1 := False;
tb2.Value := tbUnknown;
Writeln((tb1 or tb2).ToString);

输出:

True
Unknown

答案 1 :(得分:5)

AS。你在这里的意思是什么意思?优雅的实施或优雅的使用或CPI效率或可维护性?优雅是一个非常含糊的词......

我认为使更容易使用的显而易见的方法是将类型转换为ExtBoolean1 or (ExtBoolean2 and True)之类的方式。

然而,所需的功能可能在Delphi 2006之前或之前很短(本身就是一个错误的版本),所以请带上你的DUnit并做很多测试..

列出要使用的功能及其说明:

  1. 增强记录:When should I use enhanced record types in Delphi instead of classes?http://delphi.about.com/od/adptips2006/qt/newdelphirecord.htm以及manual
  2. 操作重载,包括隐式类型转换:What operator do I overload when assigning an "Enhanced Record" to a normal "Data Type" variable?Operator Overloading in Delphi以及manual
  3. 内联函数:what is use of inline keyword in delphimanual
  4. 概述其中一些想法:

    type
      TExtBoolean = record
         Value: (ebUnknown, ebTrue, ebFalse);
    
         function IsNull: boolean; inline;
         function Defined: boolean; inline;
    
         class operator Implicit ( from: boolean ): TExtBoolean; inline;
         class operator Implicit ( from: TExtBoolean ): boolean; 
         class operator LogicalAnd( Value1, Value2: TExtBoolean ):   TExtBoolean; 
         class operator LogicalAnd( Value1: TExtBoolean; Value2: boolean):  TExtBoolean; inline;
         class operator LogicalAnd( Value1: boolean; Value2: TExtBoolean ):   TExtBoolean; 
    ....
      end;
    
    const Unknown: TExtBoolean = (Value: ebUnknown); 
    
    ...
    var v1: TExtBoolean;
        v1 := False; 
        v1 := True;
        v1 := Unknown;
    ...
    
    class operator TExtBoolean.Implicit ( from: boolean ): TExtBoolean; 
    begin
      if from
         then Result.Value := ebTrue
         else Result.Value := ebFalse
    end;
    
    class operator TExtBoolean.Implicit ( from: TExtBoolean ): Boolean; 
    begin
      case from.Value of
        ebTrue: Result := True;
        ebFalse: Result := False;  
        else raise EConvertError.Create('....');
    end;
    
    
    function TExtBoolean.Defined: boolean; 
    begin
      Result := (Self.Value = ebTrue) or (Self.Value = ebFalse);
    end;
    
    // this implementation detects values other than ebTrue/ebFalse/ebUnkonwn
    // that might appear in reality due to non-initialized memory garbage 
    // since hardware type of Value is byte and may be equal to 3, 4, ...255
    function TExtBoolean.IsNull: boolean; 
    begin
      Result := not Self.Defined
    end;
    
    class operator TExtBoolean.And( Value1, Value2: TExtBoolean ): TExtBoolean; 
    begin
      if Value1.IsNull or Value2.IsNull
         then Result.Value := eb.Undefined
         else Result := boolean(Value1) and boolean(Value2);
    // Or, sacrificing readability and safety for the sake of speed
    // and removing duplicate IsNull checks
    //   else Result := (Value1.Value = ebTrue) and (Value2.Value = ebTrue);
    end;
    
    class operator TExtBoolean.LogicalAnd( Value1, TExtBoolean; Value2: boolean):  TExtBoolean;
    begin
      Result := Value2 and Value1;
    end;
    
    class operator TExtBoolean.LogicalAnd( Value1: boolean; Value2: TExtBoolean ):   TExtBoolean; 
    begin
      if Value2.IsNull
         then Result := Value2
         else Result := Value1 and (Value2.Value = ebTrue);
    // or if to accept a duplicate redundant check for readability sake
    //   and to avert potential later erros (refactoring, you may accidentally remove the check above)
    //    else Result := Value1 and boolean (Value2);
    end;
    

    PS。上面没有说明的检查是故意的悲观,倾向于错误的一面。它是对未初始化变量和未来可能变化的防御,增加了超过三个的状态。 虽然这看起来似乎过度保护,但至少Delphi XE2同意mee:在类似情况下看警告:

    program Project20;  {$APPTYPE CONSOLE}
    uses System.SysUtils;
    
    type enum = (e1, e2, e3);
    var e: enum;
    
    function name( e: enum ): char;
    begin
      case e of
        e1: Result := 'A';
        e2: Result := 'B';
        e3: Result := 'C';
      end;
    end;
    
    // [DCC Warning] Project20.dpr: W1035 Return value of function 'name' might be undefined
    
    begin
      for e := e1 to e3
          do Writeln(name(e));
      ReadLn;
    end.