写一个没有 case 的空 case 的函数
Write a function with an empty case without case
我可以用一个空的 case 写一些不可能的东西,例如用 Decision
来使用它。
{-# LANGUAGE DataKinds, EmptyCase, LambdaCase, TypeOperators #-}
import Data.Type.Equality
import Data.Void
data X = X1 | X2
f :: X1 :~: X2 -> Void
f = \case {}
-- or
-- f x = case x of {}
有没有一种不使用 case
通过直接对参数进行模式匹配来编写等价物的方法?
f :: X1 :~: X2 -> Void
f ???
好吧,你可以使用可怕的 CPP hack:
{-# LANGUAGE CPP #-}
#define Absurd = \case {}
f :: X1 :~: X2 -> Void
f Absurd -- expands to "f = case {}"
但是,如果您正在寻找使用纯 Haskell 语法的解决方案,我很确定答案是否定的。与空案例不同,您不能在没有至少一种模式的情况下使用模式语法定义 f
。而且,没有 GHC 将模式理解为无人居住类型术语的密码。 (即使有,也没有语法允许您定义没有 right-hand 边的 f pat
。)
这是使用模式同义词的尝试。它并不完全令人满意,可能不是您真正想要的。它只能通过将 \case{}
移离您的眼睛来实现。我们在某些点上仍然需要使用absurd
。
{-# LANGUAGE PatternSynonyms, ViewPatterns, GADTs #-}
{-# LANGUAGE DataKinds, EmptyCase, LambdaCase, TypeOperators #-}
import Data.Type.Equality
import Data.Void
data X = X1 | X2
pattern Abs :: Void -> a
pattern Abs x <- (\case{} -> x)
f :: 'X1 :~: 'X2 -> Void
f (Abs x) = x
g :: 'X1 :~: 'X2 -> a
g (Abs x) = absurd x
{-
Pattern match(es) are non-exhaustive
In an equation for `h':
Patterns of type 'X1 :~: 'X1 not matched: Refl
-}
h :: 'X1 :~: 'X1 -> Void
h (Abs x) = x
另一种方法是利用模板 Haskell。
我想如果你想模仿这个,最简单的方法类似于评论中发布的答案:
f _ = undefined
然而,这是懒惰的:
f (error "aw beans") -- undefined
而空case是严格的:
(\ case {} :: X1 :~: X2 -> Void) (error "aw beans") -- beans
所以更好的替代方法是 seq
:
impossible :: a -> Void
impossible x = x `seq` impossible x
或BangPatterns
:
{-# Language BangPatterns #-}
impossible :: a -> Void
impossible !x = impossible x
那你就写f = impossible
吧,我觉得挺好的。 (a
上的量词在逻辑上更像是“for any”而不是“for all”,但是哦,好吧。)你当然可以抛出一些稍微更具描述性的东西,而不是进入无限循环,以防情况不妙实际上不可能—error "the impossible was possible after all"
.
这也适用于 void
包中 Void
的 old-fashioned 定义为 data Void = Void !Void
或 newtype Void = Void Void
。
我可以用一个空的 case 写一些不可能的东西,例如用 Decision
来使用它。
{-# LANGUAGE DataKinds, EmptyCase, LambdaCase, TypeOperators #-}
import Data.Type.Equality
import Data.Void
data X = X1 | X2
f :: X1 :~: X2 -> Void
f = \case {}
-- or
-- f x = case x of {}
有没有一种不使用 case
通过直接对参数进行模式匹配来编写等价物的方法?
f :: X1 :~: X2 -> Void
f ???
好吧,你可以使用可怕的 CPP hack:
{-# LANGUAGE CPP #-}
#define Absurd = \case {}
f :: X1 :~: X2 -> Void
f Absurd -- expands to "f = case {}"
但是,如果您正在寻找使用纯 Haskell 语法的解决方案,我很确定答案是否定的。与空案例不同,您不能在没有至少一种模式的情况下使用模式语法定义 f
。而且,没有 GHC 将模式理解为无人居住类型术语的密码。 (即使有,也没有语法允许您定义没有 right-hand 边的 f pat
。)
这是使用模式同义词的尝试。它并不完全令人满意,可能不是您真正想要的。它只能通过将 \case{}
移离您的眼睛来实现。我们在某些点上仍然需要使用absurd
。
{-# LANGUAGE PatternSynonyms, ViewPatterns, GADTs #-}
{-# LANGUAGE DataKinds, EmptyCase, LambdaCase, TypeOperators #-}
import Data.Type.Equality
import Data.Void
data X = X1 | X2
pattern Abs :: Void -> a
pattern Abs x <- (\case{} -> x)
f :: 'X1 :~: 'X2 -> Void
f (Abs x) = x
g :: 'X1 :~: 'X2 -> a
g (Abs x) = absurd x
{-
Pattern match(es) are non-exhaustive
In an equation for `h':
Patterns of type 'X1 :~: 'X1 not matched: Refl
-}
h :: 'X1 :~: 'X1 -> Void
h (Abs x) = x
另一种方法是利用模板 Haskell。
我想如果你想模仿这个,最简单的方法类似于评论中发布的答案:
f _ = undefined
然而,这是懒惰的:
f (error "aw beans") -- undefined
而空case是严格的:
(\ case {} :: X1 :~: X2 -> Void) (error "aw beans") -- beans
所以更好的替代方法是 seq
:
impossible :: a -> Void
impossible x = x `seq` impossible x
或BangPatterns
:
{-# Language BangPatterns #-}
impossible :: a -> Void
impossible !x = impossible x
那你就写f = impossible
吧,我觉得挺好的。 (a
上的量词在逻辑上更像是“for any”而不是“for all”,但是哦,好吧。)你当然可以抛出一些稍微更具描述性的东西,而不是进入无限循环,以防情况不妙实际上不可能—error "the impossible was possible after all"
.
这也适用于 void
包中 Void
的 old-fashioned 定义为 data Void = Void !Void
或 newtype Void = Void Void
。