2015-11-16 3 views
1

Я пытаюсь написать удобную обертку для библиотеки hnetcdf. Вместо того чтобы иметь дело с его низкоуровневым интерфейсом, я хочу иметь возможность описать структуру файла NetCDF простым декларативным образом. Для достижения этой цели я создал кучу АТД:Цепочки параметров без круглых скобок в Haskell

data Info = Info FileInfo Dimentions Variables 
data FileInfo = FileInfo String Int 
data Dimentions = Dimentions [Dimention] 
data Variables = Variables [Variable] 
data Dimention = BoundedDimention String Int | UnboundedDimention String 
data Variable = Variable String Int NC.NcType [Dimention] 

Они работают, если я использую их, как в следующем примере:

writeNetCDF :: FilePath -> IO() 
writeNetCDF filename = do 
    let dimX, dimY, dimZ = ... 
    let var1, var2  = ... 
    let info = Info (FileInfo filename 1) 
        (Dimentions [dimX, dimY, dimZ]) 
        (Variables [var1, var2]) 
    ... 

, но я действительно не нравится дополнительные скобки. Я пытался использовать ($) и (.), но не повезло:

-- No way. 
    let info = Info $ FileInfo filename 1 
        $ Dimentions [dimX, dimY, dimZ] 
        $ Variables [var1, var2] 

Есть еще один способ кэрри параметров цепи?

+0

Для информации '' 'является право-ассоциативной. 'Info $ FileInfo filename 1 $ Dimentions [dimX, dimY, dimZ] $ Variables [var1, var2]' эквивалентно 'Info (FileInfo filename 1 (Dimentions [dimX, dimY, dimZ] (Variables [var1, var2]))) ', что вы не хотите. – Jubobs

ответ

4

Несомненно. Проблема $ в данном случае является то, что это правильно ассоциативно:

let info = Info $ FileInfo filename 1 
       $ Dimentions [dimX, dimY, dimZ] 
       $ Variables [var1, var2] 
     = Info (FileInfo filename 1 
        (Dimentions [dimX, dimY, dimZ] 
        (Variables [var1, var2]) 
       ) 
       ) 

Так все, что вам нужно, это оператор, который оставил ассоциативный:

($<) :: (a -> b) -> a -> b 
($<) = ($) 

infixl 0 $< -- left associative 

Теперь Скобки правильно:

let info = Info $< FileInfo filename 1 
       $< Dimentions [dimX, dimY, dimZ] 
       $< Variables [var1, var2] 
     = (
      (
      (Info 
       (FileInfo filename 1) 
      ) 
      (Dimentions [dimX, dimY, dimZ]) 
      ) 
      (Variables [var1, var2]) 
      ) 
+0

Является ли такой левоассоциативный оператор определенным в стандартной библиотеке? – Jubobs

+1

@Jubobs: [Не похоже, что он] (https://www.haskell.org/hoogle/?hoogle=%28a%20-%3E%20b%29%20-%3E%20a%20-% 3E% 20b). – Zeta

+0

@Jubobs: Мне тоже этого не удалось. Но если это так, его, вероятно, следует называть '€' или '¥'. – firegurafiku

0

Оба предложения let и where рассчитываются рекурсивно, поэтому у вас может быть что-то похожее:

where 
    info = Info f dim vars 
    f = FileInfo filename 1 
    dim = Dimentions [dimX, dimY, dimZ] 
    vars = Variables [var1, var2] 

$ оператор и оператор . используются для создания новой функции. Таким образом, под выражением:

info = Info $ FileInfo filename 1 
      $ Dimentions [dimX, dimY, dimZ] 
      $ Variables [var1, var2] 

говорит, что информация является тип конструктора, который принимает один аргумент, тип, возвращаемый тип FileInfo, который, как ожидается, займет три agruments (filename, 1 и все, что возвращается этой следующей функцией называется Dimentions) и так далее. Это совсем не то, что вы хотите.

Оператор . объединяет две функции вместе по математическому способу (f . g)(x), эквивалентен f(g(x)). И опять же, это никоим образом не похоже на то, что вы пытаетесь создать здесь.