對于 uni 賦值,我們得到了一行 Haskell 代碼,其中顯示:
newtype TC a = TC ([Id] -> Either TypeError ([Id], a))
首先,TypeError我們需要為作業實作一些東西,所以我不能在這里發布資料宣告,但我的問題是這樣的。我如何閱讀上面的代碼?后面的a右邊是newtype TC什么?我也不明白TC等號右邊是如何被重用的。
我認為a這是一個型別變數,因為newtype它與資料類似。我不知道知道這一點對我的理解有何幫助。
uj5u.com熱心網友回復:
后面的
a右邊是newtype TC什么?
newtypea宣告中的
newtype TC a = ...
表達與x函式宣告中的the 非常相似
f x = ...
a是一個型別引數。因此,您將能夠使用TCas,例如,TC Intor TC Bool,類似于您能夠使用flike f 1or的方式f "bla bla"(取決于其型別)。
該案例TC Int等同于以下替代方案:
newtype TCInt = TCInt ([Id] -> Either TypeError ([Id], Int))
我也不明白
TC等號右邊是如何被重用的。
在 Haskell 中,這是一個令人困惑的怪癖。Actually沒有TC被重用,而是你宣告了兩個獨立的物體,它們都被稱為. 你也可以用不同的方式稱呼它們:TC
newtype TC_T a = TC_V ([Id] -> Either TypeError ([Id], a))
TC_T是一個型別建構式。這是將出現在型別簽名中的東西,即TC_T IntorTC_T Bool。TC_V是一個值建構式。TC_T Int當生成or型別的值時,您可以使用它TC_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 中的大多數新型別呼叫相同的型別和值建構式,但通常只有型別建構式從模塊中匯出,而值建構式作為實作細節保留。
其中大部分與 fordata相同newtype。你也可以
data TC a = TC ([Id] -> Either TypeError ([Id], a))
...與 newtype 版本的唯一區別是一個微妙的間接尋址:如果它是data,那么編譯器會插入一個允許更多惰性的間接尋址,但在這種情況下,這樣做幾乎沒有意義。
在實踐中,您通常data只在需要多個建構式和/或具有多個欄位的建構式時才使用,這newtype是不支持的。
uj5u.com熱心網友回復:
newtype優于data的好處是你可以通過它的基礎型別派生:
{-# 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 ..
我不得不交換元組,但這是因為三個新型別:TC a,StateT s m a和ExceptT。編譯器為每個新型別生成一個實體,證明它具有與基礎型別相同的運行時表示。
這被稱為代表性平等,并由 見證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基于 - 的派生策略在它們之間攜帶實體(如GeneralizedNewtypeDeriving或DerivingVia)。
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
使它成為新型別確實簡化了事情,Applicative可以通過狀態轉換器派生,因此我們不需要手動撰寫任何實體。
data TC a = MkTC ..
..
deriving (Semigroup, Monoid, Num, Bounded)
via Ap TC a
該TC名稱在您的代碼中有兩個用途(“雙關語”)。我將它們分成兩個不同TC的名稱,for 和 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
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/536676.html
標籤:哈斯克尔新型
