Sanctuary.Js 恒等函子类型错误
Sanctuary.Js Type Error with Identity Functor
我正在玩 youtube 上的 Bartosz Milewski 类别理论课程。他将 Const 和 Identity 仿函数描述为 "base" 仿函数可以派生自(可能是我的自由解释)。
我的问题是,已经实现了 ES6+ / fantasy-land(不重要)版本的仿函数,一旦我开始与 Sanctuary 库集成用于地图和管道,就会出现。
实现非常简单
const {map: flMap, extract } = require('fantasy-land');
const getInstance = (self, constructor) =>
(self instanceof constructor) ?
self :
Object.create(constructor.prototype) ;
const Identity = function(x){
const self = getInstance(this, Identity)
self[flMap] = f => Identity(f(x))
self[extract] = () => x
return Object.freeze(self)
}
下面是一些简单的用法(因为我也在做离子导出透镜)
// USAGE
const {map, pipe, curry} = require("sanctuary")
const extractFrom = x => x[extract]()
const setter = (f, x) => (pipe([
Identity,
map(f),
extractFrom
])(x))
const double = x => x + x
console.log(Identity(35)) //=> 35
console.log(map(double, Identity(35))) // ERROR Should be Identity(70)
console.log(setter(double, 35)) // ERROR Should be: 70
TypeError: Type-variable constraint violation
map :: Functor f => (a -> b) -> f a -> f b
^ ^
1 2
1) 35 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer,
NonNegativeInteger, ValidNumber
2) () => x :: Function, (c -> d)
f => Identity(f(x)) :: Function, (c -> d)
Since there is no type of which all the above values are members, the
type-variable constraint has been violated.
不过,Const 仿函数的效果要好一些(没有在 map 中调用 f)
const Const = function(x) {
const self = getInstance(this, Const)
self[map] = _ => Const(x)
self[extract] = () => x
return Object.freeze(self)
}
const getter = (f, x) => (pipe([
Const,
map(f),
extractFrom
])(x))
console.log(getter(double, 35)) //=> 35
此外,一切都是 "logically sound",正如通过删除类型检查
所证明的那样
const {create, env} = require('sanctuary');
const {map, pipe, curry} = create({checkTypes: false, env: env});
或者用 ramda 替换避难所。所以它看起来像是身份映射函数的某种类型一致性问题。
问题是我如何让所有这些部分以一种快乐的方式一起玩。
您需要为您的类型 (IdentityType :: Type -> Type
) 定义一个类型构造函数,并按照 S.create
文档中的描述在您的 Sanctuary 环境中包含 IdentityType ($.Unknown)
。具体来说,您需要这样的东西:
// IdentityType :: Type -> Type
const IdentityType = $.UnaryType
('my-package/Identity')
('http://example.com/my-package#Identity')
(x => type (x) === Identity['@@type'])
(identity => [Z.extract (identity)]);
const S = create ({
checkTypes: process.env.NODE_ENV !== 'production',
env: env.concat ([IdentityType ($.Unknown)]),
});
在上面的代码片段中,$
指的是 sanctuary-def, Z
refers to sanctuary-type-classes, and type
refers to sanctuary-type-identifiers。
我正在玩 youtube 上的 Bartosz Milewski 类别理论课程。他将 Const 和 Identity 仿函数描述为 "base" 仿函数可以派生自(可能是我的自由解释)。
我的问题是,已经实现了 ES6+ / fantasy-land(不重要)版本的仿函数,一旦我开始与 Sanctuary 库集成用于地图和管道,就会出现。
实现非常简单
const {map: flMap, extract } = require('fantasy-land');
const getInstance = (self, constructor) =>
(self instanceof constructor) ?
self :
Object.create(constructor.prototype) ;
const Identity = function(x){
const self = getInstance(this, Identity)
self[flMap] = f => Identity(f(x))
self[extract] = () => x
return Object.freeze(self)
}
下面是一些简单的用法(因为我也在做离子导出透镜)
// USAGE
const {map, pipe, curry} = require("sanctuary")
const extractFrom = x => x[extract]()
const setter = (f, x) => (pipe([
Identity,
map(f),
extractFrom
])(x))
const double = x => x + x
console.log(Identity(35)) //=> 35
console.log(map(double, Identity(35))) // ERROR Should be Identity(70)
console.log(setter(double, 35)) // ERROR Should be: 70
TypeError: Type-variable constraint violation map :: Functor f => (a -> b) -> f a -> f b ^ ^ 1 2 1) 35 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer, NonNegativeInteger, ValidNumber 2) () => x :: Function, (c -> d) f => Identity(f(x)) :: Function, (c -> d) Since there is no type of which all the above values are members, the type-variable constraint has been violated.
不过,Const 仿函数的效果要好一些(没有在 map 中调用 f)
const Const = function(x) {
const self = getInstance(this, Const)
self[map] = _ => Const(x)
self[extract] = () => x
return Object.freeze(self)
}
const getter = (f, x) => (pipe([
Const,
map(f),
extractFrom
])(x))
console.log(getter(double, 35)) //=> 35
此外,一切都是 "logically sound",正如通过删除类型检查
所证明的那样const {create, env} = require('sanctuary');
const {map, pipe, curry} = create({checkTypes: false, env: env});
或者用 ramda 替换避难所。所以它看起来像是身份映射函数的某种类型一致性问题。
问题是我如何让所有这些部分以一种快乐的方式一起玩。
您需要为您的类型 (IdentityType :: Type -> Type
) 定义一个类型构造函数,并按照 S.create
文档中的描述在您的 Sanctuary 环境中包含 IdentityType ($.Unknown)
。具体来说,您需要这样的东西:
// IdentityType :: Type -> Type
const IdentityType = $.UnaryType
('my-package/Identity')
('http://example.com/my-package#Identity')
(x => type (x) === Identity['@@type'])
(identity => [Z.extract (identity)]);
const S = create ({
checkTypes: process.env.NODE_ENV !== 'production',
env: env.concat ([IdentityType ($.Unknown)]),
});
在上面的代码片段中,$
指的是 sanctuary-def, Z
refers to sanctuary-type-classes, and type
refers to sanctuary-type-identifiers。