Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.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中邻接两个泛型Either_Haskell - Fatal编程技术网

在Haskell中邻接两个泛型Either

在Haskell中邻接两个泛型Either,haskell,Haskell,我正在寻找一种方法,将两个要么a b和要么c d连接在一起,并将要么a(要么b(要么c d))作为最终结果。但是如果b~或者或者/或者d~或者,它也应该能够递归地“平坦”两个eithers 我尝试用fundep定义类型类: 类与AB c | AB->c相邻,其中 邻接:a->b->c 但无法为该类提供任何有意义的实例。我觉得可以通过类型族来实现,但我还不够精通 本质上,我试图从Scala中复制shapeless,我写了另一个答案,但它是不正确的,因为它也没有递归地展平嵌套的。希望这个能起作用

我正在寻找一种方法,将两个
要么a b
要么c d
连接在一起,并将
要么a(要么b(要么c d))
作为最终结果。但是如果
b~或者
或者/或者
d~或者
,它也应该能够递归地“平坦”两个eithers

我尝试用fundep定义类型类:

类与AB c | AB->c相邻,其中
邻接:a->b->c
但无法为该类提供任何有意义的实例。我觉得可以通过类型族来实现,但我还不够精通


本质上,我试图从Scala中复制shapeless,我写了另一个答案,但它是不正确的,因为它也没有递归地展平嵌套的
。希望这个能起作用

一些必要的扩展:

{-# LANGUAGE DataKinds, MultiParamTypeClasses, FunctionalDependencies, 
             UndecidableInstances, FlexibleInstances, ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}    -- To enable supplying types with @ 
{-# LANGUAGE AllowAmbiguousTypes #-} -- Not strictly necessary, just to avoid Proxy 
课程本身:

class Flatten input result | input -> result where
    flatten :: input -> result

-- Branch can be used as a kind thanks to DataKinds
data Branch = RebalanceNeeded
            | RebalanceNotNeeded
            | Atomic

type family WhichBranch t :: Branch where
     WhichBranch (Either (Either _ _) _) = RebalanceNeeded
     WhichBranch (Either _ _)            = RebalanceNotNeeded
     WhichBranch _                       = Atomic

class Flatten' (branch :: Branch) input result | branch input -> result where
    flatten' :: input -> result

-- We always delegate on the auxiliary class 
instance Flatten' (WhichBranch input) input result => Flatten input result where
    flatten = flatten' @(WhichBranch input)

-- The left branch is itself another either. We need to rebalance and keep flattening.
instance Flatten (Either x (Either y z)) r 
  => Flatten' RebalanceNeeded (Either (Either x y) z) r where
  flatten' e = case e of
      Left (Left x)  -> flatten @(Either x (Either y z)) (Left x)
      Left (Right y) -> flatten @(Either x (Either y z)) (Right (Left  y))
      Right z        -> flatten @(Either x (Either y z)) (Right (Right z))

-- The left branch is not itself an either. We only flatten the right branch.
instance (Flatten y y') => Flatten' RebalanceNotNeeded (Either x y) (Either x y') where
  flatten' e = case e of
      Left x  -> Left x
      Right y -> Right (flatten @y y)

instance Flatten' Atomic x x where
  flatten' = id
该解决方案利用
分支
类型族来检查最左边的类型。结果被输入到一个辅助类型类
flant'
,该类处理额外的信息。这是一种避免恼人的“重叠实例”错误的解决方法

另一种选择是简单地将
{-#OVERLAPPABLE#-}
{-#OVERLAPPING#-}
杂注放在实例上,在没有辅助类和类型族的情况下工作

使用示例:

ghci> :t flatten (undefined :: Either (Either Bool Float) (Either (Either Char Word) Int))
Either Bool (Either Float (Either Char (Either Word Int)))
编辑:代替多参数类型分类,编码这些单向转换的另一种方法是:

其优点是,现在我们可以显式要求计算结果类型:

ghci> :kind! (Flattened (Either (Either Bool Float) (Either (Either Char Word) Int)))
Either Bool (Either Float (Either Char (Either Word Int)))

你说的“平坦”是什么意思?说,我有
ab
cd
其中
b~或者ef
d~或者ghg
,最后它应该是
或者a(或者f(或者c(或者ghg))
而不是
或者a(或者ef))(或者c(或者ghh))
所以你想让它“正确递归”吗?不确定这里的语法术语是否适用,但是的,即使是“非递归”的情况对我来说也不直接。关于这两个参数,我们有4个案例:左/左、左/右、右/左、右/右。在这4种情况下,您希望输出是什么?相关:“避免与封闭类型族重叠实例”谢谢,这太棒了!另外,类型附近的
@
的含义是什么?@SergeyKolbasov这是一个类型应用程序,它不是严格需要的,另一种方法是通过添加带有普通类型注释的
数据.Proxy
参数来解决类型歧义。
ghci> :kind! (Flattened (Either (Either Bool Float) (Either (Either Char Word) Int)))
Either Bool (Either Float (Either Char (Either Word Int)))