Написание правильного пользовательского экземпляра для чтения
Привет товарищи Хаскеллерс,
Я изучаю Haskell с одного месяца и изо всех сил пытаюсь создать пользовательский экземпляр для чтения для личного типа данных.
Я следовал этому и соответствующей главе в Learn Yourself a Haskell, вот мой фрагмент кода.
data Position = Position (Absc,Ordn) deriving (Show)
instance Read (Position) where
readsPrec _ input =
let absc = List.filter (/='(') $ takeWhile (/=',')
ordn = List.filter (/=')') $ tail (dropWhile (/=',') )
in (\str -> Position ( (read (absc str) :: Int)
, (read (ordn str) :: Int) ) ) input
type Absc = Int
type Ordn = Int
Моя цель - разобрать вход "(1,3)"
вывести что-то вроде Position (1,3)
Я, однако, получаю следующие сообщения об ошибках:
• Couldn't match expected type ‘[Char]’
with actual type ‘[Char] -> [Char]’
• Probable cause: ‘takeWhile’ is applied to too few arguments
In the second argument of ‘($)’, namely ‘takeWhile (/= ',')’
In the expression: filter (/= '(') $ takeWhile (/= ',')
In an equation for ‘absc’:
absc = filter (/= '(') $ takeWhile (/= ',')
То же самое для функции ordn.
• Couldn't match expected type ‘[(Position, String)]’
with actual type ‘Position’
• In the expression:
(\ str
-> Position ((read (absc str) :: Int), (read (ordn str) :: Int)))
input
In the expression:
let
absc = filter (/= '(') $ takeWhile (/= ',')
ordn = filter (/= ')') $ tail (dropWhile (/= ','))
in
(\ str
-> Position ((read (absc str) :: Int), (read (ordn str) :: Int)))
input
In an equation for ‘readsPrec’:
readsPrec _ input
= let
absc = filter (/= '(') $ takeWhile (/= ',')
ordn = filter (/= ')') $ tail (dropWhile (/= ','))
in
(\ str
-> Position ((read (absc str) :: Int), (read (ordn str) :: Int)))
input
Кажется, что мой let
заявление не признает absc
а также ordn
как функции (или, по крайней мере, попробуйте применить их напрямую, в то время как я хочу определить их как частично примененные функции, чтобы применить их позже в параметре str
). Я также, вероятно, испортил Position
конструктор значений.
Я не знаком со стилем кодирования на Haskell, и, возможно, я использовал некоторые ключевые слова и инструменты, которые мне не совсем понятны. Не могли бы вы намекнуть, как написать это, чтобы это работало?
Заранее спасибо.
2 ответа
В вашем коде есть куча ошибок - я думаю, вы должны немного прочитать о разнице между $
а также .
это важно знать при обработке функций, большинство ваших ошибок связано с попыткой применить функцию к ее аргументу ($)
вместо объединения функций (.)
,
Это то, что я изменил ваш код, по крайней мере, для проверки типа - хотя я думаю, readsPrec
не должен сохранять исходный ввод, но оставшуюся строку после разбора сделано.
Исправление кода
instance Read Position where
readsPrec _ input =
let absc = filter (/='(') . takeWhile (/=',')
ordn = filter (/=')') . tail . dropWhile (/=',')
in [(Position ( read (absc input) :: Int
, read (ordn input) :: Int), input)]
Но видя это, я чувствую себя несчастным - разве не говорят, что Хаскелл абстрактный, ловкий и действительно выразительный. Давайте попробуем еще раз
убирать
instance Read Position where
readsPrec _ str = let ('(':absc,',':ordn') = break (==',') str
(ordn,')':str') = break (==')') ordn'
in [(Position (read absc, read ordn), str')]
намного лучше, мы понимаем, что в начале и в конце должны быть скобки, но все же немного громоздко.
используя существующий функционал
Знаю это Tuple
это уже примеры Read
instance Read Position where
readsPrec s str = [(Position x, rest) | (x,rest) <- readsPrec s str]
хорошо, но все же мы можем сделать лучше
Скажем, мы недавно немного поработали с кортежами и нашли очень удобный модуль Data.Bifunctor
это имеет функции first
а также second
преобразовать первый и второй компонент 2-кортежа (любой бифунктор на самом деле).
Мы можем упростить вышеупомянутое
instance Read Position where
readsPrec s = map (first Position) . readsPrec s
чистый и короткий.
С помощью show "(3,4)"::Position
возвращается Position (3,4)
, Большое спасибо за ваш подробный ответ. Я склонен путать $
а также .
обозначения, но после того, как я просмотрел документацию, стало ясно.