2013-03-14 1 views
7

Предположим, у меня есть функция, которая выполняет некоторые вычисления с несколькими шаблонами; реализуется в виде сопоставления с образцом.Предоставляет ли Haskell выражение let для множественных совпадений шаблонов?

Большинство этих шаблонов (наряду с другими вещами, отличными друг от друга) обрабатывают параметр, для которого я использую промежуточную переменную в выражении let. Но на самом деле я считаю, что на многих шаблонах одинаково let, и мне интересно, есть ли способ определить let для нескольких шаблонов?

Вот пример моих дублируются let:

data MyType a = Something a | Another Int [a] 

myFunc (Something x) = -- return something, this isn't the point here 
myFunc (Another 0 xs) = 
    let intermediary = some $ treatment xs 
    in doSthg intermediary 1 
myFunc (Another 1 (x:xs)) = 
    let intermediary = some $ treatment xs 
    in doSthg1 intermediary 1 x 
myFunc (Another 2 (x:x':xs)) = 
    let intermediary = some $ treatment xs 
    in doSthg2 intermediary 2 x x' 

Вы можете увидеть, что параметр xs всегда присутствует, когда я использую его для intermediary, и это может быть факторизуются. Этого легко достичь с помощью вспомогательной функции, но мне было интересно, возможно ли то, что я прошу, без него. Пожалуйста, постарайтесь сделать его простым для новичков, и я надеюсь, что мой пример достаточно ясен.

+2

Nope! Необходимо использовать отдельную функцию и передать ее как параметр явно, чтобы отменить повторный код. Что касается Haskell, вышеупомянутые вхождения 'xs' - это совершенно разные переменные (потому что они имеют разные сайты привязки). – luqui

+0

Спасибо! Теперь у меня есть другой вопрос: вы предполагали, что третье и четвертое уравнения никогда не совпадают? Потому что 'xs' соответствует любому списку ... Вы изменили порядок уравнений? – yatima2975

+0

Я написал это, чтобы проиллюстрировать, что 'xs 'извлекается из сопоставления шаблонов в нескольких шаблонах, но не всегда имеет одинаковое значение (иначе совпадение шаблонов не будет интересоваться: будет только один шаблон). То, что сделано с ним в этом примере, не важно; но в моем коде 'y' заменяется реальными значениями, поэтому последующие шаблоны совпадают. Но вы снова правы, поэтому я отредактирую его с конкретным типом, чтобы все это стало понятным. –

ответ

7

Это частности проблему можно обойти следующим образом:

myFunc2 (Something x) = returnSomething x 
myFunc2 (Another n ys) = 
    let xs = drop n ys 
     x = head ys 
     x' = head (tail ys) 
     intermediate = some $ treatment xs 
    in case n of 
     0 -> doSomething intermediate n 
     1 -> doSomething1 intermediate n x 
     2 -> doSomething2 intermediate n x x' 

Благодаря ленивым вычислениям x и x' будет оцениваться только тогда, когда требуется их значение.

Однако - и это большой, однако! - ваш код даст ошибку во время выполнения при попытке вызвать myFunc2 (Another 2 []) (и если doSomething2 фактически использует x!), потому что, чтобы узнать, что такое x, нам нужно оценить head ys - и это приведет к сбою за пустой список. Код, который вы указали в качестве примера, также не будет работать (другая ошибка времени выполнения) для Another 2 [], так как не существует соответствующего шаблона, но там легче обеспечить падение.

Возможно, это не проблема, если вы контролируете ввод и всегда убедитесь, что список в Another достаточно длинный, но важно знать об этой проблеме!

+0

Это действительно не проблема в моем коде, потому что объекты 'Another' не могут быть созданы с пустыми списками. +1, это очень трюк –

+0

@tehinternetsismadeofcatz: вся проблема имеет сильный «интерпретатор для языка стека» - чувствуйте к ней, поэтому, если вы скомпилируете право, вы будете работать правильно - система типа просто не (но он близок!) достаточно силен, чтобы выразить то, что вы * знаете * о входных данных. Вы также можете подумать об изменении своего «MyType», чтобы более четко выразить то, что вы знаете о аргументах, но это большая работа ... – yatima2975