typescript 和类型的标准名称,如Either but for 3 case?

5vf7fwbs  于 2022-12-14  发布在  TypeScript
关注(0)|答案(6)|浏览(101)

有没有一个标准的求和类型,比如Either but for 3?Haskell有These,但它不完全是这样的。

dm7nw8vv

dm7nw8vv1#

这些被称为联积,实际上Either只是一个2参数的联积。您可以使用shapeless库中的helper来构建任意长度的联积,方法如下:

type CP = Int :+: String :+: Boolean :+: CNil

val example = Coproduct[CP]("foo")

然后,您可以使用所有有趣的poly魔术来Map它们或执行其他操作:

object printer extends Poly1 {
  implicit def caseInt = at[Int](i => i -> s"$i is an int")
  implicit def caseString = at[String](s => s -> s"$s is a string")
  implicit def caseBoolean = at[Boolean](b => s -> s"$b is a bool")
}
val mapped = example map printer
mapped.select[(String, String)] shouldEqual "foo is a string"

据我所知,Scala.JS + Shapeless可以一起工作,所以这可能会给予你你想要的。

t5zmwmid

t5zmwmid2#

您使用的是哪种语言?如果是F#,则有一个三路Choice<'T1,'T2,'T3> type。(除了更“标准”的双向类型之外,还有4路、5路、6路和7路Choice类型)。

omjgkv6w

omjgkv6w4#

从另一个问题复制我的答案的后半部分:accept multiple types for a parameter in scala
经过一些修改后,这里有一个当我们必须接受多个类型时的解决方案:

def doSomething[C,T](obj: C): T = {
  obj match {
    case objA: ClassA => processA(objA.fieldA)
    case objB: ClassB => processB(objB.fieldB)
    case objC: ClassC => processC(objC.fieldC)
  }
}

doSomething[InputTypeA, ReturnTypeA](new ClassA(fieldA=InputTypeA("something")))

doSomething[InputTypeB, ReturnTypeB](new ClassB(fieldB=InputTypeB("somethingese")))

doSomething[InputTypeC, ReturnTypeC](new ClassC(fieldC=InputTypeC("another")))
kq4fsx7k

kq4fsx7k5#

我认为像这样严重依赖类型是一种反模式。
使用代数数据类型最好的一点是,结果类型可以告诉您所使用的域的一些信息。使用Choice<T1, T2, T3>这样的泛型类型,您实际上并没有说任何关于域的信息。
我想是option<T>(aka Maybe)非常清楚,因为它表示类型为T的值要么存在,要么由于某种原因丢失。我认为Either<'T, exn>仍然非常清楚,因为它表示您得到一个值或异常。但是,当您有两个以上的情况时,因此显式地定义一个具有与域匹配的名称的类型可能是一个好主意。
(我偶尔会在F#中使用Choice<T1, T2, T3>,但这种用法通常局限于一个小范围内--不到50行代码--这样我就可以很容易地找到使用它的代码周围的含义。)

bjp0bcyl

bjp0bcyl6#

在最近的 haskell ,我会打开一个厨房Flume位。

{-# LANGUAGE PolyKinds, DataKinds, GADTs, KindSignatures,
    TypeOperators, PatternSynonyms #-}

然后定义类型级列表成员资格

data (:>) :: [x] -> x -> * where
  Ze ::            (x ': xs) :> x
  Su :: xs :> x -> (y ': xs) :> x

现在我已经有了所有的有限和,而不需要写出一大堆OneOfN类型的定义:

data Sum :: [*] -> * where
  (:-) :: xs :> x -> x -> Sum xs

但是,为了解决Tomas关于可读性的问题,我会使用模式同义词。事实上,这类事情就是我多年来一直在谈论模式同义词的原因。
你可以有一个有趣的版本Maybe

type MAYBE x = Sum '[(), x]

pattern NOTHING :: MAYBE x
pattern NOTHING = Ze :- ()

pattern JUST :: x -> MAYBE x
pattern JUST x = Su Ze :- x

甚至可以使用newtype来构建递归求和。

newtype Tm x = Tm (Sum '[x, (Tm x, Tm x), Tm (Maybe x)])

pattern VAR :: x -> Tm x
pattern VAR x = Tm (Ze :- x)

pattern APP :: Tm x -> Tm x -> Tm x
pattern APP f s = Tm (Su Ze :- (f, s))

pattern LAM :: Tm (Maybe x) -> Tm x
pattern LAM b = Tm (Su (Su Ze) :- b)

newtype Package 器还允许您为以这种方式构建的类型进行instance声明。
当然,您也可以使用模式同义词来很好地隐藏迭代的Either
此技巧并不专用于求和:你也可以为产品做这个,这和de弗里斯和Löh的Generics-SOP库差不多。
这种编码的最大优势在于,数据的描述本身就是(类型级)数据,允许您在不修改编译器的情况下编写大量deriving风格的功能。
将来(如果我有办法的话),所有的数据类型都将是 defined,而不是 declared,数据类型描述由指定数据的代数结构(允许计算通用设备)及其外观的数据组成(这样您就可以在处理特定类型时看到您在做什么)。
但未来已经在这里了。

相关问题