Съпоставяне на шаблони в частен конструктор на данни

Пиша прост ADT за ос на мрежата. В моето приложение мрежата може да бъде или правилна (с постоянна стъпка между координатите), или неправилна (в противен случай). Разбира се, правилната решетка е само частен случай на неправилната, но може да си струва да ги разграничите в някои ситуации (например, за да извършите някои оптимизации). И така, декларирам моя ADT, както следва:

data GridAxis = RegularAxis (Float, Float) Float -- (min, max) delta
              | IrregularAxis [Float]            -- [xs]

Но не искам потребителят да създава деформирани оси с max < min или с неподреден xs списък. И така, добавям "по-интелигентни" функции за конструиране, които извършват някои основни проверки:

regularAxis :: (Float, Float) -> Float -> GridAxis
regularAxis (a, b) dx = RegularAxis (min a b, max a b) (abs dx)

irregularAxis :: [Float] -> GridAxis
irregularAxis xs = IrregularAxis (sort xs)

Не искам потребителят да създава мрежи директно, така че не добавям GridAxis конструктори на данни в списъка за експортиране на модули:

module GridAxis (
    GridAxis,
    regularAxis,
    irregularAxis,
    ) where

Но се оказа, че след като направих това, вече не мога да използвам съвпадение на шаблони на GridAxis. Опитвам се да го използвам

import qualified GridAxis as GA

test :: GA.GridAxis -> Bool
test axis = case axis of
              GA.RegularAxis -> True
              GA.IrregularAxis -> False  

дава следната грешка на компилатора:

src/Physics/ImplicitEMC.hs:7:15:
    Not in scope: data constructor `GA.RegularAxis'

src/Physics/ImplicitEMC.hs:8:15:
    Not in scope: data constructor `GA.IrregularAxis'

Има ли нещо, което да заобиколи това?


person firegurafiku    schedule 15.11.2015    source източник


Отговори (2)


Можете да дефинирате синоними на модел на конструктор. Това ви позволява да използвате едно и също име за интелигентна конструкция и „тъпо“ съвпадение на шаблони.

{-# LANGUAGE PatternSynonyms #-}

module GridAxis (GridAxis, pattern RegularAxis, pattern IrregularAxis) where
import Data.List

data GridAxis = RegularAxis_ (Float, Float) Float -- (min, max) delta
              | IrregularAxis_ [Float]            -- [xs]

-- The line with "<-" defines the matching behavior
-- The line with "=" defines the constructor behavior
pattern RegularAxis minmax delta <- RegularAxis_ minmax delta where
  RegularAxis (a, b) dx = RegularAxis_ (min a b, max a b) (abs dx)

pattern IrregularAxis xs <- IrregularAxis_ xs where
  IrregularAxis xs = IrregularAxis_ (sort xs)

Сега можете да направите:

module Foo
import GridAxis

foo :: GridAxis -> a
foo (RegularAxis (a, b) d) = ...
foo (IrregularAxis xs) = ...

И също така използвайте RegularAxis и IrregularAxis като интелигентни конструктори.

person András Kovács    schedule 15.11.2015

Това изглежда като случай на използване на модел синоними.

По принцип вие не експортирате истинския конструктор, а само "умен" такъв

{-# LANGUAGE PatternSynonyms #-}
module M(T(), SmartCons, smartCons) where

data T = RealCons Int

-- the users will construct T using this
smartCons :: Int -> T
smartCons n = if even n then RealCons n else error "wrong!"

-- ... and destruct T using this
pattern SmartCons n <- RealCons n

След това може да използва друг модул, импортиращ M

case someTvalue of
   SmartCons n -> use n

и напр.

let value = smartCons 23 in ...

но не може да използва RealCons директно.


Ако предпочитате да останете в основен Haskell, без разширения, можете да използвате "тип изглед"

module M(T(), smartCons, Tview(..), toView) where
data T = RealCons Int
-- the users will construct T using this
smartCons :: Int -> T
smartCons n = if even n then RealCons n else error "wrong!"

-- ... and destruct T using this
data Tview = Tview Int
toView :: T -> Tview
toView (RealCons n) = Tview n

Тук потребителите имат пълен достъп до типа изглед, който може да се конструира/унищожава свободно, но имат само ограничен начален конструктор за действителния тип T. Унищожаването на действителния тип T е възможно чрез преминаване към типа изглед

case toView someTvalue of
  Tview n -> use n

За вложените модели нещата стават по-тромави, освен ако не активирате други разширения като ViewPatterns.

person chi    schedule 15.11.2015