[英]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 s
是ReflectNum
一部分。 但是,应该像在其中应用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
那么您可以通过启用AllowAmbiguousTypes
和ScopedTypeVariables
并使用显式的forall
来消除Proxy
参数:
{-# LANGUAGE AllowAmbiguousTypes, ScopedTypeVariables #-}
f :: forall s. X -> Y
s
类型变量将绑定在f
的主体内。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.