让我们假设四个函数f1,f2,f3,f4 :: SomeMonad m => m a -> m a
,其中f1
和f2
在概念上相关,同样f3
和f4
。
现在可以编写一个函数f :: SomeMonad m => (m a -> m a) -> m a
,可以将任何f1..f4
作为输入。然后可以编写f1 $ f f2
。
问题是,如何编写一个函数g
,使其仅接受f1
或f2
作为参数?我们应该能够写f4 $ g f1
而ghc应该拒绝g f3
。
如果我尝试添加class
,例如:: (SomeMonad m, Some_G_class a) =>
,则返回类型a
也会受到约束,然后无法应用f4
。同样地,似乎m
无法修改。
延迟添加
Daniel Wagner和leftroundabout的答案似乎都可以使用。
以下是关于实际(和实际)问题的更多信息。
m a
。(.)
一样f1 . f2 . f3
。 使用代理
似乎
data Type = A | B | C ... | H
data Proxy (ty :: Type) = Proxy
可用于对函数进行分类。要处理重叠使用,可以调用函数,如
h1 :: SomeMonad t m => Either (Proxy A) (Proxy B) -> m t -> m t
h1 (Left (Proxy :: Proxy A) mt = ..
h1 (Right (Proxy :: Proxy B) mt = ..
可以做到。但是如果属于A, B, C
和D
的函数怎么办?也许有OneOf
或Any
之类的内容可以在这里使用?
使用RankNTypes
似乎SpecificMonad
- 约束(限制?)开始支持函数f3
和f4
的使用网站(即全部)。我觉得如果我尝试管理5-10个重叠函数集,那么那些在每个地方传播的约束都会遇到严重的困难。是这种情况吗?
所以我们需要一个函数来强制执行,可能就像
fg :: (SomeMonad t m1, SpecificMonad t m2) => m2 t -> m1 t
fg a = pure $ fromSpecM a
和atm假设SomeMonad
有pure
。在我的情况下,我无法将fromSpecM
添加到SomeMonad
的类方法中,但可能在SpecificMonad
中没有问题。我在这方面的第一次试验仍然过于简单,以至于我可以看出这是否可行。很可能我在这里看不到一些非常明显的东西。
在某种程度上,SpecificMonad
不应该有任何其他方法,它应该只是作为"本地env / fix / hack"不影响代码的其他部分。那么,还有其他方法可以实现像fg
答案 0 :(得分:3)
如果f1
,f2
,f3
,f4
都具有相同的类型签名,则类型系统无法区分它们(duh),所以你也不能限制哪些应该有效。
因此,在您可以实现目标之前,您需要在签名中加以区分。可能最明智的方法是改进monad级约束:
class SomeMonad m => SpecificMonad m
f1, f2 :: SomeMonad m => m a -> m a -- same as before
f3, f4 :: SpecificMonad m => m a -> m a -- more restrictive
(您不需要在此处更改实施,因为SpecificMonad
保证SomeMonad
。)
现在,f :: SomeMonad m => (m a -> m a) -> m a
本身并不强制该参数满足任何特定约束 - 您传入的任何函数只会将其约束添加到SomeMonad
带来的f
m约束,即
f f1 :: SomeMonad m => m a
f f3 :: SpecificMonad m => m a -- because `SomeMonad` is superclass, we don't need
-- to mention it, but it's actually implicit constraint
都很好。
但是,您可以假设f
只接受具有特定不太具体约束的函数。这需要Rank-2多态性†:
{-# LANGUAGE RankNTypes, UnicodeSyntax #-}
g :: SomeMonad m => (∀ μ . SomeMonad μ => μ a -> μ a) -> m a
g φ = f φ
现在,您可以编写g f1
,因为f1
是一个适用于任何SomeMonad
的多态函数。但是你不能写g f3
,因为f3
在它可以操作的monad中太挑剔了,即使m
应该与g f3
一起使用的外SpecificMonad
也是如此履行g
约束‡,f3
将不允许其参数访问该信息。
当然,要在任何其他合法设置(例如f4
)中使用f4 $ g f1
和SpecificMonad
,您必须为{添加实例{1}}他们应该与任何monad一起工作。这些是像
instance SpecificMonad []
instance SpecificMonad Maybe
(前提是它们已经有SomeMonad
个实例)。
† 无Unicode编写:
g :: SomeMonad m => (forall m' . SomeMonad m' => m' a -> m' a) -> m a
g = f
‡ 必要时,如果你想写f4 $ g f1
。
答案 1 :(得分:1)
也许你可以使用一个简单的幻像类型参数。例如:
import { NativeModules } from 'react-native';
在ghci中,我们可以看到NativeModules.TestClass.test('C# called successfully.');
和{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
data Type = A | B
data Id (ty :: Type) a = Id a
f1, f2 :: Id A a -> Id A a
f1 = id
f2 = id
f3, f4 :: Id B a -> Id B a
f3 = id
f4 = id
组合得很好,f1
和f2
也是如此,但不是f3
和f4
:
f1