是否可以具有递归和类型,而每个“级别”具有不同的值?

时间:2019-06-29 09:16:56

标签: haskell

我想知道是否有可能(我想是:))具有递归和类型,其中我们在每个级别上都有X类型的值,但是以某种方式限制了我们自己,在每个级别的递归上我们都有不同的值X?

例如,如果我有

data MachineType = Worker | Flyer | Digger | Observer | Attacker
data Machine = Single MachineType | Multi MachineType Machine

类型系统允许我构造以下类型的计算机:

Multi Worker (Multi Worker (Single Worker))

但我希望对此加以限制,以便只允许使用不同的MachineType。

有没有办法在类型系统中对此进行编码?

您可以为我指明正确的方向,因为我有点不了解google :)(类似于haskell集的递归和类型吗?)

2 个答案:

答案 0 :(得分:10)

一种解决方案是指定不能用重复的$result_array = mysqli_query($connect,"SELECT * FROM tbl_customer, categories WHERE tbl_customer.category_QA = categories.id ORDER BY Category ASC"); $checkCategory = ''; while($data = mysqli_fetch_array($result_array)){ if ($checkCategory != $data["Category"]){ echo $data["Category"]; //display once for every new category $checkCategory = $data["Category"]; } echo $data["productName"]; } 扩展Machine。为此,我们首先需要为MachineType使用singleton类型:

MachineType

然后,我们指定一个约束,如果在{-# language TypeInType, GADTs, TypeOperators, ConstraintKinds, UndecidableInstances, TypeFamilies #-} import Data.Kind import GHC.TypeLits data MachineType = Worker | Flyer | Digger | Observer | Attacker data SMachineType t where SWorker :: SMachineType Worker SFlyer :: SMachineType Flyer SDigger :: SMachineType Digger SObserver :: SMachineType Observer SAttacker :: SMachineType Attacker 列表中未包含某些内容,则抛出约束,否则抛出custom type error

MachineType

然后,将type family NotElem (x :: MachineType) (xs :: [MachineType]) :: Constraint where NotElem x '[] = () NotElem x (x ': xs) = TypeError (Text "Duplicate MachineTypes are not allowed in Machines" :$$: (Text "Can't add " :<>: ShowType x :<>: Text " to " :<>: ShowType (x ': xs))) NotElem x (y ': xs) = NotElem x xs 作为GADT给出,并以Machine的列表为索引:

MachineType

以下定义推断类型为data Machine (ts :: [MachineType]) where Single :: SMachineType t -> Machine '[ t ] Multi :: NotElem t ts => SMachineType t -> Machine ts -> Machine (t ': ts)

Machine '[ 'Flyer, 'Digger, 'Worker]

以下定义引发类型错误:

m1 = Multi SFlyer (Multi SDigger (Single SWorker))

错误消息为:

m2 = Multi SFlyer (Multi SFlyer (Single SWorker))

答案 1 :(得分:2)

看来我被殴打了!作为对安德拉斯的回答的补充,我想出了一个类似的版本,但是使用了每种机器类型的唯一性的价值水平证明。

这在实际用例中可能不太符合人体工程学,但是它确实具有一定的“证明相关数学”的魅力(或者,所以我自欺欺人!)

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TypeFamilies #-}

import Prelude

import Data.Kind (Type)
import Data.Void (Void)
import Data.Proxy (Proxy(..))

data MachineType
  = Worker
  | Flyer
  | Digger
  | Observer
  | Attacker
  deriving (Show, Eq)

data In xs x where
  Here :: forall k (xs :: [k]) (x :: k)
    . In (x ': xs) x
  There :: forall k (xs :: [k]) (x :: k) (y :: k)
    . In xs x -> In (y ': xs) x

type family Not a where
  Not a = (a -> Void)

data Machine :: [MachineType] -> Type where
  Single :: forall (t :: MachineType) (proxy :: MachineType -> Type)
    . proxy t -> Machine '[t]
  Multi :: forall (t :: MachineType) (ts :: [MachineType]) (proxy :: MachineType -> Type)
    . Not (In ts t) -> proxy t -> Machine ts -> Machine (t ': ts)

simpleMachine :: Machine '[ 'Worker ]
simpleMachine = Single Proxy

multiMachine :: Machine '[ 'Flyer, 'Attacker ]
multiMachine = Multi p (Proxy @'Flyer) $ Single (Proxy @'Attacker)
  where
    p :: Not (In '[ 'Attacker ] 'Flyer)
    p = \case
      There l -> case l of