- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我对如何在数据族
和类型族
之间进行选择感到困惑。维基页面TypeFamilies涉及很多细节。有时,它在散文中非正式地将 Haskell 的数据族
称为“类型族”,但当然 Haskell 中也有类型族
。
有一个简单的示例,显示了两个版本的代码的显示位置,区别仅在于声明的是数据系列
还是类型系列
:
-- BAD: f is too ambiguous, due to non-injectivity
-- type family F a
-- OK
data family F a
f :: F a -> F a
f = undefined
g :: F Int -> F Int
g x = f x
这里的
type
和data
含义相同,但是type family
版本无法进行类型检查,而data family
版本很好,因为 data family
“创建新类型,因此是单射的”(维基页面说)。
我从这一切中得到的结论是“对于简单的情况尝试数据族
,如果它不够强大,那么尝试类型族
”。这很好,但我想更好地理解它。是否有我可以遵循的维恩图或决策树来区分何时使用哪个?
最佳答案
(将评论中的有用信息提升为答案。)
声明类型族和/或数据族的两种语法上不同的方法,在语义上是等效的:
独立:
type family Foo
data family Bar
或者作为类型类的一部分:
class C where
type Foo
data Bar
都声明了一个类型族,但在类型类中 family
部分由 class
暗示上下文,因此 GHC/Haskell 缩写了声明。
data family F
创建一个新类型,类似于 data F = ...
创建一个新类型。
type family F
不创建新类型,类似于 type F = Bar Baz
不会创建新类型(它只是为现有类型创建别名/同义词)。
type family
的非注入(inject)性示例来自 Data.MonoTraversable.Element
的示例(稍作修改) :
import Data.ByteString as S
import Data.ByteString.Lazy as L
-- Declare a family of type synonyms, called `Element`
-- `Element` has kind `* -> *`; it takes one parameter, which we call `container`
type family Element container
-- ByteString is a container for Word8, so...
-- The Element of a `S.ByteString` is a `Word8`
type instance Element S.ByteString = Word8
-- and the Element of a `L.ByteString` is also `Word8`
type instance Element L.ByteString = Word8
在类型族中,方程的右侧 Word8
命名现有类型;左侧的事物创建了新的同义词:Element S.ByteString
和Element L.ByteString
拥有同义词意味着我们可以互换 Element Data.ByteString
与 Word8
:
-- `w` is a Word8....
>let w = 0::Word8
-- ... and also an `Element L.ByteString`
>:t w :: Element L.ByteString
w :: Element L.ByteString :: Word8
-- ... and also an `Element S.ByteString`
>:t w :: Element S.ByteString
w :: Element S.ByteString :: Word8
-- but not an `Int`
>:t w :: Int
Couldn't match expected type `Int' with actual type `Word8'
这些类型同义词是“非内射的”(“单向”),因此是不可逆的。
-- As before, `Word8` matches `Element L.ByteString` ...
>(0::Word8)::(Element L.ByteString)
-- .. but GHC can't infer which `a` is the `Element` of (`L.ByteString` or `S.ByteString` ?):
>(w)::(Element a)
Couldn't match expected type `Element a'
with actual type `Element a0'
NB: `Element' is a type function, and may not be injective
The type variable `a0' is ambiguous
更糟糕的是,GHC 甚至无法解决明确的情况!:
type instance Element Int = Bool
> True::(Element a)
> NB: `Element' is a type function, and may not be injective
注意“可能不是”的使用!我认为 GHC 很保守,拒绝检查 Element
是否有效。确实是内射的。 (也许是因为程序员可以在导入预编译模块后添加另一个type instance
,从而增加歧义。
data family
的单射性示例相反:在数据族中,每个右侧都包含一个唯一的构造函数,因此定义是单射(“可逆”)方程。
-- Declare a list-like data family
data family XList a
-- Declare a list-like instance for Char
data instance XList Char = XCons Char (XList Char) | XNil
-- Declare a number-like instance for ()
data instance XList () = XListUnit Int
-- ERROR: "Multiple declarations of `XListUnit'"
data instance XList () = XListUnit Bool
-- (Note: GHCI accepts this; the new declaration just replaces the previous one.)
与 data family
,看到右侧的构造函数名称( XCons
或 XListUnit
)足以让类型推断器知道我们必须使用 XList ()
不是XList Char
。由于构造函数名称是唯一的,因此这些定义是单射/可逆的。
type
“just”声明了一个同义词,为什么它在语义上有用?通常,type
同义词只是缩写,但是type
系列同义词增加了功能:它们可以使简单类型 (kind *
) 成为“将 kind * -> *
应用于参数的类型”的同义词:
type instance F A = B
使B
匹配F a
。例如,这在 Data.MonoTraversable
中使用。制作一个简单的类型Word8
匹配 Element a -> a
类型的函数( Element
已在上面定义)。
例如,(有点傻),假设我们有一个 const
的版本仅适用于“相关”类型:
> class Const a where constE :: (Element a) -> a -> (Element a)
> instance Const S.ByteString where constE = const
> constE (0::Word8) undefined
ERROR: Couldn't match expected type `Word8' with actual type `Element a0'
-- By providing a match `a = S.ByteString`, `Word8` matches `(Element S.ByteString)`
> constE (0::Word8) (undefined::S.ByteString)
0
-- impossible, since `Char` cannot match `Element a` under our current definitions.
> constE 'x' undefined
关于haskell - 简而言之,'type family' 与 'data family' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20870432/
我对如何在数据族和类型族之间进行选择感到困惑。维基页面TypeFamilies涉及很多细节。有时,它在散文中非正式地将 Haskell 的数据族称为“类型族”,但当然 Haskell 中也有类型族。
我想知道如果我不支持它,如何不显示复杂功能系列。 示例:超大表盘 在 ComplicationController.swift的 getLocalizableSampleTemplate和 getCu
我正在开发一个用 C 编写的服务器软件。我创建了一个用于设置名为 config 的全局变量的函数,因此我可以在多个项目中使用此代码。您可以从标题中获取错误消息。 typedef struct ntp_
我刚开始接触网络编程。在查看套接字函数时,有些使用 PF_INET,有些使用 AF_INET。看过 wikipedia ,它说这样的设计被用来使不同的协议(protocol)族能够使用不同的地址族。今
我在主函数中声明了一个struct sockaddr_in server。 我将它传递给这个函数以返回一个套接字文件描述符 int openSocket(char* ip_addr, int port
library(lme4) dummy <- as.data.frame(cbind(speed = rpois(100, 10), pop = rep(1:4, each = 25), season
我正在使用 react-native webview在我的react-native应用程序。和我的应用程序 font-family和 webview font-family是不同的。 我要改webvi
我正在使用 JDeveloper 10g 开发一个项目(是的,想象一下)。 该项目包括使用 Jersey 开发 RESTful Web 服务。 让我发疯的是,每当我使用 javax.ws.rs.cor
我只是套接字编程的初学者,目前正在开发一个使用 UDP 处理文件传输的小程序。这个程序是用C写的。 这是我的问题: UDP 服务器将首先使用 recvfrom() 函数从 UDP 客户端捕获消息,以便
所以我决定开始优化我的网站并修复问题,这在 W3C 验证程序中出现了。 值错误:字体系列 "Neue"不是字体系列值:"Montserrat",Helvetica "Neue",Helvetica,A
我在 w3 css validtor as 中遇到两个错误 值错误:font-family 属性 font-family 在 CSS level 2.1 中不存在但存在于 [css1, css2, c
有没有办法改变 input["password"] 的字体? ? 我创建了一个带有 WOFF 的网络字体 ( squared asterisk)模拟 -webkit-text-security: sq
我试图按顺序打印每个人的姓名,但我不断收到此错误family[i] is undefined。 function Person (name, age) { this.name = name;
我刚刚发现我的 Chrome 会以不同的方式对待 font-family: "sans-serif" 和 font-family: sans-serif(它会选择不同的字体) .谁能解释这是如何工作的
给定表格 | id | user | | 1 | 1 | | 1 | 2 | | 1 | 3 | | 1 | 4 | | 2 | 5 | | 2 | 6
我们有一组共享相同包前缀的应用程序。它们是同一项目中的目标。我们希望发送属于整个组应用程序的推送通知,以便用户不会收到相同的通知多次,一个用于该组的每个应用程序。是否有一些正式的方式来发送此类推送通知
当我启用浏览器打印时,我的字体系列 ARIAL NARROW 无法正常工作,在屏幕上它很好,但在打印预览中它将变成 TIMES NEW ROMAN. 示例代码,这种样式的 css 在我的 dvCont
我试过这个: div.content { font-family: Verdana; } 还有这个: div.content { font-family: 'Verdana'; } 还
我的页面中有 2 个文本框控件。单线和多线。 我注意到多行文本框和单行文本框之间的默认 Family-fonts 是不同的。我检查过它也来自相同的 CSS 表和相同的行。 不确定为什么不同以及如何修复
像这样加载 Google 字体(Open sans)时: 并像这样在 CSS 中使用它: font-family: 'Open Sans',sans-serif !important; 在不同的页面
我是一名优秀的程序员,十分优秀!