应用实例化中的刚性变量
Rigid Variable in Applicative instantiation
我收到 Safeness
的 Applicative 实例化的编译器错误,如下所示:
{-# LANGUAGE InstanceSigs #-}
module Main where
main :: IO ()
main = pure ()
data Safeness a
= Unsafe a
| Safe a
| VerySafe a
deriving (Eq, Show)
instance Functor Safeness where
fmap :: (a -> b) -> Safeness a -> Safeness b
fmap f (Unsafe x) = Unsafe $ f x
fmap f (Safe x) = Safe $ f x
fmap f (VerySafe x) = VerySafe $ f x
instance Applicative Safeness where
pure :: a -> Safeness a
pure x = Safe x
(<*>) :: Safeness (a -> b) -> Safeness a -> Safeness b
(<*>) (Safe f) (Safe x) = Safe $ f x
(<*>) (VerySafe f) (VerySafe x) = VerySafe $ f x
(<*>) _ x = x
编译器错误:
* Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for:
(<*>) :: forall a b. Safeness (a -> b) -> Safeness a -> Safeness b
at C:\practise\app\Main.hs:27:14-58
`b' is a rigid type variable bound by
the type signature for:
(<*>) :: forall a b. Safeness (a -> b) -> Safeness a -> Safeness b
at C:\practise\app\Main.hs:27:14-58
Expected type: Safeness b
Actual type: Safeness a
* In the expression: x
In an equation for `<*>': (<*>) _ x = x
In the instance declaration for `Applicative Safeness'
* Relevant bindings include
x :: Safeness a
(bound at C:\practise\app\Main.hs:30:13)
(<*>) :: Safeness (a -> b) -> Safeness a -> Safeness b
(bound at C:\practise\app\Main.hs:28:5)
|
30 | (<*>) _ x = x
|
我知道 b
不必与 a
相同,但可以;在某些情况下,我总是强迫它相同。这有什么问题,我还能如何为预期的功能编写代码?
如错误消息所示,问题在于此模式:
(<*>) _ x = x
为了清楚起见,我们给第一个参数起个名字,并为主体提供一个“洞”:
(<*>) f x = _
然后编译器会告诉我们:
/Users/jpurdy/Code/Safe.hs:24:17: error:
• Found hole: _ :: Safeness b
…
• Relevant bindings include
x :: Safeness a
f :: Safeness (a -> b)
(<*>) :: Safeness (a -> b) -> Safeness a -> Safeness b
您可以 return 的唯一值是 Unsafe (_ :: b)
、Safe (_ :: b)
或 VerySafe (_ :: b)
,因此您必须提供 b
;通过参数化,获得 b
的 only 方法是通过匹配 f
获得 a -> b
并匹配 x
获取 a
,并将该函数应用于该值。换句话说,你不能只是 return x
未修改。
不幸的是,解决方案取决于您要执行的操作。您可以使用两个参数的 minimum 安全性来标记结果:
VerySafe f <*> VerySafe x = VerySafe $ f x
VerySafe f <*> Safe x = Safe $ f x
VerySafe f <*> Unsafe x = Unsafe $ f x
Safe f <*> VerySafe x = Safe $ f x
Safe f <*> Safe x = Safe $ f x
Safe f <*> Unsafe x = Unsafe $ f x
Unsafe f <*> VerySafe x = Unsafe $ f x
Unsafe f <*> Safe x = Unsafe $ f x
Unsafe f <*> Unsafe x = Unsafe $ f x
通过将安全参数从类型中分解出来会更简单(在类型代数中,从 a + a + a 到 3 × a):
data Safety = Unsafe | Safe | VerySafe
deriving (Eq, Ord)
data Safeness a = Safeness Safety a
instance Applicative Safeness where
-- Combine safeties with ‘min’, or use
-- ‘deriving (Semigroup, Monoid) via (Min Safety)’
-- to use the Semigroup ‘<>’ operator.
Safeness s1 f <*> Safeness s2 x
= Safeness (min s1 s2) (f x)
-- Must use ‘VerySafe’ instead of ‘Safe’
-- since it’s the identity for ‘min’,
-- to satisfy the ‘Applicative’ laws.
-- (Or respectively ‘mempty’ = ‘maxBound’.)
pure = Safeness VerySafe
或者您可以使用 GADT 将安全参数提升到类型级别,在 Applicative
实例之前,但只允许具有 相同 的值安全组合:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}
data Safety = U | S | V
data Safeness (s :: Safety) a where
VerySafe :: a -> Safeness 'V a
Safe :: a -> Safeness 'S a
Unsafe :: a -> Safeness 'U a
apply :: Safeness s (a -> b) -> Safeness s a -> Safeness s b
apply (VerySafe f) (VerySafe x) = VerySafe (f x)
apply (Safe f) (Safe x) = Safe (f x)
apply (Unsafe f) (Unsafe x) = Unsafe (f x)
-- (Other cases are impossible because ‘s’ won’t match.)
顺便说一句,您可以使用 DeriveFunctor
扩展名为 Safeness
编写 deriving (Functor)
。
我收到 Safeness
的 Applicative 实例化的编译器错误,如下所示:
{-# LANGUAGE InstanceSigs #-}
module Main where
main :: IO ()
main = pure ()
data Safeness a
= Unsafe a
| Safe a
| VerySafe a
deriving (Eq, Show)
instance Functor Safeness where
fmap :: (a -> b) -> Safeness a -> Safeness b
fmap f (Unsafe x) = Unsafe $ f x
fmap f (Safe x) = Safe $ f x
fmap f (VerySafe x) = VerySafe $ f x
instance Applicative Safeness where
pure :: a -> Safeness a
pure x = Safe x
(<*>) :: Safeness (a -> b) -> Safeness a -> Safeness b
(<*>) (Safe f) (Safe x) = Safe $ f x
(<*>) (VerySafe f) (VerySafe x) = VerySafe $ f x
(<*>) _ x = x
编译器错误:
* Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for:
(<*>) :: forall a b. Safeness (a -> b) -> Safeness a -> Safeness b
at C:\practise\app\Main.hs:27:14-58
`b' is a rigid type variable bound by
the type signature for:
(<*>) :: forall a b. Safeness (a -> b) -> Safeness a -> Safeness b
at C:\practise\app\Main.hs:27:14-58
Expected type: Safeness b
Actual type: Safeness a
* In the expression: x
In an equation for `<*>': (<*>) _ x = x
In the instance declaration for `Applicative Safeness'
* Relevant bindings include
x :: Safeness a
(bound at C:\practise\app\Main.hs:30:13)
(<*>) :: Safeness (a -> b) -> Safeness a -> Safeness b
(bound at C:\practise\app\Main.hs:28:5)
|
30 | (<*>) _ x = x
|
我知道 b
不必与 a
相同,但可以;在某些情况下,我总是强迫它相同。这有什么问题,我还能如何为预期的功能编写代码?
如错误消息所示,问题在于此模式:
(<*>) _ x = x
为了清楚起见,我们给第一个参数起个名字,并为主体提供一个“洞”:
(<*>) f x = _
然后编译器会告诉我们:
/Users/jpurdy/Code/Safe.hs:24:17: error:
• Found hole: _ :: Safeness b
…
• Relevant bindings include
x :: Safeness a
f :: Safeness (a -> b)
(<*>) :: Safeness (a -> b) -> Safeness a -> Safeness b
您可以 return 的唯一值是 Unsafe (_ :: b)
、Safe (_ :: b)
或 VerySafe (_ :: b)
,因此您必须提供 b
;通过参数化,获得 b
的 only 方法是通过匹配 f
获得 a -> b
并匹配 x
获取 a
,并将该函数应用于该值。换句话说,你不能只是 return x
未修改。
不幸的是,解决方案取决于您要执行的操作。您可以使用两个参数的 minimum 安全性来标记结果:
VerySafe f <*> VerySafe x = VerySafe $ f x
VerySafe f <*> Safe x = Safe $ f x
VerySafe f <*> Unsafe x = Unsafe $ f x
Safe f <*> VerySafe x = Safe $ f x
Safe f <*> Safe x = Safe $ f x
Safe f <*> Unsafe x = Unsafe $ f x
Unsafe f <*> VerySafe x = Unsafe $ f x
Unsafe f <*> Safe x = Unsafe $ f x
Unsafe f <*> Unsafe x = Unsafe $ f x
通过将安全参数从类型中分解出来会更简单(在类型代数中,从 a + a + a 到 3 × a):
data Safety = Unsafe | Safe | VerySafe
deriving (Eq, Ord)
data Safeness a = Safeness Safety a
instance Applicative Safeness where
-- Combine safeties with ‘min’, or use
-- ‘deriving (Semigroup, Monoid) via (Min Safety)’
-- to use the Semigroup ‘<>’ operator.
Safeness s1 f <*> Safeness s2 x
= Safeness (min s1 s2) (f x)
-- Must use ‘VerySafe’ instead of ‘Safe’
-- since it’s the identity for ‘min’,
-- to satisfy the ‘Applicative’ laws.
-- (Or respectively ‘mempty’ = ‘maxBound’.)
pure = Safeness VerySafe
或者您可以使用 GADT 将安全参数提升到类型级别,在 Applicative
实例之前,但只允许具有 相同 的值安全组合:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}
data Safety = U | S | V
data Safeness (s :: Safety) a where
VerySafe :: a -> Safeness 'V a
Safe :: a -> Safeness 'S a
Unsafe :: a -> Safeness 'U a
apply :: Safeness s (a -> b) -> Safeness s a -> Safeness s b
apply (VerySafe f) (VerySafe x) = VerySafe (f x)
apply (Safe f) (Safe x) = Safe (f x)
apply (Unsafe f) (Unsafe x) = Unsafe (f x)
-- (Other cases are impossible because ‘s’ won’t match.)
顺便说一句,您可以使用 DeriveFunctor
扩展名为 Safeness
编写 deriving (Functor)
。