Кажется, что я застрял в интересном краеугольном камне здесь. Это сложно объяснить, что я пытаюсь сделать, так что позвольте мне написать это в коде вместо:Принуждение фальшивого типа
data Foobar x =
Foo1 {field1 :: x, field2 :: String} |
Foo2 {field1 :: x, field3 :: Int} |
Foo3 { field4 :: Bool} |
Foo4 { field2 :: String, field4 :: Bool}
Как вы можете видеть, некоторые конструкторы зависят от x
, но другие этого не делают. Я пытаюсь написать функцию, аналогичную fmap
:
transform :: (x -> y) -> Foobar x -> Foobar y
transform fn foobar =
case foobar of
Foo1 {} -> foobar {field1 = fn (field1 foobar)}
Foo2 {} -> foobar {field1 = fn (field1 foobar)}
_ -> foobar
Как вы можете видеть, запись синтаксис аккуратно позволяет мне избежать необходимости перестраивать весь конструктор, применяя fn
только там, где это необходимо. К сожалению, это происходит, когда fn
необходим в ноль мест. В этом случае (т. Е. Конечная альтернатива) выражение не проверяет тип. Мне совершенно ясно почему это терпит неудачу - но я озадачен как исправить это.
Очевидно, я мог бы просто написать всю вещь долго. Это будет работать на этом сокращенном примере, но реальное приложение, которое я пытаюсь написать, намного больше. (Около 25 конструкторов, некоторые из них более 15 полей.)
Есть ли у кого-нибудь четкие идеи о том, как я могу исправить этот глюк?
Можете ли вы просто добавить 'получение Functor' и позволить компилятору написать для вас все 25 случаев? –
@ DanielWagner Реальный тип имеет несколько параметров типа - и я намерен написать одну функцию 'transform' для каждого параметра. Я не знаю, как это получить. – MathematicalOrchid
[Этот вопрос] (http://stackoverflow.com/q/4069840/485115) может вас заинтересовать. –