Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 是否存在具有可约束类型的语言?_Haskell_Agda_Dependent Type - Fatal编程技术网

Haskell 是否存在具有可约束类型的语言?

Haskell 是否存在具有可约束类型的语言?,haskell,agda,dependent-type,Haskell,Agda,Dependent Type,有没有一种类型化编程语言可以像下面两个例子那样约束类型 概率是一个浮点数,最小值为0.0,最大值为1.0 type Probability subtype of float where max_value = 0.0 min_value = 1.0 离散概率分布是一个映射,其中:键应该都是相同的类型,值都是概率,值之和=1.0 type DPD<K> subtype of map<K, Probability> where sum(values

有没有一种类型化编程语言可以像下面两个例子那样约束类型

  • 概率是一个浮点数,最小值为0.0,最大值为1.0

    type Probability subtype of float
    where
        max_value = 0.0
        min_value = 1.0
    
  • 离散概率分布是一个映射,其中:键应该都是相同的类型,值都是概率,值之和=1.0

    type DPD<K> subtype of map<K, Probability>
    where
        sum(values) = 1.0
    
    类型DPD映射的子类型
    哪里
    总和(值)=1.0
    
  • 据我所知,这在Haskell或Agda是不可能的。

    你想要的就是所谓的

    可以在Agda中定义
    概率

    第264行定义了具有求和条件的概率质量函数类型


    与Agda相比,有些语言具有更直接的细化类型,例如,Nimrod是一种支持此概念的新语言。它们被称为子范围。这里有一个例子。你可以在这里学习更多关于这门语言的知识


    您可以在Haskell中执行此操作,并使用它扩展Haskell。谓词在编译时由SMT解算器管理,这意味着证明是完全自动的,但您可以使用的逻辑受到SMT解算器处理内容的限制。(令人高兴的是,现代SMT解决方案相当通用!)

    一个问题是,我认为Liquid Haskell目前不支持浮动。如果没有,应该可以纠正,因为SMT解算器有浮点数理论。您还可以假装浮点数实际上是有理数(或者甚至在Haskell中使用
    rational
    )。考虑到这一点,您的第一种类型可以如下所示:

    {p : Float | p >= 0 && p <= 1}
    
    measure total :: [(a, Float)] -> Float
    total []          = 0 
    total ((_, p):ps) = p + probDist ps
    
    (您可能还需要将
    []
    包装在
    新类型中。)

    现在,您可以在细化中使用
    total
    来约束列表:

    {dist: [(a, Float)] | total dist == 1}
    
    Liquid Haskell的巧妙之处在于,所有的推理都是在编译时自动进行的,作为使用某种受限逻辑的回报。(像
    total
    这样的度量在如何编写它们方面也非常有限,这是Haskell的一个小子集,有“每个构造函数正好一个案例”这样的规则)。这意味着这种风格的精化类型的功能不如依赖类型的精化类型强大,但更易于使用,这使得它们更实用。

    Perl6有一个“类型子集”,可添加任意条件以创建“子类型”

    对于你的具体问题:

    subset Probability of Real where 0 .. 1;
    

    (注意:在当前的实现中,“where”部分是在运行时检查的,但由于“real type”是在编译时检查的(包括您的类),并且std中有纯注释(
    是纯的
    )(主要是perl6)(这些注释也在像
    *
    等操作符上),这只是一个努力的问题(不应该更多)

    更一般地说:

    # (%% is the "divisible by", which we can negate, becoming "!%%")
    subset Even of Int where * %% 2; # * creates a closure around its expression
    subset Odd of Int where -> $n { $n !%% 2 } # using a real "closure" ("pointy block")
    
    然后,您可以检查数字是否与智能匹配运算符匹配
    ~

    say 4 ~~ Even; # True
    say 4 ~~ Odd; # False
    say 5 ~~ Odd; # True
    
    而且,多亏了
    multi-sub
    s(或者多个,实际上是多个方法或其他),我们可以基于此进行调度:

    multi say-parity(Odd $n) { say "Number $n is odd" }
    multi say-parity(Even) { say "This number is even" } # we don't name the argument, we just put its type
    #Also, the last semicolon in a block is optional
    

    对于第一部分,是的,那将是Pascal,它有整数子范围。

    Modula 3有子范围类型。(序数的子范围。)因此对于示例1,如果您愿意将概率映射到某个精度的整数范围,您可以使用以下方法:

    TYPE PROBABILITY = [0..100]
    
    根据需要添加有效数字

    参考:关于子范围序数的更多信息。

    支持与您所说非常类似的内容。例如:

    type natural is (int x) where x >= 0
    type probability is (real x) where 0.0 <= x && x <= 1.0
    

    该语言非常有表现力。这些不变量和前置/后置条件使用SMT解算器进行静态验证。这可以很好地处理上述示例,但目前难以处理涉及数组和循环不变量的更复杂示例。

    对于任何感兴趣的人,我想我可以添加一个示例,说明如何解决此问题n截至2019年

    问题的第一部分是直截了当的,因为在问这个问题的时间间隔内,Nim已经能够在浮点上生成子范围类型(以及序数和枚举类型)。下面的代码定义了两个新的浮点子范围类型,
    Probability
    ProbOne

    问题的第二部分更为棘手——定义一个类型,并对其字段的函数进行约束。我提出的解决方案没有直接定义这种类型,而是使用宏(
    makePmf
    )来绑定常量
    表[t,Probability]的创建
    object以创建有效的
    ProbOne
    对象(从而确保PMF有效)。编译时对
    makePmf
    宏进行评估,确保您不能创建无效的PMF表

    请注意,我是Nim的新手,因此这可能不是编写此宏的最惯用方法:

    import macros, tables
    
    type
      Probability = range[0.0 .. 1.0]
      ProbOne = range[1.0..1.0]
    
    macro makePmf(name: untyped, tbl: untyped): untyped =
      ## Construct a Table[T, Probability] ensuring
      ## Sum(Probabilities) == 1.0
    
      # helper templates
      template asTable(tc: untyped): untyped =
        tc.toTable
    
      template asProb(f: float): untyped =
        Probability(f)
    
      # ensure that passed value is already is already
      # a table constructor
      tbl.expectKind nnkTableConstr
      var
        totprob: Probability = 0.0
        fval: float
        newtbl = newTree(nnkTableConstr)
    
      # create Table[T, Probability]
      for child in tbl:
        child.expectKind nnkExprColonExpr
        child[1].expectKind nnkFloatLit
        fval = floatVal(child[1])
        totprob += Probability(fval)
        newtbl.add(newColonExpr(child[0], getAst(asProb(fval))))
    
      # this serves as the check that probs sum to 1.0
      discard ProbOne(totprob)
      result = newStmtList(newConstStmt(name, getAst(asTable(newtbl))))
    
    
    makePmf(uniformpmf, {"A": 0.25, "B": 0.25, "C": 0.25, "D": 0.25})
    
    # this static block will show that the macro was evaluated at compile time
    static:
      echo uniformpmf
    
    # the following invalid PMF won't compile
    # makePmf(invalidpmf, {"A": 0.25, "B": 0.25, "C": 0.25, "D": 0.15})
    
    

    注意:使用宏的一个很酷的好处是
    nimssuggest
    (集成到VS代码中)甚至会突出显示创建无效Pmf表的尝试。

    我相信ADA有类似的功能(子类型约束)。例如,您正在寻找依赖类型的语言-类型可以依赖于值。一些示例包括Idris、Agda和Coq。SQL确实做到了这一点(请参见)嗨,我在LiquidHaskell上工作(在下面的回答中描述),如果能看到您正在使用的程序/应用程序,我将非常好奇(并且非常感激!)(特别是要保留这些约束的代码。)谢谢!Shen()具有此功能。例如,请参见。我在Agda或Coq中所做的与此问题所要求的不同之处在于,细化类型是新类型,而不是现有类型的子类型。例如,
    DPD
    将是包含映射和一些证明的新类型,而不是恰好满足某些附带条件的映射。@П谢谢---回答已被接受!我原以为Agda能做到。不幸的是,我发现即使是最简单的Agda也无法穿透(我只是在托儿所的slo上)
    type natural is (int x) where x >= 0
    type probability is (real x) where 0.0 <= x && x <= 1.0
    
    function abs(int x) => (int r)
    ensures r >= 0:
        //
        if x >= 0:
            return x
        else:
            return -x
    
    import macros, tables
    
    type
      Probability = range[0.0 .. 1.0]
      ProbOne = range[1.0..1.0]
    
    macro makePmf(name: untyped, tbl: untyped): untyped =
      ## Construct a Table[T, Probability] ensuring
      ## Sum(Probabilities) == 1.0
    
      # helper templates
      template asTable(tc: untyped): untyped =
        tc.toTable
    
      template asProb(f: float): untyped =
        Probability(f)
    
      # ensure that passed value is already is already
      # a table constructor
      tbl.expectKind nnkTableConstr
      var
        totprob: Probability = 0.0
        fval: float
        newtbl = newTree(nnkTableConstr)
    
      # create Table[T, Probability]
      for child in tbl:
        child.expectKind nnkExprColonExpr
        child[1].expectKind nnkFloatLit
        fval = floatVal(child[1])
        totprob += Probability(fval)
        newtbl.add(newColonExpr(child[0], getAst(asProb(fval))))
    
      # this serves as the check that probs sum to 1.0
      discard ProbOne(totprob)
      result = newStmtList(newConstStmt(name, getAst(asTable(newtbl))))
    
    
    makePmf(uniformpmf, {"A": 0.25, "B": 0.25, "C": 0.25, "D": 0.25})
    
    # this static block will show that the macro was evaluated at compile time
    static:
      echo uniformpmf
    
    # the following invalid PMF won't compile
    # makePmf(invalidpmf, {"A": 0.25, "B": 0.25, "C": 0.25, "D": 0.15})