- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试回答 this stackoverflow question, using uniplate
as I suggested ,但 the only solution I've come up with so far 非常难看。
这似乎是一个相当普遍的问题,所以我想知道是否有更优雅的解决方案。
基本上,我们有一个 GADT,它可以解析为 Expression Int
或 Expression Bool
(忽略 codataIf = If (B True) codataIf codataIf
):
data Expression a where
I :: Int -> Expression Int
B :: Bool -> Expression Bool
Add :: Expression Int -> Expression Int -> Expression Int
Mul :: Expression Int -> Expression Int -> Expression Int
Eq :: Expression Int -> Expression Int -> Expression Bool
And :: Expression Bool -> Expression Bool -> Expression Bool
Or :: Expression Bool -> Expression Bool -> Expression Bool
If :: Expression Bool -> Expression a -> Expression a -> Expression a
step :: Expression a -> Expression a
step = \case
Add (I x) (I y) -> I $ x + y
Mul (I x) (I y) -> I $ x * y
Eq (I x) (I y) -> B $ x == y
And (B x) (B y) -> B $ x && y
Or (B x) (B y) -> B $ x || y
If (B b) x y -> if b then x else y
z -> z
DataDeriving
派生
Uniplate
和
Biplate
实例时遇到了一些困难(这可能应该是一个危险信号),所以
Uniplate
、
Expression Int
和
Expression Bool
实例为
Biplate
、
(Expression a) (Expression a)
和
(Expression Int) (Expression Bool)
滚动了我自己的
(Expression Bool) (Expression Int)
实例。
evalInt :: Expression Int -> Expression Int
evalInt = transform step
evalIntBi :: Expression Bool -> Expression Bool
evalIntBi = transformBi (step :: Expression Int -> Expression Int)
evalBool :: Expression Bool -> Expression Bool
evalBool = transform step
evalBoolBi :: Expression Int -> Expression Int
evalBoolBi = transformBi (step :: Expression Bool -> Expression Bool)
Int
叶子或
Bool
叶子,但两者都不能),它们不能进行完全简化,而必须手动链接在一起:
λ example1
If (Eq (I 0) (Add (I 0) (I 0))) (I 1) (I 2)
λ evalInt it
If (Eq (I 0) (I 0)) (I 1) (I 2)
λ evalBoolBi it
If (B True) (I 1) (I 2)
λ evalInt it
I 1
λ example2
If (Eq (I 0) (Add (I 0) (I 0))) (B True) (B False)
λ evalIntBi it
If (Eq (I 0) (I 0)) (B True) (B False)
λ evalBool it
B True
Uniplate
定义一个
Either (Expression Int) (Expression Bool)
实例:
type WExp = Either (Expression Int) (Expression Bool)
instance Uniplate WExp where
uniplate = \case
Left (Add x y) -> plate (i2 Left Add) |* Left x |* Left y
Left (Mul x y) -> plate (i2 Left Mul) |* Left x |* Left y
Left (If b x y) -> plate (bi2 Left If) |* Right b |* Left x |* Left y
Right (Eq x y) -> plate (i2 Right Eq) |* Left x |* Left y
Right (And x y) -> plate (b2 Right And) |* Right x |* Right y
Right (Or x y) -> plate (b2 Right Or) |* Right x |* Right y
Right (If b x y) -> plate (b3 Right If) |* Right b |* Right x |* Right y
e -> plate e
where i2 side op (Left x) (Left y) = side (op x y)
i2 _ _ _ _ = error "type mismatch"
b2 side op (Right x) (Right y) = side (op x y)
b2 _ _ _ _ = error "type mismatch"
bi2 side op (Right x) (Left y) (Left z) = side (op x y z)
bi2 _ _ _ _ _ = error "type mismatch"
b3 side op (Right x) (Right y) (Right z) = side (op x y z)
b3 _ _ _ _ _ = error "type mismatch"
evalWExp :: WExp -> WExp
evalWExp = transform (either (Left . step) (Right . step))
λ evalWExp . Left $ example1
Left (I 1)
λ evalWExp . Right $ example2
Right (B True)
error
和包装/展开,这让我觉得这不雅和错误。
uniplate
解决这个问题
的正确方法?
最佳答案
单板没有解决这个问题的正确方法,但是有一个正确的方法可以用相同的机制解决这个问题。 uniplate 库不支持对类型为 * -> *
的数据类型进行单板化。 ,但我们可以创建另一个类来适应它。这是一个用于种类类型的最小单板库* -> *
.它基于当前 git 版本的 Uniplate
已更改为使用 Applicative
而不是 Str
.
{-# LANGUAGE RankNTypes #-}
import Control.Applicative
import Control.Monad.Identity
class Uniplate1 f where
uniplate1 :: Applicative m => f a -> (forall b. f b -> m (f b)) -> m (f a)
descend1 :: (forall b. f b -> f b) -> f a -> f a
descend1 f x = runIdentity $ descendM1 (pure . f) x
descendM1 :: Applicative m => (forall b. f b -> m (f b)) -> f a -> m (f a)
descendM1 = flip uniplate1
transform1 :: Uniplate1 f => (forall b. f b -> f b) -> f a -> f a
transform1 f = f . descend1 (transform1 f)
Uniplate1
Expression
的实例:
instance Uniplate1 Expression where
uniplate1 e p = case e of
Add x y -> liftA2 Add (p x) (p y)
Mul x y -> liftA2 Mul (p x) (p y)
Eq x y -> liftA2 Eq (p x) (p y)
And x y -> liftA2 And (p x) (p y)
Or x y -> liftA2 Or (p x) (p y)
If b x y -> pure If <*> p b <*> p x <*> p y
e -> pure e
emap
非常相似。我在
my answer to the original question 中写的函数,除了此实例将每个项目放入
Applicative
Functor
.
descend1
简单地将它的论点提升为
Identity
和
runIdentity
的结果,使
desend1
等同于
emap
.因此
transform1
等同于
postmap
从上一个答案。
reduce
根据
transform1
.
reduce = transform1 step
"reduce"
If (And (B True) (Or (B False) (B True))) (Add (I 1) (Mul (I 2) (I 3))) (I 0)
I 7
关于haskell - 使用 Uniplate 简化 GADT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25355570/
这三者之间有什么/为什么有区别? GADT(和常规数据类型)只是数据系列的简写吗?具体有什么区别: data GADT a where MkGADT :: Int -> GADT Int dat
我们能否将构造函数没有给定约束的 GADT 转换为具有上述约束的 GADT?我想这样做是因为我想要深度嵌入箭头,并使用(目前)似乎需要 Typeable 的表示来做一些有趣的事情。 (One reas
我试图将 mod-n 计数器表示为将间隔 [0, ..., n-1] 分成两部分: data Counter : ℕ → Set where cut : (i j : ℕ) → Counter (
这是一个示例代码: {-# LANGUAGE GADTs #-} data NumGadt a where NumGadt :: Num a => a -> Int -> String -> Bo
我为表达式创建了一个 GADT。当我对具有约束的构造函数进行模式匹配时,类型检查器无法推断构造函数约束中使用的类型变量的约束。我认为代码和错误消息更清楚。 {-# LANGUAGE GADTs, Mu
背景 我正在使用 Haskell 编写一个红黑树实现 依赖类型并且我在理解为什么下面的代码不起作用时遇到了一些麻烦。作为一种热身练习,我想做的是找到一个给定任意值的子树。不幸的是,我在编译代码并最终继
在他的论文 Generics for the Masses Hinze 回顾了数据类型的编码。 从 Nat 开始 data Nat :: ⋆ where Zero :: Nat Succ
当我尝试创建一个返回 Thing a 的函数时,我目前正与类型检查器发生冲突。 (其中 Thing 是 GADT)。一个最小的人为例子: {-#LANGUAGE GADTs, EmptyDataDec
考虑以下代码 data Foo f where Foo :: Foo Int class DynFoo t where dynFoo :: Foo f -> Foo t instance Dy
假设我正在编写一个 DSL,并希望同时支持幻像类型和错误类型的表达式。我的值(value)类型可能是 {-# LANGUAGE GADTs, DataKinds #-} data Ty = Num |
当answering a question with a suggestion to use GADTs ,评论中出现了一些关于性能的问题。问题涉及类型类 PlotValue : class Plot
我只是在阅读Dependent Types at Work .在参数化类型的介绍中,作者提到在这个声明中 data List (A : Set) : Set where [] : List A
考虑以下代码: data (:+:) f g a = Inl (f a) | Inr (g a) data A data B data Foo l where Foo :: Foo A data
是分机GADT在 Haskell 中破坏多态性,即使在不使用 GADT 的代码中? 这是一个有效但不使用 GADT 的示例 {-# LANGUAGE RankNTypes #-} --{-# LANG
这两个 GADT 声明之间有区别吗? data A a b where ... data A :: * -> * -> * where ... 最佳答案 没有区别。有人可能会认为,在构
我在 haskell 中建立了一个几何库。我不打算发布它,它只是我用来提高我的语言知识的一个项目。 我有一个 Local数据类型,定义如下 data Local a where MkLocal
我正在阅读 GADTs for dummies Haskell Wiki 上的页面,我仍然不明白如何以及为什么应该使用它们。作者举了一个励志的例子: data T a where D1 ::
我正在解析表单的一些语句 v1 = expression1 v2 = expression2 ... 我正在使用 State Monad 并且我的状态应该是一对 (String, Expr a),我真
如何使用广义代数数据类型? haskell wikibook 中给出的示例太短了,无法让我深入了解 GADT 的真正可能性。 最佳答案 我发现“Prompt”monad(来自“MonadPrompt”
我正在使用 learnyouahaskell 来介绍 GADT,并且我对它们可能的用途很感兴趣。据我了解,它们的主要特点是允许显式类型设置。 如: data Users a where GetUs
我是一名优秀的程序员,十分优秀!