Используйте совпавшее значение в конструкции case в Haskell - PullRequest
2 голосов
/ 24 октября 2011

Я сопоставляю шаблон с конструктором данных записи, и у меня есть следующий фрагмент кода:

colorFor shape = 
  case material shape of
    ColorMaterial -> material shape
    -- etc.

Проблема заключается в следующем: material - нетривиальный метод, и я 'Я хотел бы не пересчитать это в кейсе.Я знаю, что мог бы сделать что-то вроде:

colorFor shape = 
  let m = material shape
  in case m of
    ColorMaterial -> m

или

colorFor shape = 
  case material shape of
    ColorMaterial r g b -> ColorMaterial r g b

Но я не мог не подумать, что должен быть какой-то способ извлечь сопоставленное значение в сопоставлении с образцом.Это также подходит для определений функций, где я хотел бы сопоставить конструктор данных по какому-либо аргументу, не распаковывая его полностью.

К вашему сведению: я новичок в Haskell, и если есть более эффективные способы сделать эточто я делаю, я очень открыт для предложений.Любая помощь с благодарностью!

Ответы [ 2 ]

8 голосов
/ 24 октября 2011

Вы ищете " как шаблоны ":

data SomeDataType = ColorMaterial Int Int Int
                  | BlandMaterial

colorFor shape = 
  case material shape of
    res@(ColorMaterial _ _ _) -> res
    -- etc.
2 голосов
/ 24 октября 2011

Я не совсем уверен, что есть какой-то "лучший" способ сделать это, чем

colorFor shape =  
  let m = material shape 
  in case m of 
      ColorMaterial -> m 

В частности, глядя на то, что ghc делает с шаблоном "as", который Томас предложил запустить ghc -ddump-dsпоказывает, что ghc просто превращает это в let после десугарирования

 Main.colorFor :: forall t_ac9. t_ac9 -> Main.SomeDataType
 [LclId]
 Main.colorFor =
   \ (@ t_ac9) ->
     letrec {
       colorFor_ac8 :: t_ac9 -> Main.SomeDataType
       [LclId]
       colorFor_ac8 =
         \ (shape_aby :: t_ac9) ->
           **let** {
             res_abz :: Main.SomeDataType
             [LclId]
             **res_abz** =
               GHC.Err.undefined @ (t_ac9 -> Main.SomeDataType) shape_aby } in
           let {
             fail_dcV :: GHC.Prim.State# GHC.Prim.RealWorld -> Main.SomeDataType
             [LclId]
             fail_dcV =
               \ (ds_dcW :: GHC.Prim.State# GHC.Prim.RealWorld) ->
                 Control.Exception.Base.patError
                   @ Main.SomeDataType "Test.hs:(5,3)-(6,36)|case" } in
           case res_abz of wild_B1 {
             __DEFAULT -> fail_dcV GHC.Prim.realWorld#;
             **Main.ColorMaterial ds_dcS ds_dcT ds_dcU -> res_abz**
           }; } in
     colorFor_ac8

Это довольно многословно, но я пометил важные части <> .Не определено, конечно, потому что «материал» не существует в моем коде, и мне нужно было там для компиляции.Таким образом, As-Pattern лучше только тогда, когда есть только один из них.Еще, и тебе лучше сделать так, чтобы ты позволил себе.Меньше печатания и выглядит лучше imho.

Похоже, что в целом это также справедливо:

data SomeDataType = ColorMaterial Int Int Int 
                  | BlandMaterial 
                  | NoMaterial

colorFor shape =  
  case undefined shape of 
    res@(ColorMaterial _ _ _) -> res 
    foo@BlandMaterial         -> foo

просто вводит еще один let, и уже больше печатает, чем просто один let.

 Main.colorFor :: forall t_ace. t_ace -> Main.SomeDataType
 [LclId]
 Main.colorFor =
   \ (@ t_ace) ->
     letrec {
       colorFor_acd :: t_ace -> Main.SomeDataType
       [LclId]
       colorFor_acd =
         \ (shape_abz :: t_ace) ->
           let {
             **res_abA** :: Main.SomeDataType
             [LclId]
             **res_abA** =
               GHC.Err.undefined @ (t_ace -> Main.SomeDataType) shape_abz } in
           let {
             fail_dd0 :: GHC.Prim.State# GHC.Prim.RealWorld -> Main.SomeDataType
             [LclId]
             fail_dd0 =
               \ (ds_dd1 :: GHC.Prim.State# GHC.Prim.RealWorld) ->
                 Control.Exception.Base.patError
                   @ Main.SomeDataType "Test.hs:(6,3)-(8,36)|case" } in
           **let** {
             foo_abB :: Main.SomeDataType
             [LclId]
             **foo_abB** = res_abA } in
           case res_abA of wild_B1 {
             __DEFAULT -> fail_dd0 GHC.Prim.realWorld#;
             Main.ColorMaterial ds_dcX ds_dcY ds_dcZ -> res_abA;
             Main.BlandMaterial -> foo_abB
           }; } in
     colorFor_acd
...