【发布时间】:2018-06-14 01:08:00
【问题描述】:
我正在尝试从头开始学习逆变器和更深入的 Sanctuary 知识。代码“有效”,但我的类型也不完全正确。
这里是逆变器
const {contramap: contramapFl, extract } = require('fantasy-land');
const getInstance = (self, constructor) =>
(self instanceof constructor) ?
self :
Object.create(constructor.prototype) ;
// Contra a ~> g: a -> ?
const Contra = function(g){
const self = getInstance(this, Contra)
// :: F a ~> b -> a -> F b [ b -> a -> ? ]
self[contramapFl] = f => Contra( x => g(f(x)) )
self[extract] = g
self['@@type'] = 'fs-javascript/contra'
return Object.freeze(self)
}
// UPDATE adding type to constructor
Contra['@@type'] = 'fs-javascript/contra'
我尝试正确输入类型
const $ = require('sanctuary-def');
const type = require('sanctuary-type-identifiers');
const Z = require('sanctuary-type-classes') ;
const isContra = x => type (x) === 'fs-javascript/contra'
const ContraType = $.UnaryType(
'fs-javascript/contra',
'http://example.com/fs-javascript#Contra',
isContra,
x => [x[extract]])($.Unknown)
然后是我的测试
const {create, env} = require('sanctuary');
const {contramap} = create({checkTypes: true, env: env.concat(ContraType) });
const isEven = Contra(x => x % 2 === 0) ;
console.log(Z.Contravariant.test(isEven)) // => true
const isLengthEvenContra = contramap(y => y.length, isEven)
const isStringLengthEven = isLengthEvenContra[extract]
console.log(isStringLengthEven("asw")) //=> ERROR
TypeError: Type-variable constraint violation contramap :: Contravariant f => (b -> a) -> f a -> f b ^ 1 1) "fs-javascript/contra" :: String f => Contra( x => g(f(x)) ) :: Function, (c -> d) x => x % 2 === 0 :: Function, (c -> d) Since there is no type of which all the above values are members, the type-variable constraint has been violated.
如果我禁用类型检查,那么它会按预期工作,所以从逻辑上讲,它似乎被正确地缝合在一起。我定义了自己的 contramap 版本
const def = $.create({ checkTypes: true, env: $.env.concat(ContraType) });
const contramap2 =
def('contramap2', {}, [$.Unknown, ContraType, ContraType],
(f, x) => {
const z = x[contramapFl](f)
return z
}
)
然后我重新运行测试:
const isEven = Contra(x => x % 2 === 0) ;
console.log(Z.Contravariant.test(isEven)) // => true
const isLengthEvenContra = contramap2(y => y.length, isEven)
const isStringLengthEven = isLengthEvenContra[extract]
console.log(isStringLengthEven("asw")) //=> false
因此,尽管讨论了逆变函子是否是解决这个问题的最佳方法(学习练习),问题是,在定义我自己的逆变函数实现时,我可以如何将 sanctuary 的 contramap 函数与启用类型检查。
更新后添加代码:
Contra['@@type'] = 'fs-javascript/contra'
将错误更改为:
TypeError: Type-variable constraint violation contramap :: Contravariant f => (b -> a) -> f a -> f b ^ ^ 1 2 1) 3 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer, NonNegativeInteger, ValidNumber 2) x => x % 2 === 0 :: Function, (c -> d) Since there is no type of which all the above values are members, the type-variable constraint has been violated.
// Contra (Integer -> Boolean)
const isEven = Contra(x => x % 2 === 0) ;
// String -> Integer
const strLength = y => y.length
// I Think: Contra (String -> (Integer -> Boolean))
const isLengthEvenContra = contramap(strLength, isEven)
// (String -> (Integer -> Boolean))
const isStringLengthEven = isLengthEvenContra[extract]
我对逆变函子的理解是,它在其中预先组合了函数,函数通过contramap 传入。因此,如果逆变器包含函数 f 并且它是 contramap 和 g 它返回一个新的逆变函子包装 x = g(f(x)) 我是否也误解了这个
【问题讨论】:
-
@@type必须存在于类型代表而不是值本身上。换句话说,x.constructor['@@type']而不是x['@@type']。你能提供Contra#fantasy-land/contramap的类型签名吗?我不清楚它与Function#fantasy-land/contramap有何不同。 -
@davidchambers 感谢 cmets。我已将签名添加到 Contra 构造函数,它改变了错误。我会在上面更新。
标签: javascript functional-programming fantasyland sanctuary