我有以下类型定义:
newtype Flip f a b =
Flip (f b a) deriving (Eq, Show)
Flip
数据构造函数是否有一个或三个参数?
Consinder实施后:
data K a b = K a
newtype Flip f a b =
Flip (f b a) deriving (Eq, Show)
instance Functor (Flip K a) where
fmap f (Flip (K b)) = Flip (K (f b))
(Flip K a)
的类型是什么?
答案 0 :(得分:7)
import django.http
from django.views.generic import View
from project.stuff.models import Stuff
class ApiStuff(View):
@staticmethod
def get(request, *args, **kwargs):
stuff_id = kwargs['stuff_id']
try:
stuff = Stuff.objects.get(pk=stuff_id)
except Stuff.DoesNotExist:
return response({"error": "stuff not found"}, 404)
result = stuff.serialize()
return response(result)
def response(data, status=200):
data = json.dumps(data)
return django.http.HttpResponse(data, status=status, content_type='application/json')
数据构造函数有一个参数。该参数的类型为Flip
。
这意味着f b a
本身是类型为f
的高阶类型参数。更严格的f :: * -> * -> *
声明将是:
newtype
因此,您可以实例化newtype Flip (f :: * -> * -> *) a b = Flip (f b a)
,因为Flip Either Int Bool
是一种需要两个额外类型参数的类型,然后构造一个Either
。
Flip (Right 1) :: Flip Either Int Bool
的类型是什么?
(Flip K a)
不是完全应用的类型。在伪代码中,它具有类型Flip K a
。解析b -> Flip K a b
后(b
使用更高阶类型),我们知道Functor
的唯一参数将具有Flip
构造函数。因此,例如K b
是Flip (K 1)
类型。
答案 1 :(得分:6)
现在,未来(使用ghc 8和)打开一两个标志
Prelude> :set -XPolyKinds -XFlexibleInstances
让我们宣布
Prelude> newtype Flip f a b = MkFlip (f b a)
然后查询
Prelude> :kind Flip
Flip :: (k1 -> k -> *) -> k -> k1 -> *
Prelude> :type MkFlip
MkFlip
:: forall k k1 (b :: k) (f :: k -> k1 -> *) (a :: k1).
f b a -> Flip f a b
类型构造函数Flip
有两个隐式参数,即k
和k1
,以及三个显式参数,是生成类型的二元函数,然后它的两个参数的顺序相反。这个函数的参数是无约束的类型(老人们可以说"亲和"如果他们喜欢),但它肯定会返回一个类型(严格意义上的{&1;} *
"而不是对::
")的任何旧垃圾权利的无用模糊感,因为它肯定在MkFlip
的声明中用作类型。< / p>
数据构造函数MkFlip
采用五个隐式参数(正好是Flip
的参数)和一个显式参数,是一些数据在f b a
。
正在进行的是Hindley-Milner类型推断一级。收集约束(例如,f b a
必须居住*
,因为构造函数参数必须居住f b a
),否则会传递最常规的类型:a
和b
可以是任何内容,因此它们的类型被概括为k1
和k
。
让我们使用常量类型构造函数玩相同的游戏:
Prelude> newtype K a b = MkK a
Prelude> :kind K
K :: * -> k -> *
Prelude> :type MkK
MkK :: forall k (b :: k) a. a -> K a b
我们看到a :: *
但b
可能是任何旧垃圾(就此而言,k :: *
,这些日子,* :: *
)。显然,a
实际上被用作事物的类型,但b
根本不被使用,因此不受约束。
然后我们可以宣布
Prelude> instance Functor (Flip K b) where fmap f (MkFlip (MkK a)) = MkFlip (MkK (f a))
并询问
Prelude> :info Flip
...
instance [safe] forall k (b :: k). Functor (Flip K b)
告诉我们未使用的b
仍然可以是任何旧垃圾。因为我们有
K :: * -> k -> *
Flip :: (k1 -> k -> *) -> k -> k1 -> *
我们可以统一k1 = *
并获取
Flip K :: k -> * -> *
等等
Flip K b :: * -> *
适用于任何旧b
。因此,Functor
实例是合理的,并且实际上是可交付的,其中函数作用于打包的a
元素,对应于Flip K b
的参数,该参数成为第一个 K
的参数,因此是存储元素的类型。
基于统一的类型推断是活生生的,并且(相当)很好,在::
右边。