Haskell 中是否可以定义纯虚数类型?

Qua*_*Wiz 1 haskell types

我将在这里使用 C++ 作为示例来展示我所追求的内容。对于复数算术,它具有复数类型和虚数类型:

https://en.cppreference.com/w/c/language/arithmetic_types#Imaginary_floating_types

这些例如具有这样的属性:将两个数字与双虚数类型相乘将具有双精度类型。这与使用实部为 0.0 的复数几乎但不完全相同,但又不完全相同。虚数类型不会显式存储实部,这会自动消除不需要的计算和 0.0 的存储。

此外,它还可以防止带符号零的一些问题。例如,如果 a 和 b 为负,则 (0.0+i*a)*(0.0+i*b) 计算结果为 (-a*bi*0.0),否则为 (-a*b+i*0.0)。如果将结果输入到具有分支切割的函数中,这可能会令人惊讶。虚数类型避免了这种不必要的零否定。

我的问题是你能在 Haskell 中定义一个类似的虚数类型(除了复杂类型之外)以及操作(+), (-), (*), 和(/)for 它,这样它们的行为就像在 C++ 中一样?看来至少在NumFractional类的当前定义中这是不可能的,因为(+), (-), (*), 和(/)具有a -> a -> a类型签名,因此例如两个虚数相乘不能得到不同的类型。然而,是否可以对这些类有不同的定义,以便我所追求的目标成为可能?

我问这个并不是为了实际目的。我只是想更好地了解 Haskell 类型系统的功能。

Dan*_*ner 6

是的,你当然可以定义这样的类型。您只是无法使用该Num界面来执行所有操作;但是您可以自由地使用其他类型定义任何您想要的其他函数,甚至可以根据需要使它们中缀运算符。

下面是一个类型的示例,该类型在类型级别跟踪它是虚数还是实数,并支持使用替代名称进行加法和乘法(减法和除法不需要此处未显示的任何新想法):

{-# Language DataKinds #-}
{-# Language KindSignatures #-}
{-# Language TypeFamilies #-}

-- hide the Mindful data constructor
module Mindful (Mindful, real, iTimes, (+.), (*.), EqBool, KnownReality(isReal)) where

newtype Mindful (reality :: Bool) a = Mindful a deriving (Eq, Ord, Read, Show)

real :: a -> Mindful True a
real = Mindful

iTimes :: a -> Mindful False a
iTimes = Mindful

(+.) :: Num a => Mindful r a -> Mindful r a -> Mindful r a
Mindful x +. Mindful y = Mindful (x + y)

(*.) :: (KnownReality r, KnownReality r', Num a)
     => Mindful r a -> Mindful r' a -> Mindful (EqBool r r') a
xm@(Mindful x) *. ym@(Mindful y) = Mindful (iSquared * x * y) where
    iSquared = if isReal xm || isReal ym then 1 else -1

type family EqBool a b where
    EqBool False False = True
    EqBool False True = False
    EqBool True False = False
    EqBool True True = True

class KnownReality r where isReal :: Mindful r a -> Bool
instance KnownReality False where isReal _ = False
instance KnownReality True where isReal _ = True
Run Code Online (Sandbox Code Playgroud)

如果出于某种原因你必须让名称完全相同+(我不推荐这样做,这将是一个很大的痛苦),你可以看看我关于控制命名空间的另一个答案