簡體   English   中英

創建一個返回在Haskell中該類型類的另一個實例的類型類

[英]Creating a typeclass that returns another instance of that typeclass in haskell

我正在嘗試創建一個系統以導出符號函數,但我遇到了一個問題:

我有一個表達式的類型類Exp ,它定義了一個派生函數:

class Exp e where 
    derivative :: (Exp d) => e -> d

我希望該類具有一些實例:

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編譯的結果是:

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實例,那么為什么它不能與類型匹配?

當你寫

class Exp e where 
    derivative :: (Exp d) => e -> d

您聲明Exp類中的任何類型e都應具有函數derivative :: e -> d 請注意,這里的e是一個非常特定的類,但是d只能說在Exp 這幾乎是任意類型。 因此,您嘗試定義一個函數,該函數在給定參數的情況下返回屬於Exp任意類型的值

取決於上下文,將d選擇留給編譯器,例如fromInteger 因此,您並不是說“對於每個e都有一個屬於Expd使得derivative將返回d ”,而是說“對於每個e 所有 d屬於Exp 所有 d都將使得derivative將返回d ”。 如果要說前者,則可能必須使用多參數化的類和函數依賴項(以指定輸出的類型由輸入的類型唯一地確定)。

如果我們將e替換為某些特定類型,則您正在嘗試實現以下內容:

derivative :: Exp d => Double -> d
derivative = (0::Double)

您無法執行此操作,因為並非所有Exp都是雙精度。 說, Operator Double Double (位於Exp )顯然不是Double 具有相同問題的更多人工示例:

derivative :: Double -> a
derivative = (0::Double)

有多種方法可以實現所需的行為,一種方法是使用FunctionalDependenciesMultiParamTypeClasses ,另一種方法是使用TypeFamilies ,如下所示:

{-# 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的實例時,實現中存在兩個錯誤:

  1. 嘗試構造一個無限類型
  2. derivative (f :* g)derivative (f :+ g)具有不同的返回類型。

但是,這是解決此問題的方法:

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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM