Соответствие паттерну Хаскелла охранникам - PullRequest
0 голосов
/ 26 сентября 2018

Предположим, что я хочу смоделировать древовидную структуру в Haskell с

data Tree = Null | Node Tree Integer Tree deriving Show

, и я хотел бы проверить, если каждая запись, скажем, меньше 10. Я подумал, что буду использовать сопоставление с образцом и запись

isSmall :: Tree -> Bool
isSmall _ 
  | Null = True
  | (Node a b c) = if b >= 10
                   then False
                   else isSmall a && isSmall c

Однако выдает ошибки о том, что a, b и c находятся вне области видимости.Я бы подумал, что, поместив их в охранники, в основном поместил бы их в прицел.Разве это не то, как вы должны делать сопоставление с образцом в Haskell?Я искал примеры, которые могли бы помочь мне, но я не нашел примеров сопоставления с образцом у охранников, которые используют структуру данных, состоящую из нескольких других структур данных.

Ошибка:

test.hs:24:6: Not in scope: data constructor ‘Node’

test.hs:24:11: Not in scope: ‘a’

test.hs:24:13: Not in scope: ‘b’

test.hs:24:15: Not in scope: ‘c’

test.hs:24:27: Not in scope: ‘b’

test.hs:26:38: Not in scope: ‘a’

test.hs:26:57: Not in scope: ‘c’

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Разве это не то, как вы должны выполнять сопоставление с шаблоном в Haskell?

Нет.Охранники - это логические выражения, а не шаблоны.

Вы можете выполнить сопоставление с шаблоном следующим образом:

isSmall :: Tree -> Bool
isSmall Null = True
isSmall (Node a b c) = b < 10 && isSmall a && isSmall c

... или вот так:

isSmall :: Tree -> Bool
isSmall x = case x of
  Null -> True
  Node a b c -> b < 10 && isSmall a && isSmall c

...или даже так:

{-# LANGUAGE LambdaCase #-}

isSmall :: Tree -> Bool
isSmall = \case
  Null -> True
  Node a b c -> b < 10 && isSmall a && isSmall c

(используя расширение языка LambdaCase ).Возможно, это наиболее близко к вашей первоначальной попытке.

Тем не менее, можно встроить шаблоны в охрану, используя <-.Это известно как «паттерн охранников»:

isSmall :: Tree -> Bool
isSmall x 
  | Null <- x = True
  | Node a b c <- x = b < 10 && isSmall a && isSmall c

Однако этот синтаксис здесь не особо вам подходит.Вы все еще должны дать аргументу имя (x в данном случае), и вы должны явно сказать <- x везде.Было бы более понятно использовать непосредственное сопоставление с образцом (используя case или уравнения нескольких функций).

0 голосов
/ 26 сентября 2018

Как указано в комментариях, это неверное сопоставление с образцом.Вот один из способов достичь того, что вы, похоже, ищете:

isSmall :: Tree -> Bool
isSmall Null         = True
isSmall (Node a b c) = if b >= 10
                       then False
                       else isSmall a && isSmall c

Вы также получаете другую ошибку, выполнив ее так, как вы указали в вопросе:

* Couldn't match expected type `Bool' with actual type `Tree'
* In the expression: (Node a b c)
  In a stmt of a pattern guard for
                 an equation for `isSmall':
    (Node a b c)
  In an equation for `isSmall':
      isSmall _
        | Null = True
        | (Node a b c) = if b >= 10 then False else isSmall a && isSmall c

Это указывает начто выражение внутри операторов защиты должно иметь тип Bool, но вы предоставляете Tree (либо Null, либо Node).

...