繁体   English   中英

Haskell中的可见类型应用程序:如何绑定类型

[英]Visible type application in Haskell : how to bind the type

在可见类型应用程序中,可以指定我们“调用”多态值的类型。

这允许删除诸如Proxy :: Proxy s值,只是在我们成为用户时绑定类型s ,我们只需编写myPolyValue @ s

但是,如果我们要构建一个多态值,是否有一种方法可以绑定我们所调用的类型,以及Proxy s类型的参数呢?

示例我使用VisibleTypeApplication强制多态类型,但是除了通过Proxy s参数外,我不知道如何绑定绑定到的类型:

#!/usr/bin/env stack
-- stack --resolver nightly-2018-12-12 script --package base-unicode-symbols --package unicode-prelude --package constraints
{-# LANGUAGE AllowAmbiguousTypes,GeneralizedNewtypeDeriving  #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies, KindSignatures #-}
{-# LANGUAGE FlexibleContexts , TypeApplications #-}
{-# LANGUAGE InstanceSigs , FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses , ScopedTypeVariables #-}
{-# LANGUAGE GADTs , MultiParamTypeClasses     #-}
{-# LANGUAGE RankNTypes , TypeOperators             #-}
{-# LANGUAGE UnicodeSyntax,DataKinds              #-}

module ImplicitConfigurationFirstPart where

import Data.Proxy

data KNat where
  Zero :: KNat
  Twice :: KNat -> KNat
  Succ :: KNat -> KNat
  Pred :: KNat -> KNat

class ReflectNum (s :: KNat) where reflectNum ∷ Num a ⇒ Proxy s -> a
instance                ReflectNum  'Zero      where reflectNum _ = 0
instance ReflectNum s ⇒ ReflectNum ('Pred  s) where reflectNum _ = (reflectNum (Proxy @ s)) - 1
instance ReflectNum s ⇒ ReflectNum ('Succ  s) where reflectNum _ = (reflectNum (Proxy @ s)) + 1
instance ReflectNum s ⇒ ReflectNum ('Twice s) where reflectNum _ = (reflectNum (Proxy @ s)) * 2

reifyIntegral ∷ (Integral a) ⇒ a → (∀ (s :: KNat). ReflectNum s ⇒ Proxy s -> w) → w
reifyIntegral i k = case quotRem i 2 of
  (0,0)  → k $ Proxy @ 'Zero
  (j,0)  → reifyIntegral j (\(p :: Proxy s) -> let n = reflectNum p in
                                               k $ Proxy @ ('Twice s) )
  (j,1)  → reifyIntegral j (\(_ :: Proxy s) -> k $ Proxy @ ('Succ('Twice s)))
  (j,-1) → reifyIntegral j (\(_ :: Proxy s) -> k $ Proxy @ ('Pred('Twice s)))

Attempt1在此示例中, Zero索引处的第一种情况可以正常工作。

但是第二个不能证明'Twice sReflectNum一部分。 但是,应该像在其中应用k1的s那样,对ReflectNum进行验证,以便'Twice s对它进行验证,并且只要我们有ReflectNum s的证明,就可以调用k ,它是s中的多态。

{-# LANGUAGE AllowAmbiguousTypes,GeneralizedNewtypeDeriving  #-}
{-# LANGUAGE  TypeFamilies, KindSignatures, FlexibleContexts #-}
{-# LANGUAGE TypeApplications, FunctionalDependencies, MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables , GADTs, MultiParamTypeClasses, RankNTypes                #-}
{-# LANGUAGE TypeOperators, UnicodeSyntax, DataKinds              #-}
{-# LANGUAGE UndecidableSuperClasses    #-}
module ImplicitConfigurationFirstPart where

import Data.Proxy

data KNat where
  Zero :: KNat
  Twice :: KNat -> KNat

class ReflectNum (s :: KNat) where reflectNum ∷ Num a ⇒ Proxy s -> a
instance                ReflectNum  'Zero      where reflectNum _ = 0
instance ReflectNum s ⇒ ReflectNum ('Twice s)  where reflectNum _ = (reflectNum (Proxy @ s)) * 2

reifyIntegral2 ∷ forall a w. (Integral a) ⇒ a → (∀ (s :: KNat). ReflectNum s ⇒ w) → w
reifyIntegral2 i k = case quotRem i 2 of
  (0,0)  → k @ 'Zero
  (j,0)  → reifyIntegral2 j k1

  where k1 :: forall (s :: KNat). ReflectNum s ⇒ w
        k1 = k @ ('Twice s)

但是,如果我们要构建一个多态值,是否有一种方法可以绑定我们所调用的类型,以及Proxy s类型的参数呢?

如果我理解正确的话,这意味着要定义一个接受类型参数的多态绑定,该绑定旨在使用可见类型应用程序提供。 这个问题的答案是使用forall

如果您有一些使用Proxy s编写的函数f ,例如

f :: Proxy s -> X -> Y

那么您可以通过启用AllowAmbiguousTypesScopedTypeVariables并使用显式的forall来消除Proxy参数:

{-# LANGUAGE AllowAmbiguousTypes, ScopedTypeVariables #-}
f :: forall s. X -> Y

s类型变量将绑定在f的主体内。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM