Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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_Lazy Evaluation - Fatal编程技术网

Haskell 最低严格(*)

Haskell 最低严格(*),haskell,lazy-evaluation,Haskell,Lazy Evaluation,是否可以在Haskell中用最不严格的语义实现(*)(首选标准化的Haskell,但扩展是可以的。使用编译器内部构件是欺骗)?例如,这样的定义应导致以下结果为真: 0 * ⊥ = 0 ⊥ * 0 = 0 只有: ⊥ * ⊥ = ⊥ 我可以构建满足上述其中一种情况的模式匹配,但不能同时满足这两种情况,因为零检查强制该值。是,但仅使用受约束的杂质 laziestMult :: Num a => a -> a -> a laziestMult a b = (a * b) `una

是否可以在Haskell中用最不严格的语义实现
(*)
(首选标准化的Haskell,但扩展是可以的。使用编译器内部构件是欺骗)?例如,这样的定义应导致以下结果为真:

0 * ⊥ = 0
⊥ * 0 = 0
只有:

⊥ * ⊥ = ⊥

我可以构建满足上述其中一种情况的模式匹配,但不能同时满足这两种情况,因为零检查强制该值。

是,但仅使用受约束的杂质

laziestMult :: Num a => a -> a -> a
laziestMult a b = (a * b) `unamb` (b * a)
这是科纳尔·埃利奥特(Conal Elliott)对
amb
的“纯”变体。在操作上,
amb
并行运行两个计算,返回哪个先到。从外延上讲,unab取两个值,其中一个值严格大于另一个值(在领域理论意义上),并返回较大的值Edit:这也是unab,而不是lub,因此除非一个是bottom,否则需要使它们相等。因此,您必须满足一个语义要求,即使它不能由类型系统强制执行。这主要体现为:

unamb a b = unsafePerformIO $ amb a b
在异常/资源管理/线程安全的情况下,要使这一切正常工作,需要做很多工作

如果
*
是可交换的,
laziestMult
是正确的。如果
*
在一个参数中不严格,则为“最不严格”


有关更多信息,请参见blog

Phillip JF的回答仅适用于平面域,但也有一些非平面的实例,例如lazy naturals。当你进入这个竞技场,事情变得相当微妙

data Nat = Zero | Succ Nat
    deriving (Show)

instance Num Nat where
    x + Zero = x
    x + Succ y = Succ (x + y)

    x * Zero = Zero
    x * Succ y = x + x * y

    fromInteger 0 = Zero
    fromInteger n = Succ (fromInteger (n-1))

    -- we won't need the other definitions
对于懒惰的自然人来说,最不严格的操作尤其重要,因为这是他们使用的领域;e、 我们使用它们来比较可能无限的列表的长度,如果它的操作不是最严格的,那么当有有用的信息被发现时,这将产生分歧

正如所料,
(+)
是不可交换的:

ghci> undefined + Succ undefined
Succ *** Exception: Prelude.undefined
ghci> Succ undefined + undefined
*** Exception: Prelude.undefined
因此,我们将应用标准技巧来实现这一点:

laxPlus :: Nat -> Nat -> Nat
laxPlus a b = (a + b) `unamb` (b + a)
一开始这似乎有效

 ghci> undefined `laxPlus` Succ undefined
 Succ *** Exception: Prelude.undefined
 ghci> Succ undefined `laxPlus` undefined
 Succ *** Exception: Prelude.undefined
但事实并非如此

 ghci> Succ (Succ undefined) `laxPlus` Succ undefined
 Succ (Succ *** Exception: Prelude.undefined
 ghci> Succ undefined `laxPlus` Succ (Succ undefined)
 Succ *** Exception: Prelude.undefined
这是因为
Nat
不是平面域,而
unab
仅适用于平面域。正因为这个原因,我认为 UNAMB低级原语,除了定义更高级的概念外,不应该使用它。使用
unab
将对改变域结构的重构非常敏感——同样的原因
seq
在语义上是丑陋的。我们需要推广
unab
,就像
seq
推广到
deeqSeq
一样:这在模块中完成。我们首先需要为
Nat
编写一个
HasLub
实例:

instance HasLub Nat where
    lub a b = unambs [
                  case a of
                      Zero -> Zero
                      Succ _ -> Succ (pa `lub` pb),
                  case b of
                      Zero -> Zero
                      Succ _ -> Succ (pa `lub` pb)
              ]
        where
        Succ pa = a
        Succ pb = b
假设这是正确的,但事实并非如此(这是我到目前为止的第三次尝试),我们现在可以编写
laxPlus'

laxPlus' :: Nat -> Nat -> Nat
laxPlus' a b = (a + b) `lub` (b + a)
它实际上是有效的:

ghci> Succ undefined `laxPlus'` Succ (Succ undefined)
Succ (Succ *** Exception: Prelude.undefined
ghci> Succ (Succ undefined) `laxPlus'` Succ undefined
Succ (Succ *** Exception: Prelude.undefined
因此,我们被迫推广可交换二元算子的最小严格模式为:

leastStrict :: (HasLub a) => (a -> a -> a) -> a -> a -> a
leastStrict f x y = f x y `lub` f y x
至少,它保证是可交换的。但是,唉,还有更多的问题:

ghci> Succ (Succ undefined) `laxPlus'` Succ (Succ undefined)
Succ (Succ *** Exception: BothBottom
我们期望至少为2的两个数之和至少为4,但这里我们得到一个至少为2的数。我想不出一种方法来修改
leastStrit
以获得我们想要的结果,至少在不引入新的类约束的情况下是这样。要解决此问题,我们需要深入研究递归定义,并在每一步同时对两个参数进行模式匹配:

laxPlus'' :: Nat -> Nat -> Nat
laxPlus'' a b = lubs [
    case a of
        Zero -> b
        Succ a' -> Succ (a' `laxPlus''` b),
    case b of
        Zero -> a
        Succ b' -> Succ (a `laxPlus''` b')
    ]
最后我们得到了一个尽可能多的信息,我相信:

ghci> Succ (Succ undefined) `laxPlus''` Succ (Succ undefined)
Succ (Succ (Succ (Succ *** Exception: BothBottom
如果我们将同样的模式应用于时代,我们会得到一些似乎也有效的东西:

laxMult :: Nat -> Nat -> Nat
laxMult a b = lubs [
    case a of
        Zero -> Zero
        Succ a' -> b `laxPlus''` (a' `laxMult` b),
    case b of
        Zero -> Zero
        Succ b' -> a `laxPlus''` (a `laxMult` b')
    ]

ghci> Succ (Succ undefined) `laxMult` Succ (Succ (Succ undefined))
Succ (Succ (Succ (Succ (Succ (Succ *** Exception: BothBottom
不用说,这里有一些重复的代码,开发模式以尽可能简洁地表达这些函数(从而减少出错的机会)将是一个有趣的练习。然而,我们还有另一个问题

asLeast :: Nat -> Nat
atLeast Zero = undefined
atLeast (Succ n) = Succ (atLeast n)

ghci> atLeast 7 `laxMult` atLeast 7
Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ ^CInterrupted.
它慢得可怕。很明显,这是因为它(至少)参数的大小是指数级的,在每个递归上下降为两个分支。它需要更微妙的技巧才能在合理的时间内运行


最不严格的编程是一个相对未开发的领域,在实现和实际应用中都有必要进行更多的研究。我对它感到兴奋,并认为它是有前途的领土。你的意思是在实践中(通过勺子等不安全的东西)还是理论上,这是不安全的还是在实践中只使用H2010?你可能会在有限的情况下这样做,比如底部值是从调用<代码>错误< /代码>引起的。然而,能够识别任何底部值就等于解决了停止问题。如果第一个参数是非终止计算,会发生什么情况?@sabauma如果绝对必须检查与0的相等性,那么这可能是真的,这将解释为什么这可能不可能发生。@singpolyma即使你没有与0进行比较,第一种模式必须确保第二个参数在返回零之前确实处于底部。这更多是因为您在底部进行模式匹配。@sabauma显然无法在底部进行模式匹配:)您对
unab
的定义几乎正确,但您忘记了一个重要的前提条件:如果两个参数都不匹配⊥, 那么它们必须完全相等。这个包也有这个功能,所以你可以只写
parComb(*)
。我认为
Nat
应该只指归纳自然:或者是平面域
Nat=Z | S!Nat
或真正的离散集
Nat
不应该包含像
x=sx
这样的值,因为没有自然数具有这种形式。相反,我们应该把“懒惰的自然”称为其他的东西,也许是“超自然的数字”?@PhilipJF,你是否也反对把
[]
称为“列表”。但是没有Nat那么多,因为“list”是这样一个“cs”字,而natura