据我所知,仿函数是两个类别之间的映射,例如从C http://mathurl.com/32qch9w.png中的对象到D http://mathurl.com/36b8r37.png中的对象,其中C http://mathurl.com/32qch9w.png和D http://mathurl.com/36b8r37.png是类别.
在Haskell中有Hask,其中对象是Haskell类型,而态射是Haskell函数.但是,Functor
类型类有一个函数fmap
,它在这些类型之间进行映射(因此它们是对象而不是类别本身):
fmap :: (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
f a
并且f b
都是Hask中的对象.这是否意味着Functor
Haskell中的每个实例都是一个endofunctor,如果不是Functor
真的代表一个仿函数?
我在这里错过了什么?类型也是Haskell中的类别吗?
我一直在学习函数式编程,并且遇到了Monads,Functors和Applicatives.
根据我的理解,以下定义适用:
a)(A => B)=> C [A] => C [B] | 函子
b)(A => C [B])=> C [A] => C [B] | 单子
c)(C [A => B])=> C [A] => C [B] | 合用的
(参考:https://thedet.wordpress.com/2012/04/28/functors-monads-applicatives-can-be-so-simple/)
此外,我了解Monad是Functor的一个特例.在中,它应用一个函数,该函数将包装值返回到包装值并返回包装值.
当我们使用时Promise.then(func)
,我们传递Promise(即C [A])一个通常具有签名A => B
并返回另一个Promise(即C [B])的函数.所以我的想法是,Promise只是一个Functor而不是Monad,因为func
返回B而不是C [B].
然而,谷歌搜索我发现Promise不仅是一个Functor,也是一个Monad.我想知道为什么,因为func
不会返回包裹值C [B]但只是B.我错过了什么?
javascript monads functional-programming functor es6-promise
想要将boost :: bind传递给期望普通函数指针(相同签名)的方法.
typedef void TriggerProc_type(Variable*,void*);
void InitVariable(TriggerProc_type *proc);
boost::function<void (Variable*, void*)> triggerProc ...
InitVariable(triggerProc);
error C2664: 'InitVariable' : cannot convert parameter 1 from
'boost::function<Signature>' to 'void (__cdecl *)(type *,void *)'
Run Code Online (Sandbox Code Playgroud)
我可以避免存储boost :: function并直接传递绑定的functor,但后来我得到类似的错误:
error C2664: 'blah(void (__cdecl *)(type *,void *))' : cannot convert parameter
1 from 'boost::_bi::bind_t<R,F,L>' to 'void (__cdecl *)(type *,void *)'
Run Code Online (Sandbox Code Playgroud) "类似的论点也表明,满足第一定律的任何Functor实例(fmap id = id)也会自动满足第二定律.实际上,这意味着只需要检查第一定律(通常通过非常简单的归纳法)确保Functor实例有效."
如果是这种情况,为什么我们甚至提到第二个仿函法?
Law 1: fmap id = id
Law 2: fmap (g . h) = (fmap g) . (fmap h)
Run Code Online (Sandbox Code Playgroud) 我遇到了一种情况,我的代码将受益于使用Functor
和Applicative
类似的抽象,但对于类型的类型(* -> *) -> *
.定义一个更高级的仿函数可以RankNTypes
像这样完成
class HFunctor f where
hfmap :: (forall x. a x -> b x) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
但更高级的版本Applicative
有点棘手.这是我能想到的最好的:
class HFunctor f => HApplicative f where
hpure :: (forall x. a x) -> f a
(<**>) :: f (a :-> b) -> f a -> f b
newtype (:->) a b x = HFunc (a x -> b x)
infixr 5 :->
Run Code Online (Sandbox Code Playgroud)
我们需要:-> …
也许我错过了一些明显的东西,但我正在尝试清理一个使用Scalaz 7的项目中的一些样板,而我找不到一个看似非常简单且可能有用的特殊拼图.
假设我们有两种类型的双射:
case class Foo(x: Int)
case class Bar(i: Int)
import scalaz._, Scalaz._, BijectionT._
val fb: Foo <@> Bar = bijection[Id, Id, Foo, Bar](
foo => Bar(foo.x),
bar => Foo(bar.i)
)
Run Code Online (Sandbox Code Playgroud)
现在假设我们发现我们需要List[Foo]
和之间的双射List[Bar]
.我们可以轻松编写一个提供此功能的隐式类(实际上我们也可以使它适用于任何仿函数):
implicit class BijectionLifter[A, B](val bij: A <@> B) extends AnyVal {
def liftInto[F[_]: Functor]: F[A] <@> F[B] = bijection[Id, Id, F[A], F[B]](
_ map bij.to,
_ map bij.from
)
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是bimap
Haskell的直接翻译Data.Bijection
.Scalaz的双射也有一个名为的方法bimap
,但它有一个更繁忙的类型,似乎没有以任何明显的方式做我想要的.
现在我们可以写下面的内容:
fb.liftInto[List]
Run Code Online (Sandbox Code Playgroud)
我们得到了我们需要的双射.
我是否遗漏了一些抽象,这使得我可以用Scalaz 7中已经提供的用于双射的函数和实例更清晰地编写它?
class foo {
public:
bool operator () (int & i) {
return true;
}
};
int main() {
foo(WhyDoesThisCompile);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当传递WhyDoesThisCompile
(没有空格)到仿函数时,程序编译.
为什么是这样?我在clang 4.0.0上测试过它.
我理解了<$>
类型签名背后的原因,因为它只是一个中缀版本fmap
,但是将它与>>=
类型签名相比较,它对我来说没什么意义.
让我们首先确定我的意思.
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(<$>) :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
查看类型签名,我们可以看到>>=
左边是一个值,右边是一个函数,如果考虑它的链接属性,这很有意义:foo >>= bar >>= baz
这使我想知道,你为什么不<*>
和<$>
做到这一点?你不能写,foo <*> bar <*> baz
因为它需要输出foo <*> bar
是一个函数,而不是一个值.
我知道<**>
并=<<
存在这两个参数的顺序,允许我做类似的事情: …
如果要从数据结构中提取元素,则必须提供其索引.但索引的含义取决于数据结构本身.
class Indexed f where
type Ix f
(!) :: f a -> Ix f -> Maybe a -- indices can be out of bounds
Run Code Online (Sandbox Code Playgroud)
例如...
列表中的元素具有数字位置.
data Nat = Z | S Nat
instance Indexed [] where
type Ix [] = Nat
[] ! _ = Nothing
(x:_) ! Z = Just x
(_:xs) ! (S n) = xs ! n
Run Code Online (Sandbox Code Playgroud)
二叉树中的元素由一系列方向标识.
data Tree a = Leaf | Node (Tree a) a (Tree a)
data TreeIx = …
Run Code Online (Sandbox Code Playgroud) functor ×10
haskell ×6
applicative ×2
c++ ×2
monads ×2
bijection ×1
boost ×1
compilation ×1
es6-promise ×1
javascript ×1
math ×1
parameters ×1
scala ×1
scalaz ×1
scalaz7 ×1