函数式编程多态 [英] Functional programming polymorhism
问题描述
我想知道如何在函数式编程中创建多态。
让我们以不同类型的输入作为示例表单类
在JS es6中使用polymorh:
class表单{
构造函数(字段){
this.fields = fields;
}
validate(){
let err = null;
for(let f of this.fields){
if(!field.validate()){
return field.getErr();
}
}
}
}
class TextField {
isNotEmpty(){
return this.value!=' '
}
validate(){
return this.isNotEmpty()
}
}
class SelectField {
validate (){
if(!inArray(this.value,this.options){
return'value is not in the available options'
}
}
}
该代码仅用于演示目的,不要看语法或正确行为。
我想知道如何在FP中创建类似的多态。
在Haskell中,您可以使用模式匹配,但是如何在javascript中执行它?
有人说我可以用if语句实现不同的功能:
if(field.type =='文本')...
else if(field.type =='select')...
但是这很糟糕,因为我应该将所有的逻辑写入一个函数中。
I如果想要添加新类型的字段(例如MultipleSelect),我应该更改普通功能中的代码。
在javascript中有更好的选择吗?
$我从OP提供的示例代码中得到的唯一方法就是将当前处理的表单字段映射为字段
- 特定的验证和错误处理功能...一个可用的示例代码然后看起来像...
/ ** *表单和字段类型匹配配置表/ maps * / const validationTable = {isValidFieldType:{text:isValidTextField,select:isValidSelectField ,// multiselect:... __invalid__:returnInvalidFieldValue},validateForm:validateForm}; const createErrorTable = {// form:createFormError,field:{text:createTextFieldError,select:createSelectFieldError,// multiselect:... __invalid__:handleCreateErrorException}}; / ** *帮助getter功能* - 返回一个有效的字段类型*匹配`validationTable.isValidFieldType` *中的键 - 或者返回'__invalid__'键,因为它是* fallback值。 * / function getValidationFieldType(field){const fieldType =(field& field.type); return((typeof fieldType ==='string')&&(validationTable.isValidFieldType中的fieldType)&& fieldType)|| '__invalid __';} / ** *主要验证功能* - 为完全有效的表单验证过程返回`true` - 或者返回类型特定/相关的验证错误。 * / function validateForm(type){const tableOfIsValidFieldType = validationTable.isValidFieldType;让recentField;返回Array.from(type.fields).every(field => {recentField = field; return tableOfIsValidFieldType [getValidationFieldType(field)](field);})|| createErrorTable.field [getValidationFieldType(recentField)](/ * recentField * /);} / ** *验证和错误处理特定帮助函数* / function isValidTextField(type){return(type.value!=='');}函数isValidSelectField(type){返回Array.from(type.options).includes(type.value);}函数returnInvalidFieldValue(){返回false;}函数createTextFieldError(/ * recentField * /){return(new Error('an '));} function createSelectFieldError(/ * recentField * /){return(new Error('字段值与选项'不匹配));}函数handleCreateErrorException(/ * recentField * / ){return(new error('没有与此字段匹配的验证和错误处理'));} / ** * test * / const validForm = {fields:[{type:'text',value:'valid '},{type:'select',value:'valid',options:['valid','select','field']}]}; const invalidFormWithNullType = {fields:[{type:'text ',value:'valid'},{type:null,value:'valid'},{type:'select',value:'valid',options:['valid','select','field']} ]}; const invalidFormWithMissingType = {fields:[{value:'valid'},{type:'select',value:'valid',options:['valid','select','field']}]}; const invalidFormWithEmptyTextValue = {fields:[{type:'text',value:''},{type:'select',value:'valid',options:['valid','select','field']}] }; const intFormWithNonMatchingSelectValue = {fields:[{type:'text',value:'valid'},{type:'select',value:'invalid',options:['valid','select','field' ];}}}; console.log('validateForm(validForm):',validateForm(validForm)); console.log('validateForm(invalidFormWithNullType).message:',validateForm(invalidFormWithNullType).message); console.log(' validateForm(invalidFormWithMissingType).message:',v console.log('validateForm(invalidFormWithEmptyTextValue).message:',validateForm(invalidFormWithEmptyTextValue).message); console.log('validateForm(invalidFormWithNonMatchingSelectValue).message:',validateForm(invalidFormWithNonMatchingSelectValue).message );
.as-console-wrapper {max-height :100%!重要; top:0; }
/ strong>
这非常符合 @Bergi 昨天已经在他的一个评论中提及了。
请注意,OOP和FP是正交的,您可以轻松地将它们组合。
这里基于函数的解决方案满足两个将这些函数指定为其数据的对象。从现在开始,一个字段将被这些函数视为纯数据(如示例所示),但始终必须具有额外的类型
属性。
I wonder how to create polymorphism in functional programming. Lets take as example form class with different type of inputs Sample polymorh in JS es6:
class Form {
constructor(fields){
this.fields = fields;
}
validate() {
let err = null;
for(let f of this.fields) {
if (! field.validate()){
return field.getErr();
}
}
}
}
class TextField {
isNotEmpty() {
return this.value != ''
}
validate() {
return this.isNotEmpty()
}
}
class SelectField {
validate() {
if (! inArray(this.value, this.options) {
return 'value is not in the available options'
}
}
}
The code is for demonstration purposes only, dont look the syntax or the correct behavior.
I wonder how to create similar polymorhism in FP. In Haskell you can use pattern matching, but how to do it in javascript?
Some say that i can implement different functions with if statements:
if (field.type == 'text')...
else if (field.type == 'select')...
But this is bad because i should write all logic in one function. If i want to add new type of field (MultipleSelect for example) i should change the code inside the common funciton.
Is there better alternative in javascript?
The only approach I can think of, from what I got from the OP's provided example code, was a mapping of the currently processed form-field to field
-specific validation and error-handling functionality ... a working example code then looks like that ...
/**
* form and field type matching configuration tables/maps
*/
const validationTable = {
isValidFieldType: {
text: isValidTextField,
select: isValidSelectField,
//multiselect: ...
__invalid__: returnInvalidFieldValue
},
validateForm: validateForm
};
const createErrorTable = {
//form: createFormError,
field: {
text: createTextFieldError,
select: createSelectFieldError,
//multiselect: ...
__invalid__: handleCreateErrorException
}
};
/**
* helping getter functionality
* - that either returns a valid field type that does
* match a key in `validationTable.isValidFieldType`
* - or that does return the '__invalid__' key as it's
* fallback value.
*/
function getValidationFieldType(field) {
const fieldType = (field && field.type);
return (
(typeof fieldType === 'string')
&& (fieldType in validationTable.isValidFieldType)
&& fieldType
) || '__invalid__';
}
/**
* main validation functionality
* - that either returns `true` for an entirely valid form validation process
* - or that does return a type specific/related validation error.
*/
function validateForm(type) {
const tableOfIsValidFieldType = validationTable.isValidFieldType;
let recentField;
return Array.from(type.fields).every(field => {
recentField = field;
return tableOfIsValidFieldType[getValidationFieldType(field)](field);
}) || createErrorTable.field[getValidationFieldType(recentField)](/*recentField*/);
}
/**
* validation and error handling specific helper functionality
*/
function isValidTextField(type) {
return (type.value !== '');
}
function isValidSelectField(type) {
return Array.from(type.options).includes(type.value);
}
function returnInvalidFieldValue() {
return false;
}
function createTextFieldError(/*recentField*/) {
return (new Error('an empty text field value is not allowed.'));
}
function createSelectFieldError(/*recentField*/) {
return (new Error('the field value does not match the options'));
}
function handleCreateErrorException(/*recentField*/) {
return (new Error('there is no matching validation and error handling for this field.'));
}
/**
* test
*/
const validForm = { fields: [{
type: 'text',
value: 'valid'
}, {
type: 'select',
value: 'valid',
options: ['valid', 'select', 'field']
}] };
const invalidFormWithNullType = { fields: [{
type: 'text',
value: 'valid'
}, {
type: null,
value: 'valid'
}, {
type: 'select',
value: 'valid',
options: ['valid', 'select', 'field']
}] };
const invalidFormWithMissingType = { fields: [{
value: 'valid'
}, {
type: 'select',
value: 'valid',
options: ['valid', 'select', 'field']
}] };
const invalidFormWithEmptyTextValue = { fields: [{
type: 'text',
value: ''
}, {
type: 'select',
value: 'valid',
options: ['valid', 'select', 'field']
}] };
const invalidFormWithNonMatchingSelectValue = { fields: [{
type: 'text',
value: 'valid'
}, {
type: 'select',
value: 'invalid',
options: ['valid', 'select', 'field']
}] };
console.log('validateForm(validForm) : ', validateForm(validForm));
console.log('validateForm(invalidFormWithNullType).message : ', validateForm(invalidFormWithNullType).message);
console.log('validateForm(invalidFormWithMissingType).message : ', validateForm(invalidFormWithMissingType).message);
console.log('validateForm(invalidFormWithEmptyTextValue).message : ', validateForm(invalidFormWithEmptyTextValue).message);
console.log('validateForm(invalidFormWithNonMatchingSelectValue).message : ', validateForm(invalidFormWithNonMatchingSelectValue).message);
.as-console-wrapper { max-height: 100%!important; top: 0; }
Note
This pretty much also fits to what @Bergi yesterday already did mention in one of his comments.
Notice that OOP and FP are orthogonal, you can easily combine them.
Here a function based solution meets two objects that have these functions assigned as their's data. A field from now will be treated as pure data by these functions (as shown with the example) but always has to feature an additional type
property.
这篇关于函数式编程多态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!