База даныых: социальные сети

      Комментарии к записи База даныых: социальные сети отключены

В этой теме 5 ответов, 3 участника, последнее обновление  Васильев Владимир Сергеевич 3 мес., 1 неделя назад.

  • Автор
    Сообщения
  • #3215

    questioner
    Участник

    Описать объекты предметной области:

    1. Пользователь — в какой соц.сети, имя / логин.
    2. Профиль — в какой соц.сети, имя / логин, пол, возраст, рост.
    3. Пост — в какой соц.сети, кто написал (имя / логин), когда написал (время), на чьей странице (имя / логин).
    4. Личное сообщение — в какой соц.сети, кто написал (имя / логин), когда написал (время), на чьей странице (имя / логин).
    5. Друг — в какой соц.сети, кто (имя / логин), у кого в друзьях (имя / логин).

    Описать запросы:

    • Вывести статистику для указанного пользователя (ввести имя с клавиатуры): в каких соц.сетях зарегистрирован, сколько друзей, постов, личных сообщений имеет.
    • У кого из пользователей меньше друзей?
    • Определить социальную сеть, в которой переписка ведется активно.
      Определить, кто отправляет больше постов — мужчины или женщины?

    Мой код:

    domains
      socialn = string
      name = string
      sex = string
      age = integer
      height = real
      time = real
      who = string
      where = string
    predicates
      user(socialn, name)
      profile(socialn,name,sex,age,height)
      post(socialn,who,time,where)
      privatesms(socialn,who,time,where)
      friend(socialn,who,where)
      %stats(string,string)
    clauses
      user(vkontakte, oleg).
      user(facebook, kolya).
      user(facebook, sasha).
      user(vkontakte, dima).
      user(odnoklasniki, vika).
      user(vkontakte, masha).
      user(odnoklasniki, katya).
    
      profile(vkontakte, oleg, male, 20, 1.85).
      profile(facebook, kolya, male, 20, 1.80).
      profile(facebook, sasha, male, 22, 1.77).
      profile(vkontakte, dima, male, 21, 1.79).
      profile(odnoklasniki, vika, female, 19, 1.68).
      profile(vkontakte, masha, female, 20, 1.81).
      profile(odnoklasniki, katya, female, 24, 1.72).
    
      post(vkontakte, oleg, 17.32, dima).
      post(vkontakte, dima, 18.21, oleg).
      post(facebook, kolya, 00.40, sasha).
      post(facebook, sasha, 01.13, kolya).
      post(vkontakte, masha, 07.08, oleg).
      post(odnoklasniki, vika, 13.22, katya).
      post(odnoklasniki, katya, 17.44, vika).
    
      privatesms(vkontakte, oleg, 14.55, dima).
      privatesms(odnoklasniki, vika, 09.22, katya).
    
      friend(odnoklasniki, vika, katya).
      friend(vkontakte, oleg, dima).

    Правила нужно построить не используя списки (то есть [ … | … ]).

    Подскажите пожалуйста, как построить правила, которые будут считать количество друзей, постов, где ведётся активно переписка и т.д. Как это правильно сделать, через рекурсию или создавать какой-то счетчик?

    Учесть, что количество фактов будет увеличиваться

  • #3216

    Посчитать число друзей (и любые другие параметры) ты можешь только через рекурсию. Другого механизма в прологе просто нет. Счетчик в прологе реализовать нельзя, т.к. у нем нет оператора разрушающего присваивания. Посмотрите «Введение в логическое программирование«.

    Другое дело, что через рекурсию это сделать нормально нельзя. Например, вы хотите написать функцию:

    friend_count(Who, Count):-
      friend(SocialNetwork, Who, Friend), !,
      friend_count(Who, CountOtherFriend),
      Count = CountOtherFriend + 1.
    friend_count(Who, 0).
    

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

    Чтобы программа не зацикливалась, вам нужно удалять из базы обработанные факты, а на возврате из рекурсивной функции — восстанавливать базу. Это можно сделать примерно так:

    friend_count(Who, Count):-
      friend(SocialNetwork, Who, Friend), !,
      retract(friend(SocialNetwork, Who, Friend)),
      friend_count(Who, CountOtherFriend),
      assert(friend(SocialNetwork, Who, Friend)),
      Count = CountOtherFriend + 1.
    friend_count(Who, 0).
    

    Мне такое решение не нравится. Во-первых, оно излишне сложное. Во-вторых, если бы вы использовали списки, то возможно было бы реализовать решение с хвостовой рекурсией, т.е. это насколько же эффективное решение, как с использованием циклов в языках типа С++/Java. Изменяя подобным образом базу данных мы никак не сможем использовать хвостовую рекурсию, т.к. после вызова функции нужно восстановить данные в базе.

  • #3246

    Oleg1
    Участник

    В строке
    retract(friend(SocialNetwork, Who, Friend))
    пролог выдает ошибку 512 Wrong object type,
    а в строке
    friend_count(Who, 0).
    — ошибку 420 The variable is only used once

    Пишу на Turbo Prolog

    • #3247

      Когда пролог выдает ошибку, у вас устанавливается курсор на символ с ошибкой. Это было бы полезно чтобы узнать какой именно тип не нравится интерпретатору в первой ошибке.
      Вообще, в исходном сообщении, friend описан как предикат (в секции predicates), но retract можно применять только к фактам базы данных. Чтобы решить проблему в Turbo Prolog и Visual Prolog нужно описание прототипа перенести в секцию database, а в SWI Prolog — объявить предикат динамическим. Прочитать про это подробнее можно в теме «Пример работы с базами данных в Prolog«.

      По второй ошибке — замените строку с ошибкой на
      friend_count(_, 0).
      В данном случае, должна возникать не ошибка а предупреждение (Warning), которое обычно не мешает компиляции. Компилятор сообщал вам, что переменная Who используется только один раз, т.е. он предупреждает об этом, т.к. часто это происходит вследствие опечатки. В некоторых диалектах подавить предупреждение можно поставив знак подчеркивания перед именем переменной (это хорошо, т.к. имена помогают читать код), вроде бы в Turbo Prolog такая конструкция не работает — он требует указания символа подчеркивания вместо имени переменной.

      • #3338

        Oleg1
        Участник

        domains
        	socialn = string
        	name = string
        	sex = string
        	age = integer
        	height = real
        	time = real
        	who = string
        	where = string																																	
        predicates
        	user(integer,socialn, name)
        	profile(socialn,name,sex,age,height)
        	post(integer,socialn,who,time,where)
        	privatesms(integer,socialn,who,time,where)
        	fc(integer, integer,string)
        	lfc(integer,integer)
        	fcl(integer,integer,string,integer)
        	pc(integer, integer,string)
        	psc(integer, integer,string)
        	uc(integer,integer,string)
        	zapt1(string)
        	zapt2
        	friend(integer,socialn,who,where)
        clauses
        	user(1,vkontakte, oleg).
        	user(2,facebook, kolya).
        	user(3,facebook, sasha).
        	user(4,vkontakte, dima).
        	user(5,odnoklasniki, vika).
        	user(6,vkontakte, masha).
        	user(7,odnoklasniki, katya).
        	user(8,vkontakte, igor).
        	user(9,vkontakte, nikita).
        	user(10, facebook,oleg).
        	
        	profile(vkontakte, oleg, male, 20, 1.85).
        	profile(facebook, oleg, male, 20, 1.85).
        	profile(vkontakte, igor, male, 22, 1.79).
        	profile(vkontakte, nikita, male, 44, 1.81).
        	profile(facebook, kolya, male, 20, 1.80).
        	profile(facebook, sasha, male, 22, 1.77).
        	profile(vkontakte, dima, male, 21, 1.79).
        	profile(odnoklasniki, vika, female, 19, 1.68).
        	profile(vkontakte, masha, female, 20, 1.81).
        	profile(odnoklasniki, katya, female, 24, 1.72).
        	
        	post(1,vkontakte, oleg, 17.32, dima).
        	post(2,vkontakte, dima, 18.21, oleg).
        	post(3,facebook, kolya, 00.40, sasha).
        	post(4,facebook, sasha, 01.13, kolya).
        	post(5,vkontakte, masha, 07.08, oleg).
        	post(6,odnoklasniki, vika, 13.22, katya).
        	post(7,odnoklasniki, katya, 17.44, vika).
        	
        	privatesms(1,vkontakte, oleg, 14.55, dima).
        	privatesms(2,odnoklasniki, vika, 09.22, katya).
        	
        	friend(1,odnoklasniki, vika, katya).
        	friend(2,vkontakte, oleg, dima).
        	friend(3,vkontakte, oleg, igor).
        	friend(4,vkontakte, oleg, nikita).
        
        uc(0,S,_) :- write("Social count = ", S),nl.
        uc(N,S,Name) :- user(N,C,Name),S1=S+1,N1=N-1,write("Social network = ", C),nl, uc(N1,S1,Name); N1=N-1,uc(N1,S,Name).		
        fc(0,S,_) :- write("Friend count = ", S),nl.
        fc(N,S,Name) :- friend(N,_,Name,_),S1=S+1,N1=N-1,fc(N1,S1,Name); N1=N-1,fc(N1,S,Name).	
        pc(0,S,_) :- write("Post count = ", S),nl.
        pc(N,S,Name) :- post(N,_,Name,_,_), S1=S+1, N1=N-1,pc(N1,S1,Name); N1=N-1,pc(N1,S,Name).
        psc(0,S,_) :- write("Privatesms count = ", S),nl.
        psc(N,S,Name) :- privatesms(N,_,Name,_,_), S1=S+1, N1=N-1,psc(N1,S1,Name); N1=N-1,psc(N1,S,Name).
        
        lfc(0,S) :- write(S),nl.
        lfc(N,S) :- user(N,_,X), fcl(4,0,X,N); lfc(N,S).
        
        fcl(0,S,_,C) :- C1=C-1,lfc(C1,S).
        fcl(N,S,X,C) :- friend(N,_,X,_), S1=S+1, N1=N-1, fcl(N1,S1,X,C); N1=N-1, fcl(N1,S,X,C).
        
        zapt1(Name) :- uc(10,0,Name), fc(4,0,Name), pc(7,0,Name), psc(2,0,Name).
        zapt2 :- 	lfc(10,0).
        

        Немного переписал код, смог реализовать первый запрос — «Вывести статистику для указанного пользователя (ввести имя с клавиатуры): в каких соц.сетях зарегистрирован, сколько друзей, постов, личных сообщений имеет.» Во втором не могу найти у кого меньше друзей.

        В этих правилах я перебираю всех пользователей и нахожу количество друзей у каждого пользователя.

        lfc(0,S) :- write(S),nl.
        lfc(N,S) :- user(N,_,X), fcl(4,0,X,N); lfc(N,S).
        
        fcl(0,S,_,C) :- C1=C-1,lfc(C1,S).
        fcl(N,S,X,C) :- friend(N,_,X,_), S1=S+1, N1=N-1, fcl(N1,S1,X,C); N1=N-1, fcl(N1,S,X,C).

        Подскажите пожалуйста, как сравнить количество друзей каждого пользователя и найти минимальное?

        • #3339

          Подскажите пожалуйста, как сравнить количество друзей каждого пользователя и найти минимальное?

          По-разному можно сделать. Я люблю писать код так, чтобы он был понятным. Поэтому я завел бы структуру и список типа:

          friend_count_d = friend_count(user, integer)
          friend_counts = friend_count_d*

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

Для ответа в этой теме необходимо авторизоваться.