Для аппликативного экземпляра требуется 1 И 0 аргументов

Я прошел через «Изучай себя на Haskell» и пытаюсь реализовать задачу «Хитроу в Лондон» [1] монадическим способом (вместо сгибов или явных рекурсий). [1] http://learnyouahaskell.com/functionally-solving-problems#heathrow-to-london

Мой вопрос таков: и instance Applicative Route where, и instance Applicative Route a where заставляют GHC жаловаться, как показано ниже. Таким образом, включение параметра типа является неправильным, но не включение также является неправильным. Как мне преодолеть это путем минимального изменения кода (его идеи реализации)? См. реализацию ниже ошибки GHC.

Prelude> :r
[1 of 1] Compiling Main             ( heathrowToLondon.hs, interpreted )

heathrowToLondon.hs:70:10: error:
    • Expecting one fewer argument to ‘Applicative Route’
      Expected kind ‘k0 -> Constraint’,
        but ‘Applicative Route’ has kind ‘Constraint’
    • In the instance declaration for ‘Applicative Route a’
Failed, modules loaded: none.
Prelude> :r
[1 of 1] Compiling Main             ( heathrowToLondon.hs, interpreted )

heathrowToLondon.hs:70:10: error:
    • The type synonym ‘Route’ should have 1 argument, but has been given none
    • In the instance declaration for ‘Applicative Route’
Failed, modules loaded: none.

Моя реализация была такой: подумайте о каждой улице (одна улица выше, одна улица ниже и пересекающий проспект) как Street, затем подумайте о Route как обо всем маршруте до сих пор, а также о совокупных затратах на переход Up или Down дальше. Тогда mempty или pure для Route будет что-то вроде ([], (0,0)). Мы определяем бинарную операцию от join до Route, затем мы можем получить >=, используя fmap и join. Частичный код ниже:

{-# LANGUAGE TypeSynonymInstances #-} 

import Data.List
import Data.List.Extra (chunksOf)
import Control.Monad

-- Try this:
-- solvePath [50, 10, 30, 5, 90, 20, 40, 2, 25, 10, 8]

data Path = Up | Down deriving (Show, Eq, Read)
type Costs a = (a, a)
type Street a = [a]
type Route a = ([Path], Costs a)

-- Monadic!?
toRoute :: (Num a, Ord a) => Street a -> Route a
toRoute [x,y,z] = ([], (min x (y+z), min y (x+z)))
toRoute _ = ([], (0,0))

instance Applicative Route where -- putting or not putting this `a` here doesn't work
  pure x = toRoute x -- turns [1,2,5] Street value 
  f <*> g = undefined


-- Irrelevant to this question but does the job
-- Using explicit recursion
solvePath :: (Num a, Ord a) => Street a -> [Path]
solvePath xs = reverse . crossStreet (0,0) [] $ 0:xs

crossStreet :: (Num a, Ord a) => Costs a -> [Path] -> Street a -> [Path]
crossStreet (a,b) rd street
  | null street        = rd
  | a > b             = crossStreet (a',b') (Down:rd) street'
  | a == b && a' >= b' = crossStreet (a',b') (Down:rd) street'
  | otherwise          = crossStreet (a',b') (Up:rd) street'
  where (a',b') = (a + min x (y+z), b + min y (x+z))
        (x:y:z:street') = street



-- Using folds
solvePath' = reverse . fst . foldl' crossStreet' ([], (0,0)) . chunksOf 3 . (0:)

crossStreet' :: (Num a, Ord a) => Route a -> Street a -> Route a
crossStreet' (ps, (a,b)) [] = (ps, (a,b))
crossStreet' (ps, (a,b)) [x,y,z] = (ps', (a', b'))
  where (a',b') = (a + min x (y+z), b + min y (x+z))
        ps' = p:ps
        p | a > b || ((a==b) && a' >= b') = Down
          | otherwise                     = Up

Изменить №1

Основываясь на комментариях, я изменил определение маршрута на RouteM, используя data, и теперь первоначальная жалоба решена. Однако мне все еще нужно выяснить, как реализовать <*>.

data RouteM a = RouteM {getPath :: [Path], getCost :: Costs a} deriving (Show, Eq, Read)

-- Monadic!?
toRouteM :: (Num a, Ord a) => Street a -> RouteM a
toRouteM [x,y,z] = RouteM [] (min x (y+z), min y (x+z))
toRouteM _ = RouteM [] (0, 0)

instance Functor RouteM where -- putting or not putting this `a` here doesn't work
  fmap f r = RouteM (getPath r) (f . fst $ getCost r, f . snd $ getCost r)

instance Applicative RouteM where -- putting or not putting this `a` here doesn't work
  pure x = RouteM [] (x, x)
  f <*> r = undefined

person hyiltiz    schedule 27.04.2017    source источник
comment
Здесь есть пара проблем. Прежде всего, вы не можете определить экземпляры для псевдонимов типов (вы можете с расширениями GHC, но это то же самое, что определение экземпляра для базового типа). Вы должны изменить type Route a = ... на data Route a = Route ..., чтобы создать новый тип для определения экземпляров. Кроме того, хотя в данном случае верным является instance Applicative Route ..., стоит отметить, что вы, вероятно, хотели попробовать instance Applicative (Route a), не instance Applicative Route a. Последний является синтаксисом для многопараметрического класса типов.   -  person Alexis King    schedule 28.04.2017
comment
@AlexisKing Вероятно, это следует превратить в ответ!   -  person jkeuhlen    schedule 28.04.2017


Ответы (1)


Я не уверен, что ваш тип маршрута /является/ аппликативным или почему так должно быть.

Что означает Route path (f,g) <*> Route path' (x,y)?

Вам не хватает информации, которая вам нужна здесь. (А именно, стоимость на улице вверх/вниз.)

Ваш тип Route/RouteM не составляется так, как должен аппликатив.

Также я бы определил type Block a = {getUp::a,getDown:a,getCross:a) и type Street a = [Block]. Затем определите Route a -> Block a -> Route a.

person Chris Upshaw    schedule 28.04.2017