说我有一个Request
对象:
{
user: { /* user data: username, email, etc. */ }
post: { /* post data: content, date, etc. */ }
}
Request
对象的示例:
{
user: {
id: '123'
username: 'kibe'
email: 'blabla@gmail.com'
}
post: {
content: 'my new post!'
date: '20/02/2004'
}
}
现在,我有两个功能:validateUser
和validatePost
。他们两个都返回一个Maybe
monad,因为它们可能会失败。
然后我该怎么做?
function savePost (request) {
return request
|> validateUser // if validateUser returns either Success(user) or Failure(error), how would I pass down the post?
|> validatePost
|> savePostToDb
|> ok
}
我是否应该创建由validateRequest
和validateUser
组成的函数validatePost
?但是,那我怎么只给post
对象呢?如果savePostToDb
也需要用户ID怎么办?
savePostToDb
希望这些问题是有道理的。我是FP的新手,虽然我了解FP的范例,但我无法设计一个简单的程序
谢谢!
答案 0 :(得分:1)
道具
我们编写了一个简单的 prop
函数,它可以安全地查找对象的属性。如果它们存在,我们得到一个 Just
-wrapped 值,否则我们得到 Nothing
-
const fromNullable = x =>
x == null
? Nothing
: Just(x)
const prop = k => t =>
fromNullable(t[k])
道具
虽然你有嵌套的属性,所以让我们使用props
-
const props = (k, ...ks) => t =>
ks.length
? prop(k)(t).bind(props(...ks))
: prop(k)(t)
验证
现在我们可以编写一个简单的 validate
协程 -
function* validate (t)
{ const id = yield props("user", "id")(t)
const username = yield props("user", "username")(t)
const email = yield props("user", "email")(t)
const post = yield props("post", "content")(t)
const date = yield props("post", "date")(t)
return Just({ id, username, email, post, date }) // <- Just(whateverYouWant)
}
const doc =
{ user:
{ id: '123'
, username: 'kibe'
, email: 'blabla@gmail.com'
}
, post:
{ content: 'my new post!'
, date: '20/02/2004'
}
}
coroutine(validate(doc)).bind(console.log)
我们看到一个有效的 doc
-
{
id: '123',
username: 'kibe',
email: 'blabla@gmail.com',
post: 'my new post!',
date: '20/02/2004'
}
如果文档无效,otherdoc
-
const otherdoc =
{ user:
{ id: '123'
, username: 'kibe'
, // <- missing email
}
, post:
{ content: 'my new post!'
, // <- missing date
}
}
coroutine(validate(otherdoc)).bind(console.log)
// no effect because validate returns a Nothing!
协程
coroutine
的实现很简单,最重要的是它对任何 monad 都是通用的 -
function coroutine (f)
{ function next (v)
{ let {done, value} = f.next(v)
return done ? value : value.bind(next)
}
return next()
}
也许
最后我们为 Nothing
和 Just
提供实现 -
const Nothing =
({ bind: _ => Nothing })
const Just = v =>
({ bind: f => f(v) })
演示
展开下面的代码片段以在您自己的浏览器中验证结果 -
const Nothing =
({ bind: _ => Nothing })
const Just = v =>
({ bind: f => f(v) })
const fromNullable = x =>
x == null
? Nothing
: Just(x)
const prop = k => t =>
fromNullable(t[k])
const props = (k, ...ks) => t =>
ks.length
? prop(k)(t).bind(props(...ks))
: prop(k)(t)
function coroutine (f)
{ function next (v)
{ let {done, value} = f.next(v)
return done ? value : value.bind(next)
}
return next()
}
function* validate (t)
{ const id = yield props("user", "id")(t)
const username = yield props("user", "username")(t)
const email = yield props("user", "email")(t)
const post = yield props("post", "content")(t)
const date = yield props("post", "date")(t)
return Just({ id, username, email, post, date })
}
const doc =
{user:{id:'123',username:'kibe',email:'blabla@gmail.com'},post:{content:'my new post!',date:'20/02/2004'}}
coroutine(validate(doc)).bind(console.log)
相关阅读
答案 1 :(得分:0)
是的,你应该创建 <img
src='www.awesomesite.com/awesomeImage.svg'
ref={el => this.imageRef = el}
onLoad={() => console.log(this.imageRef.src) }
/>
和一个 validateRequest
方法,它们会给你一个布尔值。然后,您可以使用这两种新方法简单地创建两个 Maybe-Functions 并将其组合在一起。看看我的例子,我会如何简单地做到这一点:
savePostToDb