2013-05-02 2 views
0

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

def encode(tree : Tree, text: String):String = { 
    def rec(tree: Tree, text:String, result:String):String = ??? 

    rec(tree, text, "") 
} 

Я хочу упростить это в:

def encode(tree : Tree, text: String)(implicit result:String = ""):String 

это может удалить внутреннее определение функции, но у него есть проблема, что посмотреть, если мне нужно вызвать функцию lookup внутри encode и lookup также принимает неявный параметр типа String, implicit result:String = "" неявно переходит к функции lookup.

def lookup(tree : Tree, text: String)(implicit result:String = ""):String 

Я не хочу, чтобы это произошло, есть способ ограничить неявный параметр в lookup от решения вне этой функции? Или другие лучшие идеи?

+1

Моя интуиция подсказывает мне, что это не хорошее использование неявных списков параметров ... К сожалению, я не могу объяснить или оправдывать интуицию. –

+0

@ RandallSchulz Martin использовал этот шаблон в PIS 2nd P494. Пример 'maxListImpParm', в основном это означает, что у метода есть дополнительная информация, которую я хочу передать, здесь информация является аккумулятором. Проблема здесь, не в этом шаблоне, это происходит везде, где у вас есть неявные параметры, это просто передается неявно, иногда это противоречит моему намерению, если «lookup» не определен мной, я, возможно, не знал, этот параметр когда-либо проходил к нему. – Sawyer

ответ

2

Как об использовании нормальный аргумент по умолчанию, а и переходя затем аккумулятор явно в реализации:

def encode(tree : Tree, text: String, result : String = ""): String = { 
    //snip 
    encode(new_tree, new_text, new_result) 
} 

// call 
encode(my_tree, my_text) 
+0

Я думал, что аргумент по умолчанию нельзя опустить.Моя ошибка ~ – Sawyer

+0

@Sawyer В чем смысл иметь аргумент по умолчанию? – gzm0

+0

Дело в том, что вызывающий API не имеет источника питания, и метод может быть рекурсивным без вспомогательной функции. – Sawyer

0

Считаете ли вы, что в этом сценарии явно указано неявное значение lookup. Как так:

def encode(tree : Tree, text: String)(implicit result:String = ""):String = { 
    lookup(tree, text)("other string") 
} 
+0

Я могу это сделать, но одна из целей неявного аргумента для 'lookup' заключается в том, чтобы позволить ему вызываться без второго списка параметров, а также не должна, иначе я просто определяю его как обычный параметр. В настоящее время я сделал то же, что и вы, просто задаюсь вопросом, есть ли лучший подход. – Sawyer

0

Ваша идея хороша, но использование неявных параметров такого общего типа не рекомендуется, чтобы не наткнуться в конфликт неявного определения (например, слишком много неявных Strings видимых в Вашей области).

IIRC, книга Мартина конкретно упоминает такие проблемы.

Можно определить явный класс Wrapper иерархии вокруг String, чьи изменения для каждого конкретного метода

abstract class Wrapper[A](value: A) { def apply(): A = value } 

case class EncodeWrapper[A](value: A) extends Wrapper(value) 
case class LookupWrapper[A](value: A) extends Wrapper(value) 

def encode(tree : Tree, text: String)(implicit result: EncodeWrapper[String] = EncodeWrapper("")):String 

def lookup(tree : Tree, text: String)(implicit result: LookupWrapper[String] = LoodupWrapper("")):String 

с Очевидным недостатком, что вам нужно «обернуть/разворачивать» Строку в теле метода типа.

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

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

Смежные вопросы