首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建一个在haskell中返回该类型类的另一个实例的类型类

创建一个在haskell中返回该类型类的另一个实例的类型类
EN

Stack Overflow用户
提问于 2017-02-06 15:19:32
回答 2查看 101关注 0票数 2

我正在尝试创建一个系统来派生符号函数,我有一个问题:

我有一个表达式的类型类,Exp,它定义了一个派生函数:

代码语言:javascript
复制
class Exp e where 
    derivative :: (Exp d) => e -> d

我希望这个类有几个实例:

代码语言:javascript
复制
data Operator a b = a :* b | a :+ b

instance (Exp a, Exp b) => Exp (Operator a b)  where
    derivative (f :* g) = ((derivative f) :* g) :+ (f :* (derivative g)) --The derivative of the multiplication of two expressions 
    derivative (f :+ g) = derivative f :+ derivative g --The derivative of the addition of two expressions

instance Exp Double where
    derivative a = (0 :: Double)  --The derivative of a constant value is 0


instance Exp Char where
    derivative c = (1 :: Double) --The derivative of just a variable is one

我用ghci编译得到的结果是:

代码语言:javascript
复制
math.hs:19:21: error:
• Couldn't match expected type ‘d’ with actual type ‘Double’
  ‘d’ is a rigid type variable bound by
    the type signature for:
      derivative :: forall d. Exp d => Double -> d
    at math.hs:19:5
• In the expression: (0 :: Double)
  In an equation for ‘derivative’: derivative a = (0 :: Double)
  In the instance declaration for ‘Exp Double’
• Relevant bindings include
    derivative :: Double -> d (bound at math.hs:19:5)

math.hs:22:21: error:
• Couldn't match expected type ‘d’ with actual type ‘Double’
  ‘d’ is a rigid type variable bound by
    the type signature for:
      derivative :: forall d. Exp d => Char -> d
    at math.hs:22:5
• In the expression: (1 :: Double)
  In an equation for ‘derivative’: derivative c = (1 :: Double)
  In the instance declaration for ‘Exp Char’
• Relevant bindings include
    derivative :: Char -> d (bound at math.hs:22:5)

math.hs:28:27: error:
• Couldn't match expected type ‘d’
              with actual type ‘Operator (Operator a0 b) (Operator a b0)’
  ‘d’ is a rigid type variable bound by
    the type signature for:
      derivative :: forall d. Exp d => Operator a b -> d
    at math.hs:27:5
• In the expression: derivative f :+ derivative g
  In an equation for ‘derivative’:
      derivative (f :+ g) = derivative f :+ derivative g
  In the instance declaration for ‘Exp (Operator a b)’
• Relevant bindings include
    g :: b (bound at math.hs:28:22)
    f :: a (bound at math.hs:28:17)
    derivative :: Operator a b -> d (bound at math.hs:27:5)

我的问题是:为什么我的实例减速有问题?每个函数中的派生总是解析为derivative的类型约束所需的Exp实例,那么为什么它不能匹配该类型呢?

EN

回答 2

Stack Overflow用户

发布于 2017-02-06 15:48:13

当你写的时候

代码语言:javascript
复制
class Exp e where 
    derivative :: (Exp d) => e -> d

您声明Exp类中的任何类型e都应该有一个函数derivative :: e -> d。请注意,这里的e是一个非常具体的类,但据说d只在Exp中。它几乎是一个任意类型。因此,您正在尝试定义一个函数,该函数在给定参数的情况下,返回属于Exp的任意类型的值

with fromInteger一样,d的选择将根据上下文留给编译器。因此,您并不是说“对于每个e,都有一个属于Exp的代码,这样derivative将返回d",而是说”对于每个e,属于Exp的所有代码都使得derivative将返回<代码>D19“。如果要说前者,您可能必须使用多参数化类和函数依赖(以指定输出的类型由输入的类型唯一确定)。

如果我们将e替换为某个特定类型,您将尝试实现以下内容:

代码语言:javascript
复制
derivative :: Exp d => Double -> d
derivative = (0::Double)

这不是你能做的事情,因为并不是所有的Exp都是doubles。比方说,Operator Double Double (在Exp中)显然不是Double。甚至更多具有相同问题的人工示例:

代码语言:javascript
复制
derivative :: Double -> a
derivative = (0::Double)
票数 5
EN

Stack Overflow用户

发布于 2017-02-08 06:16:07

实现预期行为的方法有两种,一种是使用FunctionalDependenciesMultiParamTypeClasses,另一种是使用TypeFamilies,如下所示:

代码语言:javascript
复制
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
module Main where

class Exp e where
    type ResExp e :: * -- type family of resulting expression
    derivative :: (Exp (ResExp e)) => e -> ResExp e

instance Exp Double where
    type ResExp Double = Double
    derivative a = 0


instance Exp Char where
    type ResExp Char = Double
    derivative c = 1

但是当涉及到Operator的实例时,在实现中有两个bug:

  1. 尝试构造无限大的type
  2. derivative (f :* g)derivative (f :+ g)具有不同的返回类型。

这里有一个解决这个问题的方法:

代码语言:javascript
复制
data Mult a b = a :* b

data Plus a b = a :+ b

instance (Exp a, Exp b, Exp (ResExp a), Exp (ResExp b)) => Exp (Plus a b) where
    type ResExp (Plus a b) = (Plus (ResExp a) (ResExp b))
    derivative (f :+ g) = derivative f :+ derivative g


instance (Exp a, Exp b, Exp (ResExp a), Exp (ResExp b)) => Exp (Mult a b) where
    type ResExp (Mult a b) = Plus (Mult (ResExp a) b) (Mult a (ResExp b))
    derivative (f :* g) = ((derivative f) :* g) :+ (f :* (derivative g))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42062261

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档