haskell 了解"newtype"关键字

7xzttuei  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(142)

对于uni分配,我们已获得一行Haskell代码,其中显示:

newtype TC a = TC ([Id] -> Either TypeError ([Id], a))

首先,TypeError是需要我们实现的赋值语句,所以我不能在这里发布数据声明,但我的问题是,我如何阅读上面的代码?newtype TC后面的a是什么?我也不明白等号右边的TC是如何被重用的。
我认为这里的a是一个类型变量,因为newtype的工作方式与数据类似。我不知道知道知道这一点对我的理解有什么帮助。

7rtdyuoh

7rtdyuoh1#

newtype TC后面的a是什么?
新类型声明中的a

newtype TC a = ...

在函数声明中的表达与x非常相似

f x = ...

a是一个类型参数,所以你可以使用TC,例如TC IntTC Bool,类似于你可以使用f,例如f 1f "bla bla"(取决于它的类型)。
案例TC Int等效于以下备选项:

newtype TCInt = TCInt ([Id] -> Either TypeError ([Id], Int))

我也不明白TC是如何被重用到等号的右边的。
这在Haskell中有点令人困惑。实际上TC * 没有 * 被重用,而是声明了 * 两个单独的 * 实体,它们都被称为TC。你也可以用不同的方式来调用它们:

newtype TC_T a = TC_V ([Id] -> Either TypeError ([Id], a))
  • TC_T是一个 * 类型构造函数 *。这是将出现在类型签名中的内容,即TC_T IntTC_T Bool
  • TC_V是一个 * 值构造函数 *。当生成TC_T IntTC_T Bool类型的值时,可以使用它。

例如,您可以编写以下代码:

tci :: TC_T Int
tci = TC_V (\ids -> Right (ids, 37))

tcb :: TC_T Bool
tcb = TC_V (\ids -> Right (reverse ids, False))

使用原始版本时,其外观如下所示:

tci :: TC Int
tci = TC (\ids -> Right (ids, 37))

tcb :: TC Bool
tcb = TC (\ids -> Right (reverse ids, False))

...但它仍然是两个独立的东西,在这里都被称为TV。Haskell中的大多数newtypes调用类型和值构造函数是一样的,但通常只有类型构造函数从模块中导出,而值构造函数作为实现细节留下。
datanewtype的大部分内容是相同的。

data TC a = TC ([Id] -> Either TypeError ([Id], a))

...与newtype版本的唯一区别是一个微妙的间接:如果是data,那么编译器会插入一个间接值,它允许更多的惰性,但在这种情况下,这样做几乎没有意义。
在实践中,通常只有在需要 * 多个 * 构造函数和/或具有多个字段的构造函数时才使用data,而newtype不支持这些构造函数。

p8h8hvxi

p8h8hvxi2#

与 * data * 相比,* newtype * 的好处是可以通过其基础类型进行派生:

{-# Language DerivingVia              #-}
{-# Language StandaloneKindSignatures #-}

import Control.Applicative   (Alternative)
import Control.Monad         (MonadPlus)
import Control.Monad.Except  (ExceptT(..), Except)
import Control.Monad.Fix     (MonadFix)
import Control.Monad.State   (StateT(..), MonadState)
import Data.Functor.Identity (Identity(..))
import Data.Kind             (Type)

type    TC :: Type -> Type
newtype TC a = MkTC ([Id] -> Either TypeError (a, [Id]))
  deriving
    ( Functor, Applicative, Alterantive
    , Monad, MonadPlus, MonadState [Id], MonadFix
    )
  via StateT [Id] (Except TypeError)

-- Alternative and MonadPlus rely on these
instance Semigroup TypeError ..
instance Monoid    TypeError ..

我不得不交换元组,但由于有三个 * newtype *,所以这是可行的:TC aStateT s m aExceptT。编译器为每个 * newtype * 生成一个示例,证明它与基础类型具有相同的运行时表示。
这被称为 * 代表性相等 *,由Coercible证明。

-- instance Coercible (StateT s m a) (s -> m (a, s))
type    StateT :: Type -> (Type -> Type) -> (Type -> Type)
newtype StateT s m a = MkStateT (s -> m (a, s))

-- instance Coercible (ExceptT e m a) (m (Either e a))
type    ExceptT :: Type -> (Type -> Type) -> (Type -> Type)
newtype ExceptT e m a = MkExceptT (m (Either e a))

这使得TC a可以强制为StateT [Id] (Except TypeError) a,因此我们可以使用基于coerce的派生策略在它们之间携带示例(如GeneralizedNewtypeDerivingDerivingVia)。

TC a
={Coercible}
  [Id] -> Either TypeError (a, [Id])
={Coercible}
  [Id] -> ExceptT TypeError Identity (a, [Id])
={Except e = ExceptT e Identity} 
  [Id] -> Except TypeError (a, [Id])
={Coercible}
  StateT [Id] (Except TypeError) a

GeneralizedNewtypeDeriving仅适用于 * newtype *,但这并不意味着DerivingVia仅适用于 * newtype *。您可以为 * data * 派生许多示例,例如通过Applicative提升方法对TCAp TC a)进行提升。
将其变为 * newtype * 确实简化了事情,Applicative可以通过状态转换器派生,因此我们不需要手动编写任何示例。

data TC a = MkTC ..
  ..

  deriving (Semigroup, Monoid, Num, Bounded)
  via Ap TC a

TC名称在代码中有两个用途("双关语")。我将它们分成两个不同的名称,分别是TC和transformers。
左边是型别建构函式:

>> :k TC
TC :: Type -> Type
>> :k StateT
StateT :: Type -> (Type -> Type) -> (Type -> Type)
>> :k ExceptT
ExceptT :: Type -> (Type -> Type) -> (Type -> Type)

右边是值构造函数,我添加了一个Mk以消除歧义:

>> :t MkTC
MkTC :: ([Id] -> Either TypeError (a, [Id])) -> TC a
>> :t MkStateT
MkStateT :: (s -> m (a, s)) -> StateT s m a
>> :t MkExceptT
MkExceptT :: m (Either e a) -> ExceptT e m a

a :: Type是型别建构函式的参数:

TC   :: Type -> Type
TC a :: Type

如果没有类型参数,这些示例都不会进行类型检查,因为所有这些示例都需要一个"一元类型构造函数"(Type -> Type)作为参数。也就是说,由类型参数化的类型:

Functor         :: (Type -> Type) -> Constraint
Applicative     :: (Type -> Type) -> Constraint
Alternative     :: (Type -> Type) -> Constraint
Monad           :: (Type -> Type) -> Constraint
MonadPlus       :: (Type -> Type) -> Constraint
MonadState [Id] :: (Type -> Type) -> Constraint
MonadFix        :: (Type -> Type) -> Constraint

相关问题