haskell - “点菜数据类型” - 注入正确的问题
问题描述
我正在查看本文中指定的代码:http: //www.staff.science.uu.nl/~swier004/publications/2008-jfp.pdf,数据类型点菜。
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
data Expr f = In (f (Expr f))
data Val e = Val Int
data Add e = Add e e
data Mul x = Mul x x
type IntExpr = Expr Val
type AddExpr = Expr Add
data ( f:+:g ) e = Inl (f e)| Inr (g e)
class (Functor sub, Functor sup) => sub :<: sup where
inj :: sub a -> sup a
instance Functor sym => sym :<: sym where
inj = id
instance {-# OVERLAPPING #-} (Functor f, Functor g) => (f :<: (f :+: g)) where
inj = Inl
instance {-# OVERLAPPING #-} (Functor f, Functor g, Functor h, f :<: g) => (f :<: (h :+: g)) where
inj l = Inr (inj l)
addExample::Expr ( Val :+: Add )
addExample= In(
Inr(
Add
(In (Inl (Val 118) ) )
(In (Inl (Val 1219) ) )
)
)
instance Functor Val where
fmap f (Val x)=Val x
instance Functor Add where
fmap f (Add e1 e2) = Add (f e1) (f e2)
instance Functor Mul where
fmap f (Mul e1 e2) = Mul (f e1) (f e2)
instance (Functor f, Functor g) => Functor (f :+: g) where
fmap f (Inl e1) = Inl (fmap f e1)
fmap f (Inr e2) = Inr (fmap f e2)
foldExpr::Functor f => (f a -> a) -> Expr f -> a
foldExpr f (In t) = f (fmap (foldExpr f) t)
class Functor f => Eval f where
evalAlgebra ::f Int -> Int
instance Eval Val where
evalAlgebra (Val x) = x
instance Eval Add where
evalAlgebra (Add e1 e2) = e1 + e2
instance Eval Mul where
evalAlgebra (Mul e1 e2) = e1 * e2
instance (Eval f, Eval g) => Eval (f :+: g) where
evalAlgebra (Inl x) = evalAlgebra x
evalAlgebra (Inr y) = evalAlgebra y
eval::Eval f => Expr f -> Int
eval expr = foldExpr evalAlgebra expr
inject::(g :<: f) => g (Expr f) -> Expr f
inject = In . inj
val::(Val :<: f) => Int -> Expr f
val x = inject (Val x)
infixl 6 ⊕
(⊕):: (Add :<: f) => Expr f -> Expr f -> Expr f
x ⊕ y = inject (Add x y)
infixl 7 ⊗
(⊗):: (Mul :<: f) => Expr f -> Expr f -> Expr f
x ⊗ y = inject (Mul x y)
xxx :: Int -> Expr (Val :+: (Mul :+: Add) )
xxx x = val 100 ⊗ val 5
我很难把头绕在右边的注射处。两个问题:
为什么不这样声明:
instance {-# OVERLAPPING #-} => (f :<: (g :+: f)) where ...
类似于左边的注入。第二个问题,
inj = Inr . inj
调用本身是递归的吗?
解决方案
为什么不这样声明:
instance {-# OVERLAPPING #-} => (f :<: (g :+: f))
where ... 类似于左边的注入。
原始代码使用的方式使实例头比另一个更具体。也就是说:f :<: (f :+: g)
比 更具体f :<: (h :+: g)
,因为第一个仅匹配后者的(严格)案例子集。
这让编译器很高兴:可以尝试第一个实例。如果匹配,那就太好了。如果它不匹配,并且不统一,我们可以提交第二个更一般的实例。(如果它不匹配但统一,那么我们就被卡住了,我们不能提交到任何一个实例。)
以自己的方式进行操作会增加约束求解卡住的可能性,因为在求解F :<: (F :+: F)
两个实例时都适用。在原始代码中,将应用第一个,因为它更具体。
第二个问题,
inj = Inr . inj
调用本身是递归的吗?
不,最后一个inj
是由实例定义的 for f :<: g
,所以它是一个不同的函数。这经常发生,例如
-- pseudocode
instance Show a => Show (Maybe a) where
show Nothing = "Nothing"
show (Just x) = "Just " ++ show x
最后一行调用该Show a
方法,并且不递归。
推荐阅读
- html - 上传jar文件并将其转换为html中的哈希值
- r - R:如何在 rmarkdown 中最好地可视化“是/否/不确定”
- swift - 无法以编程方式在 Swift 的 Stackview 中正确排列两个 UILabel
- javascript - 如何检查是否通过 java Script 打开浏览器搜索(使用 Ctrl+F)选项?
- javascript - Momentjs解析通配符
- javascript - 带有 Jquery 插件的 Ionic 3
- android - 如何在Android的firebase UI中将方向设置为纵向
- java - 从 Map 创建 tar 并将其转换为 bytearray 而不保存
- apache-kafka - kafka 经纪人,生产者和消费者相关
- bash - “字符串匹配”和“模式匹配”的区别