2017-06-21 79 views
0

我創建了一些函數來獲得2D幾何的一些舒適。 在這個例子中我使用Geom2D from CubicBezier packageHaskell:約束中的非類型變量參數

我的程序的

完整代碼:https://gist.github.com/nskeip/3784d651ac646a67c5f246f048949af4

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts #-} 
import Geom2D 

left :: (Num a) => Point a -> a -> Point a 
left (Point x y) n = Point (x - n) y 

right :: (Num a) => Point a -> a -> Point a 
right (Point x y) n = Point (x + n) y 

up :: (Num a) => Point a -> a -> Point a 
up (Point x y) n = Point x (y - n) 

down :: (Num a) => Point a -> a -> Point a 
down (Point x y) n = Point x (y + n) 

他們的工作是這樣的:

> (Point 0 0) `up` 10 
Point 0.0 -10.0 

Point這樣定義:

data Point a = Point { 
    pointX :: !a, 
    pointY :: !a 
    } deriving (Eq, Ord, Functor, Foldable, Traversable) 

一切都還順利,直到我心想:「嘿,這個功能會很好S(actualy,運營商)與像Line thigs工作 - 不僅Point

所以我聲明一個類(不採取leftright保持thigs簡單):

class Num n => Moving p n where 
    up' :: n -> p -> p 
    down' :: n -> p -> p 

    up' n = down' (-n) 
    down' n = up' (-n) 

併爲Moving實例Point a數據類型:

instance Num a => Moving (Point a) a where 
    up' n (Point x y) = Point x (y - n) 

但是當我嘗試使用它,我得到了一個錯誤:

✗ ghci ./uno.hs 
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help 
[1 of 1] Compiling Main    (uno.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> let p = Point { pointX = 0, pointY = 0 } 
*Main> up' 10 p 

<interactive>:3:1: 
    Non type-variable argument in the constraint: Moving (Point a) n 
    (Use FlexibleContexts to permit this) 
    When checking that ‘it’ has the inferred type 
     it :: forall n a. (Num a, Moving (Point a) n) => Point a 

而讓我困惑的事情是:我把FlexibleContexts編譯指向了編譯列表中的頭部,但ghcu仍然建議我將它包含在內。

如何修復我的類/實例以獲取參數多態性的工作? :)

+1

但它可能不在'ghci'中,你應該用'ghci -XFlexibleContexts file.hs'運行它。 –

回答

1

And the thing that confuses me much: I put the FlexibleContexts pragma to the pragma listing in the head, but ghcu still suggest me to get it included.

這隻能啓用模塊本身的擴展。要在GHCi中編寫此代碼,您需要在GHCi中啓用擴展::set -XFlexibleContexts

但這只是問題的一部分。它看起來像你的類p應該確定n:你只能移動一個Point a上下a,對吧?但就目前而言,沒有什麼能夠阻止你定義更多的Moving (Point a) SomeOtherType實例,編譯器不會假設你不會。因此推斷類型中的an完全無關,您希望它們相同。這可以通過添加FunctionalDependencies extension和改變類聲明中被固定地說

class Num n => Moving p n | p -> n where 

這意味着恰好有不能與同一p和不同n實例。

我認爲這足以讓它工作。該代碼仍然是欠定的,因爲它允許任何數字a,但違約規則將選擇Integer

+0

謝謝!我會盡量使用你的解決方案。 –

+0

是的,FunctionalDependencies和FlexibleContents是神奇的:) –

相關問題