评估嵌套数据类型

时间:2019-04-23 22:54:45

标签: haskell

我正在尝试编写一个函数,用于评估嵌套的布尔数据类型。我的问题来自比较数据类型内的数据类型。前两个(Lit和Or)可以很好地编译,但是我不明白如何将第一个类型合并到SecondExpr的函数中。当我输入内容时,我觉得当一些较短的方法可行时,我正在采取最长的方法。

这是两种数据类型。

data Expr = Val Int
          | Add Expr Expr
          | Sub Expr Expr
          | Mul Expr Expr
          | Div Expr Expr
          | If SecondExpr Expr Expr

data SecondExpr = Lit Bool
                | Or SecondExpr SecondExpr 
                | EqualTo Expr Expr
                | LessThan Expr Expr

(我遇到的另一个问题是创建SecondExpr的示例进行测试,因为从概念上讲,我将每个Expr视为6种不同类型的Expr。这意味着,对于每个Expr Expr,都会有数百个防护。)

下面是到目前为止的代码:

eval :: SecondExpr -> Bool
eval (Lit n)                   = n
eval (Or e1 e2)
  | True && True               = True
  | True && False              = True
  | False && True              = True
  | otherwise                  = False
eval (EqualTo e1 e2)
  | (Add e1 e2) == (Add e1 e2) = True
  | (Sub e1 e2) == (Sub e1 e2) = True
  | (Mul e1 e2) == (Mul e1 e2) = True
  | (Div e1 e2) == (Div e1 e2) = True
  | otherwise                  = False
eval (LessThan e1 e2)
  | (Add e1 e2) == (Add e1 e2) = True
  | (Sub e1 e2) == (Sub e1 e2) = True
  | (Mul e1 e2) == (Mul e1 e2) = True
  | (Div e1 e2) == (Div e1 e2) = True
  | otherwise                  = False

这是我得到的错误:

    * No instance for (Eq Expr) arising from a use of `=='
    * In the expression: (Add e1 e2) == (Add e1 e2)
      In a stmt of a pattern guard for
                     an equation for `eval':
        (Add e1 e2) == (Add e1 e2)
      In an equation for `eval':
          eval (EqualTo e1 e2)
            | (Add e1 e2) == (Add e1 e2) = True
            | (Sub e1 e2) == (Sub e1 e2) = True
            | (Mul e1 e2) == (Mul e1 e2) = True
            | (Div e1 e2) == (Div e1 e2) = True
            | otherwise = False
   |
24 |   | (Add e1 e2)       == (Add e1 e2) = True
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

所以我知道我的语法是错误的,但是如何在表达式的功能内替换表达式?

1 个答案:

答案 0 :(得分:5)

您将需要两个评估功能:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "jaxmetalmax/debian8-rubydev"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"
  config.vm.synced_folder "C:/EGodoy/Sites", "/home/vagrant/sites"
  config.vm.network "private_network", ip: "192.168.33.10"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

evalNum :: Expr -> Int

他们都不应该使用任何防护装置(evalBool :: SecondExpr -> Bool )。

例如,| ...如下所示:

evalBool

使用相应的evalBool (Lit n) = n evalBool (Or e1 e2) = evalBool e1 || evalBool e2 evalBool (EqualTo e1 e2) = evalNum e1 == evalNum e2 evalBool (LessThan e1 e2) = evalNum e1 < evalNum e2 函数对子表达式进行递归求值,并使用适当的Haskell运算符(例如eval||==)对结果进行组合。

<的实施留给读者练习。