是否有可约束类型的语言?

Iva*_*nin 25 haskell agda dependent-type

是否有类型化的编程语言,我可以约束类型,如下面的两个例子?

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

    type Probability subtype of float
    where
        max_value = 0.0
        min_value = 1.0
    
    Run Code Online (Sandbox Code Playgroud)
  2. 离散概率分布是一个映射,其中:键应该都是相同的类型,值都是概率,值的总和= 1.0.

    type DPD<K> subtype of map<K, Probability>
    where
        sum(values) = 1.0
    
    Run Code Online (Sandbox Code Playgroud)

据我所知,Haskell或Agda无法做到这一点.

npo*_*cop 31

你想要的是称为细化类型.

可以Probability在Agda中定义:Prob.agda

具有和条件的概率质量函数类型在线264处定义.

有些语言具有比Agda更直接的细化类型,例如ATS


Tik*_*vis 26

您可以在Haskell中使用Liquid Haskell执行此操作,该Haskell使用细化类型扩展Haskell .谓词是在编译时的SMT求解器管理,这意味着证明是完全自动的,但你可以使用逻辑由SMT求解器处理什么限制.(令人高兴的是,现代SMT求解器具有相当的通用性!)

一个问题是我不认为Liquid Haskell目前支持浮点数.如果不是这样,虽然,它应该是可能的纠正,因为浮点数SMT求解器理论.您还可以假装浮点数实际上是合理的(甚至可以Rational在Haskell中使用!).考虑到这一点,您的第一个类型可能如下所示:

{p : Float | p >= 0 && p <= 1}
Run Code Online (Sandbox Code Playgroud)

你的第二种类型编码会有点困难,特别是因为地图是一种难以推理的抽象类型.如果您使用了对列表而不是地图,您可以编写一个"度量",如下所示:

measure total :: [(a, Float)] -> Float
total []          = 0 
total ((_, p):ps) = p + probDist ps
Run Code Online (Sandbox Code Playgroud)

(您可能需要换[]一个newtype了.)

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

{dist: [(a, Float)] | total dist == 1}
Run Code Online (Sandbox Code Playgroud)

Liquid Haskell的巧妙之处在于,所有的推理都是在编译时自动完成的,以换取使用有限约束的逻辑.(类似total的测量也非常局限于它们的编写方式 - 它是Haskell的一小部分,其规则类似于"每个构造函数只有一个案例".)这意味着这种类型的细化类型功能不强,但比完全更容易使用 - 依赖类型,使它们更实用.


Ven*_*Ven 9

Perl6有一个"类型子集"的概念,可以添加任意条件来创建"子类型".

特别针对您的问题:

subset Probability of Real where 0 .. 1;
Run Code Online (Sandbox Code Playgroud)

role DPD[::T] {
  has Map[T, Probability] $.map
    where [+](.values) == 1; # calls `.values` on Map
}
Run Code Online (Sandbox Code Playgroud)

(注意:在当前实现中,"where"部分在运行时被检查,但是因为"真实类型"在编译时被检查(包括你的类),并且因为is purestd中有纯注释()(这主要是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")
Run Code Online (Sandbox Code Playgroud)

然后,您可以检查数字是否与智能匹配运算符匹配~~:

say 4 ~~ Even; # True
say 4 ~~ Odd; # False
say 5 ~~ Odd; # True
Run Code Online (Sandbox Code Playgroud)

并且,由于multi subs(或多种方式,真正的 - 多种方法或其他方法),我们可以基于以下方式进行调度:

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
Run Code Online (Sandbox Code Playgroud)

  • 阻止它们在编译时被检查的一件事是检查是不可判定的. (12认同)
  • 我有点畏缩的一点是"没有什么能阻止它们在编译时被检查".运行时和任意约束的编译时检查之间的语义和实现难度的相对差异是一种天文数字. (11认同)
  • 实际上,Perl完全没有能力做那种预期的事情,其意图是从问题用[tag:haskell]和[tag:agda]标记的事实推断出来的. (6认同)
  • @Ven:要检查这样的类型,编译器必须证明,对于程序的每个可能的执行,任意谓词都成立.通常,即使使用纯函数,此*也是*不可判定的.你可以约束一组可能的谓词 - Perl没有 - 但它仍然非常难以做到,而不仅仅是时间问题.这是一个开放的研究问题!Liquid Types只管理这种检查,因为它们具有*非常*约束的类型级谓词,并使用最先进的SMT求解器来生成必要的证明.这不仅仅是时间问题. (4认同)
  • @Ven困难不仅仅是(只是)您的编译时检查可能涉及不纯函数,而是当它们嵌入任意计算时很难证明类型满意/等效.通过"困难",如果你的计算是*太一般的话,我会把它扩展到容易判定的.举一个简单的例子,你可能想尝试一些类型为"P(_)"的类型取决于'P(x*1)== P(1*x)`的东西.尽管`*'的纯度和对于任何具体选择的'x'这样做的微不足道......你会发现一般的陈述难以证明. (2认同)

MFl*_*mer 7

Nimrod是一种支持这一概念的新语言.它们被称为子范围.这是一个例子.您可以了解更多关于语言这里链接

type
  TSubrange = range[0..5]
Run Code Online (Sandbox Code Playgroud)

  • 此示例定义是否会产生静态检查或动态检查? (4认同)