Как упражнение, я пытаюсь воссоздать 0pc apply
Lisp в Haskell. Я не собираюсь использовать это для каких-либо практических целей, я просто думаю, что это хорошая возможность познакомиться с системами типа и типа типа Haskell в целом. (Так что я также не ищу реализации других людей.)Воспроизведение Lisp's `apply` в Haskell с использованием GADT
Моя идея следующая: я могу использовать GADT для «тегирования» списка с типом функции, к которой он может быть применен. Итак, я переопределяю Nil
и Cons
таким же образом, что мы будем кодировать длину списка в типе с использованием определения Nat
, но вместо использования чисел Пеано длина будет закодирована в типе функции тегов (т.е. длина соответствует числу аргументов функции).
Вот код, который я до сих пор:
{-# LANGUAGE GADTs #-}
-- n represents structure of the function I apply to
-- o represents output type of the function
-- a represents argument type of the function (all arguments same type)
data FList n o a where
-- with Nil the function is the output
Nil :: FList o o a
-- with Cons the corresponding function takes one more argument
Cons :: a -> FList f o a -> FList (a -> f) o a
args0 = Nil :: FList Int Int Int -- will not apply an argument
args1 = Cons 1 args0 -- :: FList (Int -> Int) Int Int
args2 = Cons 2 args1 -- :: FList (Int -> Int -> Int) Int Int
args3 = Cons 3 args2 -- :: FList (Int -> Int -> Int -> Int) Int Int
listApply :: (n -> o) -> FList (n -> o) o a -> o
-- I match on (Cons p Nil) because I always want fun to be a function (n -> o)
listApply fun (Cons p Nil) = fun p
listApply fun (Cons p l) = listApply (fun p) l
main = print $ listApply (+) args2
В последней строке, моя идея была бы, что (+)
будет типа Int -> Int -> Int
, где Int -> Int
соответствует n
в (n -> o)
и o
соответствует последний Int
(выход) [1]. Насколько я могу судить, этот тип, похоже, работает с типом моих определений argsN
.
Однако, я получаю две ошибки, из которых я буду утверждать, компонент, который, кажется, отношение к себе:
test.hs:19:43:
Could not deduce (f ~ (n0 -> f))
from the context ((n -> o) ~ (a -> f))
bound by a pattern with constructor
Cons :: forall o a f. a -> FList f o a -> FList (a -> f) o a,
in an equation for ‘listApply’
и
test.hs:21:34:
Couldn't match type ‘Int’ with ‘Int -> Int’
Expected type: FList (Int -> Int -> Int) (Int -> Int) Int
Actual type: FList (Int -> Int -> Int) Int Int
In the second argument of ‘listApply’, namely ‘args2’
Я не уверен, как интерпретировать первую ошибку , Вторая ошибка меня сбивает с толку, поскольку она не соответствует моей интерпретации, указанной ранее [1].
Любое понимание того, что происходит не так?
P.S: Я более чем готов узнать о новых расширениях, если это сделает эту работу.
Обратите внимание, что 'a -> b -> c' совпадает с' a -> (b -> c) '** not **' (a -> b) -> c'. Похоже, вы получили это назад. Вот почему, когда вы пытаетесь объединить 'n -> o' с' Int -> Int -> Int', вы получаете, что 'n' является' Int' и 'o' является' Int -> Int'. – Bakuriu
Правильно, поэтому ключ состоит в том, что '((->) r)' не ассоциативно? Наверное, я не слишком активно знал об этом и вроде бы предполагал, что это так. Но когда я думаю об этом, конечно, не так :) Тогда мне просто нужно пересмотреть, где испортил мой код (это еще не очевидно для меня). –
Вам также может понравиться [Как определить применение Lisp в Haskell?] (Http://stackoverflow.com/q/6168880/791604). –