使函数成为矢量类型类的一个实例 [英] Make functions an instance of vector type class

查看:113
本文介绍了使函数成为矢量类型类的一个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于数学向量的自定义类型类

$ $ p $ {code> { - #LANGUAGE MultiParamTypeClasses,FlexibleInstances# - }

class Vector va其中

infixl 6 +
(< +>):: v - > v - > v - 矢量添加

infixl 6 - < - >
(< - >):: v - > v - > v - 矢量减法

infixl 7 *>
(*>):: a - > v - > v - 乘以标量

dot :: v - > v - > a - 内部产品

我想让数字 a 和函数 a - > vector 到类的一个实例中。数字很​​简单:

 实例Num a =>向量aa其中
(+)=(+)
( - )=( - )
(*>)=(*)
点=(*)

我认为函数也很容易(除了<$ c

$ p $ 实例Vector bc =>向量(a - > b)c其中
f + g = \ a - > f a + g a
f< - > g = \ a - > f a< - > g a
c *> f = \ a - > c *> fa
dot = undefined

然而,我得到以下错误:

 约束中的歧义类型变量`a0':由于使用'+'引起的
(向量b a0)
可能的修复:添加修复这些类型变量的类型签名
在表达式中:fa&+> g a
在表达式中:\ a - > f a + g a
在'+'的等式中:f + g = \ a - > f a + ga

如何告诉GHC该实例对全部类型有效 A ?在哪里我应该添加类型签名?

解决方案

类型系列绝对是解决这个问题的最可爱的方式

  { - #LANGUAGE TypeFamilies,FlexibleContexts# - } 
class VectorSpace v其中
类型字段v

infixl 6 +
(< +>):: v - > v - > v - 矢量添加

infixl 6 - < - >
(< - >):: v - > v - > v - 矢量减法

infixl 7 *>
(*>):: Field v - > v - > v - 乘以标量

dot :: v - > v - > Field v - 内部产品

在数学上,为了使函数中的向量空间不用,必须重用同样的字段:

 实例VectorSpace b => VectorSpace(a  - > b)其中
类型字段(a - > b)=字段b
f + g = \ a - > f a + g a
f< - > g = \ a - > f a< - > g a
c *> f = \ a - > c *> f a
dot =错误无法定义函数上的点积,抱歉。

...关于类型系列的好处在于,它们的工作方式非常多,您将如何解释。
我们做两个向量空间的直接结果:

pre $ $ $ $ $ $ $>实例(VectorSpace v,VectorSpace w,Field v_Field w,Num(字段v))=> VectorSpace(v,w)其中
type Field(v,w)= Field v
(v,w)+ (v',w')=(v + v',w + w')
(v,w) (v',w')=(v→v',w→w')
c *> (v,w)=(c *> v,c *> w)
(v,w)`dot`(v',w')=(v`disk`v')+ `dot` w')

您可以替换 Num context与一个自定义的代数类,但 Num 适当地捕获了字段的概念


I have a custom type class for mathematical vectors

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

class Vector v a where

    infixl 6 <+>
    (<+>) :: v -> v -> v  -- vector addition

    infixl 6 <->
    (<->) :: v -> v -> v  -- vector subtraction

    infixl 7 *>
    (*>)  :: a -> v -> v  -- multiplication by a scalar

    dot   :: v -> v -> a  -- inner product

and I want to make numbers a and functions a -> vector into an instance of the class. Numbers are easy:

instance Num a => Vector a a where
    (<+>) = (+)
    (<->) = (-)
    (*>)  = (*)
    dot   = (*)

and I thought functions would also be easy (well, except for dot, but I can live with that)

instance Vector b c => Vector (a -> b) c where
    f <+> g = \a -> f a <+> g a
    f <-> g = \a -> f a <-> g a
    c *>  f = \a -> c *> f a
    dot     = undefined

However, I get the following error:

Ambiguous type variable `a0' in the constraint:
  (Vector b a0) arising from a use of `<+>'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: f a <+> g a
In the expression: \ a -> f a <+> g a
In an equation for `<+>': f <+> g = \ a -> f a <+> g a

How can I tell GHC that the instance is valid for all types a? Where am I supposed to add the type signature?

解决方案

Type families are definitely the loveliest way of solving this problem

{-# LANGUAGE TypeFamilies, FlexibleContexts #-} 
class VectorSpace v where
    type Field v

    infixl 6 <+>
    (<+>) :: v -> v -> v  -- vector addition

    infixl 6 <->
    (<->) :: v -> v -> v  -- vector subtraction

    infixl 7 *>
    (*>)  :: Field v -> v -> v  -- multiplication by a scalar

    dot   :: v -> v -> Field v  -- inner product

Mathematically, to make a vector space out of functions, you have to reuse the same field:

instance VectorSpace b => VectorSpace (a -> b) where
    type Field (a -> b) = Field b
    f <+> g = \a -> f a <+> g a
    f <-> g = \a -> f a <-> g a
    c *>  f = \a -> c *> f a
    dot     = error "Can't define the dot product on functions, sorry."

...and the nice thing about type families is that they work very much how you would explain. Let's make the direct product of two vector spaces:

instance (VectorSpace v,VectorSpace w, Field v ~ Field w,Num (Field v)) => VectorSpace (v,w) where
    type Field (v,w) = Field v
    (v,w) <+> (v',w') = (v <+> v',w <+> w')
    (v,w) <-> (v',w') = (v <-> v',w <-> w')
    c *> (v,w) = (c *> v, c*> w)
    (v,w) `dot` (v',w') = (v `dot` v') + (w `dot` w')

You could replace the Num context with a custom algebraic class, but Num captures the concept of a Field moderately well.

这篇关于使函数成为矢量类型类的一个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆