2014-02-20 2 views
5

У меня есть функция, которая выводит свойство booleanlike, заданное тип данных. Эта функция вычисляет свойство по шаблону на первый конструктор типа данных, так что-то вродеHaskell альтернатива длинному списку совпадений шаблонов?

data C = C1 | C2 | .. | Cn 

f :: C -> Bool 
f (C1 _ _ ... _) = True 
f (C2 _ _ ... _) = True 
f (C3 _ _ ... _) = False 
. 
. 
. 
f (Cn _ _ ..._) = False 

Есть ли более компактный способ для выполнения поиска по шаблону, или есть другой (и более компактный) путь о моей проверке собственности? Я предпочитаю не добавлять свойство к определению типа данных, так как оно может быть рассчитано с относительной легкостью.

ответ

8

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

f :: C -> Bool 
f x = case x of 
    C1 {} -> True 
    C2 {} -> False 
    ... 
    Cn {} -> False 

Это примерно так же компактно, как и без изменения типа данных.

+0

Я буду использовать это. Изменение моего типа данных приведет к большей потере эстетики в других местах. Теперь я не знал о синтаксисе записи и буду читать дальше. Благодаря! – Haxelaar

+0

Возможно, вы могли бы повернуть каждый из 'C1',' C2', 'C3' и т. Д. В _functions_, которые построят другой тип данных, который имеет структуру, которая проще в работе ... – MathematicalOrchid

-1

Возможно:

f (x _ _ ... _) = g x where 
    g C1 = True 
    g C2 = True 
    g C3 = False 
    . 
    . 
    . 
    g Cn = False 

Вы могли бы сэкономить немного набрав с помощью оператора выбора вместо этого, но не так много.

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

+2

Это не сработает, так как '(x _ ...)' не является допустимым шаблоном - если нет никаких подчеркиваний, и в этом случае этот способ делать что-то не дает вам ничего! – yatima2975

+0

@ yatima2975 Я предполагаю, что Клинтон принял данные C = C1 | C2 | .. | Cn' был довольно буквальным и что '_' были множественными аргументами, тогда как подпись типа для' f' указывает иначе. – AndrewC

+0

@AndrewC: Это имеет смысл, но тогда скобки ошибочны, или запятая в кортеже отсутствует :-). – yatima2975

6

Кроме того, просто перечислить True те или False из них, в зависимости от того, что у вас есть меньше, и сделать исход мажоритарных по умолчанию:

f C1{} = True 
f C42{} = True 
f _ = False     -- all others false 
+0

Хорошая идея, слишком плохо, свойство равномерно разделено.Я также форматировал определение типа данных для другого использования, иначе я мог бы определить тип данных таким образом, чтобы можно было сделать фантастическое использование класса Enum – Haxelaar

+6

@Haxelaar. Вы по-прежнему сохраняете не менее 50% предложений, если это распределяется равномерно. – Ingo

2

Вы можете захотеть взглянуть на toConstr in the Data.Data модуля. Это может дать вам представление конструктора, который вы можете проанализировать по своему усмотрению (т. Е. Преобразовать в String или получить индекс из).

1

Опираясь на ответ @ yatima, вы могли бы сделать что-то вроде этого

{-# LANGUAGE DeriveDataTypeable #-} 

import Data.Char 
import Data.Data 

data C = C1 Int 
     | C2 Int 
     | C3 Int 
     | C4 Int 
     deriving (Data,Typeable) 

f :: C -> Bool 
f c = let [_,n] = show (toConstr c) in digitToInt n < 3 

Тогда в GHCI

>> f (C1 0) 
True 
>> f (C2 0) 
True 
>> f (C3 0) 
False 
>> f (C4 0) 
False 
Смежные вопросы